All of lore.kernel.org
 help / color / mirror / Atom feed
* [RESEND PATCH v3 00/11] drm: add support for Atmel HLCDC Display Controller
@ 2014-07-07 16:42 ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

Hello,

Sorry for the noise, but I forgot to add the LAKML in Cc.

This patch series adds support for Atmel HLCDC (HLCD Controller) available
on some Atmel SoCs (i.e. the sama5d3 family).

The first two versions of this series didn't receive any reviews from DRM
maintainers or experienced DRM developers.
Anyway, I hope I'll get some feedback on this version.

The HLCDC actually provides a Display Controller and a PWM device, hence I
decided to declare an MFD device exposing 2 subdevices: a display
controller and a PWM chip.
This also solves a circular dependency issue preventing HLCDC driver from
unloading.
The HLCDC request a drm_panel device, which request a backlight device
(a PWM backlight), which depends on a PWM which is provided by the HLCDC
driver (hlcdc -> panel -> backlight -> hlcdc (pwm part)).

The current implementation only supports sama5d3 SoCs but other SoCs should
be easily ported by defining new compatible strings and adding HLCDC
description structures for these SoCs.

The drivers supports basic CRTC functionalities, several overlays and an
hardware cursor.

At the moment, it only supports connection to LCD panels through an RGB
connector (defined as an LVDS connector in my implementation), though
connection to other kind of devices (like DRM bridges) can be added later.

It also supports several RGB format on all planes and some YUV formats on
the HEO overlay plane.

Best Regards,

Boris

Changes since v2:
- fix coding style issues (macro indentation)
- make use of GENMASK in several places
- declare regmap config as a static structure
- rework hlcdc plane update API
- rework cursor handling to make use of the new plane update API
- fix backporch config
- do not use devm_regmap_init_mmio_clk to avoid extra clk_enable
  clk disable calls when accessing registers
- explicitely include regmap and clk headers instead of relying on
  atmel-hlcdc.h inclusions
- make the atmel-hlcdc driver depends on CONFIG_OF
- separate DT bindings documentation from driver implementation
- support several pin muxing for HLCDC pins on sama5d3 SoCs

Changes since v1:
- replace the backlight driver by a PWM driver
- make use of drm_panel infrastructure
- split driver code in several subsystem: MFD, PWM and DRM
- add support for overlays
- add support for hardware cursor


Boris BREZILLON (11):
  mfd: add atmel-hlcdc driver
  mfd: add documentation for atmel-hlcdc DT bindings
  pwm: add support for atmel-hlcdc-pwm device
  pwm: add DT bindings documentation for atmel-hlcdc-pwm driver
  drm: add Atmel HLCDC Display Controller support
  drm: add DT bindings documentation for atmel-hlcdc-dc driver
  ARM: AT91/dt: split sama5d3 lcd pin definitions to match RGB mode
    configs
  ARM: AT91/dt: add alternative pin muxing for sama5d3 lcd pins
  ARM: at91/dt: define the HLCDC node available on sama5d3 SoCs
  ARM: at91/dt: add LCD panel description to sama5d3xdm.dtsi
  ARM: at91/dt: enable the LCD panel on sama5d3xek boards

 .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     |  59 ++
 .../devicetree/bindings/mfd/atmel-hlcdc.txt        |  40 ++
 .../devicetree/bindings/pwm/atmel-hlcdc-pwm.txt    |  46 ++
 arch/arm/boot/dts/sama5d31ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d33ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d34ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d36ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d3_lcd.dtsi                 | 197 +++++-
 arch/arm/boot/dts/sama5d3xdm.dtsi                  |  43 ++
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   1 +
 drivers/gpu/drm/atmel-hlcdc/Kconfig                |  11 +
 drivers/gpu/drm/atmel-hlcdc/Makefile               |   7 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     | 469 +++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c       | 474 ++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       | 210 ++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c    | 706 ++++++++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h    | 422 ++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c    | 351 ++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c    | 729 +++++++++++++++++++++
 drivers/mfd/Kconfig                                |  12 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/atmel-hlcdc.c                          | 119 ++++
 drivers/pwm/Kconfig                                |   9 +
 drivers/pwm/Makefile                               |   1 +
 drivers/pwm/pwm-atmel-hlcdc.c                      | 229 +++++++
 include/linux/mfd/atmel-hlcdc.h                    |  78 +++
 27 files changed, 4281 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
 create mode 100644 drivers/mfd/atmel-hlcdc.c
 create mode 100644 drivers/pwm/pwm-atmel-hlcdc.c
 create mode 100644 include/linux/mfd/atmel-hlcdc.h

-- 
1.8.3.2


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

* [RESEND PATCH v3 00/11] drm: add support for Atmel HLCDC Display Controller
@ 2014-07-07 16:42 ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

Sorry for the noise, but I forgot to add the LAKML in Cc.

This patch series adds support for Atmel HLCDC (HLCD Controller) available
on some Atmel SoCs (i.e. the sama5d3 family).

The first two versions of this series didn't receive any reviews from DRM
maintainers or experienced DRM developers.
Anyway, I hope I'll get some feedback on this version.

The HLCDC actually provides a Display Controller and a PWM device, hence I
decided to declare an MFD device exposing 2 subdevices: a display
controller and a PWM chip.
This also solves a circular dependency issue preventing HLCDC driver from
unloading.
The HLCDC request a drm_panel device, which request a backlight device
(a PWM backlight), which depends on a PWM which is provided by the HLCDC
driver (hlcdc -> panel -> backlight -> hlcdc (pwm part)).

The current implementation only supports sama5d3 SoCs but other SoCs should
be easily ported by defining new compatible strings and adding HLCDC
description structures for these SoCs.

The drivers supports basic CRTC functionalities, several overlays and an
hardware cursor.

At the moment, it only supports connection to LCD panels through an RGB
connector (defined as an LVDS connector in my implementation), though
connection to other kind of devices (like DRM bridges) can be added later.

It also supports several RGB format on all planes and some YUV formats on
the HEO overlay plane.

Best Regards,

Boris

Changes since v2:
- fix coding style issues (macro indentation)
- make use of GENMASK in several places
- declare regmap config as a static structure
- rework hlcdc plane update API
- rework cursor handling to make use of the new plane update API
- fix backporch config
- do not use devm_regmap_init_mmio_clk to avoid extra clk_enable
  clk disable calls when accessing registers
- explicitely include regmap and clk headers instead of relying on
  atmel-hlcdc.h inclusions
- make the atmel-hlcdc driver depends on CONFIG_OF
- separate DT bindings documentation from driver implementation
- support several pin muxing for HLCDC pins on sama5d3 SoCs

Changes since v1:
- replace the backlight driver by a PWM driver
- make use of drm_panel infrastructure
- split driver code in several subsystem: MFD, PWM and DRM
- add support for overlays
- add support for hardware cursor


Boris BREZILLON (11):
  mfd: add atmel-hlcdc driver
  mfd: add documentation for atmel-hlcdc DT bindings
  pwm: add support for atmel-hlcdc-pwm device
  pwm: add DT bindings documentation for atmel-hlcdc-pwm driver
  drm: add Atmel HLCDC Display Controller support
  drm: add DT bindings documentation for atmel-hlcdc-dc driver
  ARM: AT91/dt: split sama5d3 lcd pin definitions to match RGB mode
    configs
  ARM: AT91/dt: add alternative pin muxing for sama5d3 lcd pins
  ARM: at91/dt: define the HLCDC node available on sama5d3 SoCs
  ARM: at91/dt: add LCD panel description to sama5d3xdm.dtsi
  ARM: at91/dt: enable the LCD panel on sama5d3xek boards

 .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     |  59 ++
 .../devicetree/bindings/mfd/atmel-hlcdc.txt        |  40 ++
 .../devicetree/bindings/pwm/atmel-hlcdc-pwm.txt    |  46 ++
 arch/arm/boot/dts/sama5d31ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d33ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d34ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d36ek.dts                   |  24 +
 arch/arm/boot/dts/sama5d3_lcd.dtsi                 | 197 +++++-
 arch/arm/boot/dts/sama5d3xdm.dtsi                  |  43 ++
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   1 +
 drivers/gpu/drm/atmel-hlcdc/Kconfig                |  11 +
 drivers/gpu/drm/atmel-hlcdc/Makefile               |   7 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     | 469 +++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c       | 474 ++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       | 210 ++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c    | 706 ++++++++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h    | 422 ++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c    | 351 ++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c    | 729 +++++++++++++++++++++
 drivers/mfd/Kconfig                                |  12 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/atmel-hlcdc.c                          | 119 ++++
 drivers/pwm/Kconfig                                |   9 +
 drivers/pwm/Makefile                               |   1 +
 drivers/pwm/pwm-atmel-hlcdc.c                      | 229 +++++++
 include/linux/mfd/atmel-hlcdc.h                    |  78 +++
 27 files changed, 4281 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
 create mode 100644 drivers/mfd/atmel-hlcdc.c
 create mode 100644 drivers/pwm/pwm-atmel-hlcdc.c
 create mode 100644 include/linux/mfd/atmel-hlcdc.h

-- 
1.8.3.2

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

* [RESEND PATCH v3 01/11] mfd: add atmel-hlcdc driver
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5
family or sama5d3 family) exposes 2 subdevices:
- a display controller (controlled by a DRM driver)
- a PWM chip

The MFD device provides a regmap and several clocks (those connected
to this hardware block) to its subdevices.

This way concurrent accesses to the iomem range are handled by the regmap
framework, and each subdevice can safely access HLCDC registers.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/mfd/Kconfig             |  12 ++++
 drivers/mfd/Makefile            |   1 +
 drivers/mfd/atmel-hlcdc.c       | 119 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/atmel-hlcdc.h |  78 ++++++++++++++++++++++++++
 4 files changed, 210 insertions(+)
 create mode 100644 drivers/mfd/atmel-hlcdc.c
 create mode 100644 include/linux/mfd/atmel-hlcdc.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ee8204c..75e674f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -59,6 +59,18 @@ config MFD_AAT2870_CORE
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config MFD_ATMEL_HLCDC
+	tristate "Atmel HLCDC (HLCD Controller)"
+	select MFD_CORE
+	select REGMAP_MMIO
+	depends on OF
+	help
+	  Choose this option if you have an ATMEL SoC with an HLCDC (HLCD
+	  Controller) IP (i.e. at91sam9n12, at91sam9x5 family or sama5d3
+	  family).
+	  This MFD device exposes two subdevices: a PWM chip and a Display
+	  Controller.
+
 config MFD_BCM590XX
 	tristate "Broadcom BCM590xx PMUs"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8afedba..5f25b0d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -156,6 +156,7 @@ obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o ssbi.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
+obj-$(CONFIG_MFD_ATMEL_HLCDC)	+= atmel-hlcdc.o
 obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
 obj-$(CONFIG_MFD_PALMAS)	+= palmas.o
 obj-$(CONFIG_MFD_VIPERBOARD)    += viperboard.o
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
new file mode 100644
index 0000000..381dd06
--- /dev/null
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/atmel-hlcdc.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_REG_MAX		(0x4000 - 0x4)
+
+static const struct mfd_cell atmel_hlcdc_cells[] = {
+	{
+		.name = "atmel-hlcdc-pwm",
+		.of_compatible = "atmel,hlcdc-pwm",
+	},
+	{
+		.name = "atmel-hlcdc-dc",
+		.of_compatible = "atmel,hlcdc-dc",
+	},
+};
+
+static const struct regmap_config atmel_hlcdc_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = ATMEL_HLCDC_REG_MAX,
+};
+
+static int atmel_hlcdc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_hlcdc *hlcdc;
+	struct resource *res;
+	void __iomem *regs;
+
+	hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
+	if (!hlcdc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
+	if (IS_ERR(hlcdc->periph_clk)) {
+		dev_err(dev, "failed to get peripheral clock\n");
+		return PTR_ERR(hlcdc->periph_clk);
+	}
+
+	hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
+	if (IS_ERR(hlcdc->sys_clk)) {
+		dev_err(dev, "failed to get system clock\n");
+		return PTR_ERR(hlcdc->sys_clk);
+	}
+
+	hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
+	if (IS_ERR(hlcdc->slow_clk)) {
+		dev_err(dev, "failed to get slow clock\n");
+		return PTR_ERR(hlcdc->slow_clk);
+	}
+
+	hlcdc->regmap = devm_regmap_init_mmio(dev, regs,
+					      &atmel_hlcdc_regmap_config);
+	if (IS_ERR(hlcdc->regmap))
+		return PTR_ERR(hlcdc->regmap);
+
+	dev_set_drvdata(dev, hlcdc);
+
+	return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
+			       ARRAY_SIZE(atmel_hlcdc_cells),
+			       NULL, 0, NULL);
+}
+
+static int atmel_hlcdc_remove(struct platform_device *pdev)
+{
+	mfd_remove_devices(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_match[] = {
+	{ .compatible = "atmel,sama5d3-hlcdc" },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver atmel_hlcdc_driver = {
+	.probe = atmel_hlcdc_probe,
+	.remove = atmel_hlcdc_remove,
+	.driver = {
+		.name = "atmel-hlcdc",
+		.owner = THIS_MODULE,
+		.of_match_table = atmel_hlcdc_match,
+	},
+};
+module_platform_driver(atmel_hlcdc_driver);
+
+MODULE_ALIAS("platform:atmel-hlcdc");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/atmel-hlcdc.h b/include/linux/mfd/atmel-hlcdc.h
new file mode 100644
index 0000000..e9a503d
--- /dev/null
+++ b/include/linux/mfd/atmel-hlcdc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_MFD_HLCDC_H
+#define __LINUX_MFD_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_CFG(i)		((i) * 0x4)
+#define ATMEL_HLCDC_SIG_CFG		LCDCFG(5)
+#define ATMEL_HLCDC_HSPOL		BIT(0)
+#define ATMEL_HLCDC_VSPOL		BIT(1)
+#define ATMEL_HLCDC_VSPDLYS		BIT(2)
+#define ATMEL_HLCDC_VSPDLYE		BIT(3)
+#define ATMEL_HLCDC_DISPPOL		BIT(4)
+#define ATMEL_HLCDC_DITHER		BIT(6)
+#define ATMEL_HLCDC_DISPDLY		BIT(7)
+#define ATMEL_HLCDC_MODE_MASK		GENMASK(9, 8)
+#define ATMEL_HLCDC_PP			BIT(10)
+#define ATMEL_HLCDC_VSPSU		BIT(12)
+#define ATMEL_HLCDC_VSPHO		BIT(13)
+#define ATMEL_HLCDC_GUARDTIME_MASK	GENMASK(20, 16)
+
+#define ATMEL_HLCDC_EN			0x20
+#define ATMEL_HLCDC_DIS			0x24
+#define ATMEL_HLCDC_SR			0x28
+#define ATMEL_HLCDC_IER			0x2c
+#define ATMEL_HLCDC_IDR			0x30
+#define ATMEL_HLCDC_IMR			0x34
+#define ATMEL_HLCDC_ISR			0x38
+
+#define ATMEL_HLCDC_CLKPOL		BIT(0)
+#define ATMEL_HLCDC_CLKSEL		BIT(2)
+#define ATMEL_HLCDC_CLKPWMSEL		BIT(3)
+#define ATMEL_HLCDC_CGDIS(i)		BIT(8 + (i))
+#define ATMEL_HLCDC_CLKDIV_SHFT		16
+#define ATMEL_HLCDC_CLKDIV_MASK		GENMASK(23, 16)
+#define ATMEL_HLCDC_CLKDIV(div)		((div - 2) << ATMEL_HLCDC_CLKDIV_SHFT)
+
+#define ATMEL_HLCDC_PIXEL_CLK		BIT(0)
+#define ATMEL_HLCDC_SYNC		BIT(1)
+#define ATMEL_HLCDC_DISP		BIT(2)
+#define ATMEL_HLCDC_PWM			BIT(3)
+#define ATMEL_HLCDC_SIP			BIT(4)
+
+/**
+ * Structure shared by the MFD device and its subdevices.
+ *
+ * @regmap: register map used to access HLCDC IP registers
+ * @periph_clk: the hlcdc peripheral clock
+ * @sys_clk: the hlcdc system clock
+ * @slow_clk: the system slow clk
+ */
+struct atmel_hlcdc {
+	struct regmap *regmap;
+	struct clk *periph_clk;
+	struct clk *sys_clk;
+	struct clk *slow_clk;
+};
+
+#endif /* __LINUX_MFD_HLCDC_H */
-- 
1.8.3.2


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

* [RESEND PATCH v3 01/11] mfd: add atmel-hlcdc driver
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5
family or sama5d3 family) exposes 2 subdevices:
- a display controller (controlled by a DRM driver)
- a PWM chip

The MFD device provides a regmap and several clocks (those connected
to this hardware block) to its subdevices.

This way concurrent accesses to the iomem range are handled by the regmap
framework, and each subdevice can safely access HLCDC registers.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/mfd/Kconfig             |  12 ++++
 drivers/mfd/Makefile            |   1 +
 drivers/mfd/atmel-hlcdc.c       | 119 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/atmel-hlcdc.h |  78 ++++++++++++++++++++++++++
 4 files changed, 210 insertions(+)
 create mode 100644 drivers/mfd/atmel-hlcdc.c
 create mode 100644 include/linux/mfd/atmel-hlcdc.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ee8204c..75e674f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -59,6 +59,18 @@ config MFD_AAT2870_CORE
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config MFD_ATMEL_HLCDC
+	tristate "Atmel HLCDC (HLCD Controller)"
+	select MFD_CORE
+	select REGMAP_MMIO
+	depends on OF
+	help
+	  Choose this option if you have an ATMEL SoC with an HLCDC (HLCD
+	  Controller) IP (i.e. at91sam9n12, at91sam9x5 family or sama5d3
+	  family).
+	  This MFD device exposes two subdevices: a PWM chip and a Display
+	  Controller.
+
 config MFD_BCM590XX
 	tristate "Broadcom BCM590xx PMUs"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8afedba..5f25b0d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -156,6 +156,7 @@ obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o ssbi.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
+obj-$(CONFIG_MFD_ATMEL_HLCDC)	+= atmel-hlcdc.o
 obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
 obj-$(CONFIG_MFD_PALMAS)	+= palmas.o
 obj-$(CONFIG_MFD_VIPERBOARD)    += viperboard.o
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
new file mode 100644
index 0000000..381dd06
--- /dev/null
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/atmel-hlcdc.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_REG_MAX		(0x4000 - 0x4)
+
+static const struct mfd_cell atmel_hlcdc_cells[] = {
+	{
+		.name = "atmel-hlcdc-pwm",
+		.of_compatible = "atmel,hlcdc-pwm",
+	},
+	{
+		.name = "atmel-hlcdc-dc",
+		.of_compatible = "atmel,hlcdc-dc",
+	},
+};
+
+static const struct regmap_config atmel_hlcdc_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = ATMEL_HLCDC_REG_MAX,
+};
+
+static int atmel_hlcdc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_hlcdc *hlcdc;
+	struct resource *res;
+	void __iomem *regs;
+
+	hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
+	if (!hlcdc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
+	if (IS_ERR(hlcdc->periph_clk)) {
+		dev_err(dev, "failed to get peripheral clock\n");
+		return PTR_ERR(hlcdc->periph_clk);
+	}
+
+	hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
+	if (IS_ERR(hlcdc->sys_clk)) {
+		dev_err(dev, "failed to get system clock\n");
+		return PTR_ERR(hlcdc->sys_clk);
+	}
+
+	hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
+	if (IS_ERR(hlcdc->slow_clk)) {
+		dev_err(dev, "failed to get slow clock\n");
+		return PTR_ERR(hlcdc->slow_clk);
+	}
+
+	hlcdc->regmap = devm_regmap_init_mmio(dev, regs,
+					      &atmel_hlcdc_regmap_config);
+	if (IS_ERR(hlcdc->regmap))
+		return PTR_ERR(hlcdc->regmap);
+
+	dev_set_drvdata(dev, hlcdc);
+
+	return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
+			       ARRAY_SIZE(atmel_hlcdc_cells),
+			       NULL, 0, NULL);
+}
+
+static int atmel_hlcdc_remove(struct platform_device *pdev)
+{
+	mfd_remove_devices(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_match[] = {
+	{ .compatible = "atmel,sama5d3-hlcdc" },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver atmel_hlcdc_driver = {
+	.probe = atmel_hlcdc_probe,
+	.remove = atmel_hlcdc_remove,
+	.driver = {
+		.name = "atmel-hlcdc",
+		.owner = THIS_MODULE,
+		.of_match_table = atmel_hlcdc_match,
+	},
+};
+module_platform_driver(atmel_hlcdc_driver);
+
+MODULE_ALIAS("platform:atmel-hlcdc");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/atmel-hlcdc.h b/include/linux/mfd/atmel-hlcdc.h
new file mode 100644
index 0000000..e9a503d
--- /dev/null
+++ b/include/linux/mfd/atmel-hlcdc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_MFD_HLCDC_H
+#define __LINUX_MFD_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_CFG(i)		((i) * 0x4)
+#define ATMEL_HLCDC_SIG_CFG		LCDCFG(5)
+#define ATMEL_HLCDC_HSPOL		BIT(0)
+#define ATMEL_HLCDC_VSPOL		BIT(1)
+#define ATMEL_HLCDC_VSPDLYS		BIT(2)
+#define ATMEL_HLCDC_VSPDLYE		BIT(3)
+#define ATMEL_HLCDC_DISPPOL		BIT(4)
+#define ATMEL_HLCDC_DITHER		BIT(6)
+#define ATMEL_HLCDC_DISPDLY		BIT(7)
+#define ATMEL_HLCDC_MODE_MASK		GENMASK(9, 8)
+#define ATMEL_HLCDC_PP			BIT(10)
+#define ATMEL_HLCDC_VSPSU		BIT(12)
+#define ATMEL_HLCDC_VSPHO		BIT(13)
+#define ATMEL_HLCDC_GUARDTIME_MASK	GENMASK(20, 16)
+
+#define ATMEL_HLCDC_EN			0x20
+#define ATMEL_HLCDC_DIS			0x24
+#define ATMEL_HLCDC_SR			0x28
+#define ATMEL_HLCDC_IER			0x2c
+#define ATMEL_HLCDC_IDR			0x30
+#define ATMEL_HLCDC_IMR			0x34
+#define ATMEL_HLCDC_ISR			0x38
+
+#define ATMEL_HLCDC_CLKPOL		BIT(0)
+#define ATMEL_HLCDC_CLKSEL		BIT(2)
+#define ATMEL_HLCDC_CLKPWMSEL		BIT(3)
+#define ATMEL_HLCDC_CGDIS(i)		BIT(8 + (i))
+#define ATMEL_HLCDC_CLKDIV_SHFT		16
+#define ATMEL_HLCDC_CLKDIV_MASK		GENMASK(23, 16)
+#define ATMEL_HLCDC_CLKDIV(div)		((div - 2) << ATMEL_HLCDC_CLKDIV_SHFT)
+
+#define ATMEL_HLCDC_PIXEL_CLK		BIT(0)
+#define ATMEL_HLCDC_SYNC		BIT(1)
+#define ATMEL_HLCDC_DISP		BIT(2)
+#define ATMEL_HLCDC_PWM			BIT(3)
+#define ATMEL_HLCDC_SIP			BIT(4)
+
+/**
+ * Structure shared by the MFD device and its subdevices.
+ *
+ * @regmap: register map used to access HLCDC IP registers
+ * @periph_clk: the hlcdc peripheral clock
+ * @sys_clk: the hlcdc system clock
+ * @slow_clk: the system slow clk
+ */
+struct atmel_hlcdc {
+	struct regmap *regmap;
+	struct clk *periph_clk;
+	struct clk *sys_clk;
+	struct clk *slow_clk;
+};
+
+#endif /* __LINUX_MFD_HLCDC_H */
-- 
1.8.3.2

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

* [RESEND PATCH v3 02/11] mfd: add documentation for atmel-hlcdc DT bindings
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5
family or sama5d3 family) exposes 2 subdevices:
- a display controller (controlled by a DRM driver)
- a PWM chip

This patch adds documentation for atmel-hlcdc DT bindings.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/mfd/atmel-hlcdc.txt        | 40 ++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt

diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
new file mode 100644
index 0000000..294048a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
@@ -0,0 +1,40 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,sama5d3-hlcdc"
+ - reg: base address and size of the HLCDC device registers.
+ - clock-names: the name of the 3 clocks requested by the HLCDC device.
+   Should contain "periph_clk", "sys_clk" and "slow_clk".
+ - clocks: should contain the 3 clocks requested by the HLCDC device.
+
+The HLCDC IP exposes two subdevices:
+ - a PWM chip: see Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
+ - a Display Controller: see Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
+
+Example:
+
+	hlcdc: hlcdc@f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2


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

* [RESEND PATCH v3 02/11] mfd: add documentation for atmel-hlcdc DT bindings
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5
family or sama5d3 family) exposes 2 subdevices:
- a display controller (controlled by a DRM driver)
- a PWM chip

This patch adds documentation for atmel-hlcdc DT bindings.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/mfd/atmel-hlcdc.txt        | 40 ++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt

diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
new file mode 100644
index 0000000..294048a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
@@ -0,0 +1,40 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,sama5d3-hlcdc"
+ - reg: base address and size of the HLCDC device registers.
+ - clock-names: the name of the 3 clocks requested by the HLCDC device.
+   Should contain "periph_clk", "sys_clk" and "slow_clk".
+ - clocks: should contain the 3 clocks requested by the HLCDC device.
+
+The HLCDC IP exposes two subdevices:
+ - a PWM chip: see Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
+ - a Display Controller: see Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
+
+Example:
+
+	hlcdc: hlcdc at f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2

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

* [RESEND PATCH v3 03/11] pwm: add support for atmel-hlcdc-pwm device
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The HLCDC IP available in some Atmel SoCs (i.e. sam9x5i.e. at91sam9n12,
at91sam9x5 family or sama5d3 family) provide a PWM device.

This driver add support for a PWM chip exposing a single PWM device (which
will most likely be used to drive a backlight device).

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/pwm/Kconfig           |   9 ++
 drivers/pwm/Makefile          |   1 +
 drivers/pwm/pwm-atmel-hlcdc.c | 229 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 239 insertions(+)
 create mode 100644 drivers/pwm/pwm-atmel-hlcdc.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 5b34ff2..7186242 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -50,6 +50,15 @@ config PWM_ATMEL
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-atmel.
 
+config PWM_ATMEL_HLCDC_PWM
+	tristate "Atmel HLCDC PWM support"
+	depends on MFD_ATMEL_HLCDC
+	help
+	  Generic PWM framework driver for Atmel HLCDC PWM.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-atmel.
+
 config PWM_ATMEL_TCB
 	tristate "Atmel TC Block PWM support"
 	depends on ATMEL_TCLIB && OF
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index e57d2c3..a245519 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_PWM)		+= core.o
 obj-$(CONFIG_PWM_SYSFS)		+= sysfs.o
 obj-$(CONFIG_PWM_AB8500)	+= pwm-ab8500.o
 obj-$(CONFIG_PWM_ATMEL)		+= pwm-atmel.o
+obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM)	+= pwm-atmel-hlcdc.o
 obj-$(CONFIG_PWM_ATMEL_TCB)	+= pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
 obj-$(CONFIG_PWM_CLPS711X)	+= pwm-clps711x.o
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
new file mode 100644
index 0000000..7f25197
--- /dev/null
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/atmel-hlcdc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_PWMCVAL_MASK	GENMASK(15, 8)
+#define ATMEL_HLCDC_PWMCVAL(x)		((x << 8) & ATMEL_HLCDC_PWMCVAL_MASK)
+#define ATMEL_HLCDC_PWMPOL		BIT(4)
+#define ATMEL_HLCDC_PWMPS_MASK		GENMASK(2, 0)
+#define ATMEL_HLCDC_PWMPS_MAX		0x6
+#define ATMEL_HLCDC_PWMPS(x)		((x) & ATMEL_HLCDC_PWMPS_MASK)
+
+struct atmel_hlcdc_pwm_chip {
+	struct pwm_chip chip;
+	struct atmel_hlcdc *hlcdc;
+	struct clk *cur_clk;
+};
+
+static inline struct atmel_hlcdc_pwm_chip *
+pwm_chip_to_atmel_hlcdc_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct atmel_hlcdc_pwm_chip, chip);
+}
+
+static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
+				  struct pwm_device *pwm,
+				  int duty_ns, int period_ns)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	struct clk *new_clk = hlcdc->slow_clk;
+	u64 pwmcval = duty_ns * 256;
+	unsigned long clk_freq;
+	u64 clk_period_ns;
+	u32 pwmcfg;
+	int pres;
+
+	clk_freq = clk_get_rate(new_clk);
+	clk_period_ns = 1000000000;
+	clk_period_ns *= 256;
+	do_div(clk_period_ns, clk_freq);
+
+	if (clk_period_ns > period_ns) {
+		new_clk = hlcdc->sys_clk;
+		clk_freq = clk_get_rate(new_clk);
+		clk_period_ns = 1000000000;
+		clk_period_ns *= 256;
+		do_div(clk_period_ns, clk_freq);
+	}
+
+	for (pres = ATMEL_HLCDC_PWMPS_MAX; pres >= 0; pres--) {
+		if ((clk_period_ns << pres) <= period_ns)
+			break;
+	}
+
+	if (pres > ATMEL_HLCDC_PWMPS_MAX)
+		return -EINVAL;
+
+	pwmcfg = ATMEL_HLCDC_PWMPS(pres);
+
+	if (new_clk != chip->cur_clk) {
+		u32 gencfg = 0;
+
+		clk_prepare_enable(new_clk);
+		clk_disable_unprepare(chip->cur_clk);
+		chip->cur_clk = new_clk;
+
+		if (new_clk != hlcdc->slow_clk)
+			gencfg = ATMEL_HLCDC_CLKPWMSEL;
+		regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(0),
+				   ATMEL_HLCDC_CLKPWMSEL, gencfg);
+	}
+
+	do_div(pwmcval, period_ns);
+	if (pwmcval > 255)
+		pwmcval = 255;
+
+	pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval);
+
+	regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
+			   ATMEL_HLCDC_PWMCVAL_MASK | ATMEL_HLCDC_PWMPS_MASK,
+			   pwmcfg);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_set_polarity(struct pwm_chip *c,
+					struct pwm_device *pwm,
+					enum pwm_polarity polarity)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 cfg = 0;
+
+	if (polarity == PWM_POLARITY_NORMAL)
+		cfg = ATMEL_HLCDC_PWMPOL;
+
+	regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
+			   ATMEL_HLCDC_PWMPOL, cfg);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_enable(struct pwm_chip *c,
+				  struct pwm_device *pwm)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 status;
+
+	regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PWM);
+	while (!regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status) &&
+	       !(status & ATMEL_HLCDC_PWM))
+		;
+
+	return 0;
+}
+
+static void atmel_hlcdc_pwm_disable(struct pwm_chip *c,
+				    struct pwm_device *pwm)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 status;
+
+	regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PWM);
+	while (!regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status) &&
+	       (status & ATMEL_HLCDC_PWM))
+		;
+}
+
+static const struct pwm_ops atmel_hlcdc_pwm_ops = {
+	.config = atmel_hlcdc_pwm_config,
+	.set_polarity = atmel_hlcdc_pwm_set_polarity,
+	.enable = atmel_hlcdc_pwm_enable,
+	.disable = atmel_hlcdc_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
+{
+	struct atmel_hlcdc_pwm_chip *chip;
+	struct device *dev = &pdev->dev;
+	struct atmel_hlcdc *hlcdc;
+	int ret;
+
+	hlcdc = dev_get_drvdata(dev->parent);
+	if (!hlcdc)
+		return -EINVAL;
+
+	ret = clk_prepare_enable(hlcdc->periph_clk);
+	if (ret)
+		return ret;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->hlcdc = hlcdc;
+	chip->chip.ops = &atmel_hlcdc_pwm_ops;
+	chip->chip.dev = dev;
+	chip->chip.base = -1;
+	chip->chip.npwm = 1;
+	chip->chip.of_xlate = of_pwm_xlate_with_flags;
+	chip->chip.of_pwm_n_cells = 3;
+	chip->chip.can_sleep = 1;
+
+	ret = pwmchip_add(&chip->chip);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, chip);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_remove(struct platform_device *pdev)
+{
+	struct atmel_hlcdc_pwm_chip *chip = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(chip->hlcdc->periph_clk);
+
+	return pwmchip_remove(&chip->chip);
+}
+
+static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = {
+	{ .compatible = "atmel,hlcdc-pwm" },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver atmel_hlcdc_pwm_driver = {
+	.driver = {
+		.name = "atmel-hlcdc-pwm",
+		.of_match_table = atmel_hlcdc_pwm_dt_ids,
+	},
+	.probe = atmel_hlcdc_pwm_probe,
+	.remove = atmel_hlcdc_pwm_remove,
+};
+module_platform_driver(atmel_hlcdc_pwm_driver);
+
+MODULE_ALIAS("platform:atmel-hlcdc-pwm");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC PWM driver");
+MODULE_LICENSE("GPL");
-- 
1.8.3.2


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

* [RESEND PATCH v3 03/11] pwm: add support for atmel-hlcdc-pwm device
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The HLCDC IP available in some Atmel SoCs (i.e. sam9x5i.e. at91sam9n12,
at91sam9x5 family or sama5d3 family) provide a PWM device.

This driver add support for a PWM chip exposing a single PWM device (which
will most likely be used to drive a backlight device).

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/pwm/Kconfig           |   9 ++
 drivers/pwm/Makefile          |   1 +
 drivers/pwm/pwm-atmel-hlcdc.c | 229 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 239 insertions(+)
 create mode 100644 drivers/pwm/pwm-atmel-hlcdc.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 5b34ff2..7186242 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -50,6 +50,15 @@ config PWM_ATMEL
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-atmel.
 
+config PWM_ATMEL_HLCDC_PWM
+	tristate "Atmel HLCDC PWM support"
+	depends on MFD_ATMEL_HLCDC
+	help
+	  Generic PWM framework driver for Atmel HLCDC PWM.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-atmel.
+
 config PWM_ATMEL_TCB
 	tristate "Atmel TC Block PWM support"
 	depends on ATMEL_TCLIB && OF
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index e57d2c3..a245519 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_PWM)		+= core.o
 obj-$(CONFIG_PWM_SYSFS)		+= sysfs.o
 obj-$(CONFIG_PWM_AB8500)	+= pwm-ab8500.o
 obj-$(CONFIG_PWM_ATMEL)		+= pwm-atmel.o
+obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM)	+= pwm-atmel-hlcdc.o
 obj-$(CONFIG_PWM_ATMEL_TCB)	+= pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
 obj-$(CONFIG_PWM_CLPS711X)	+= pwm-clps711x.o
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
new file mode 100644
index 0000000..7f25197
--- /dev/null
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/atmel-hlcdc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_PWMCVAL_MASK	GENMASK(15, 8)
+#define ATMEL_HLCDC_PWMCVAL(x)		((x << 8) & ATMEL_HLCDC_PWMCVAL_MASK)
+#define ATMEL_HLCDC_PWMPOL		BIT(4)
+#define ATMEL_HLCDC_PWMPS_MASK		GENMASK(2, 0)
+#define ATMEL_HLCDC_PWMPS_MAX		0x6
+#define ATMEL_HLCDC_PWMPS(x)		((x) & ATMEL_HLCDC_PWMPS_MASK)
+
+struct atmel_hlcdc_pwm_chip {
+	struct pwm_chip chip;
+	struct atmel_hlcdc *hlcdc;
+	struct clk *cur_clk;
+};
+
+static inline struct atmel_hlcdc_pwm_chip *
+pwm_chip_to_atmel_hlcdc_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct atmel_hlcdc_pwm_chip, chip);
+}
+
+static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
+				  struct pwm_device *pwm,
+				  int duty_ns, int period_ns)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	struct clk *new_clk = hlcdc->slow_clk;
+	u64 pwmcval = duty_ns * 256;
+	unsigned long clk_freq;
+	u64 clk_period_ns;
+	u32 pwmcfg;
+	int pres;
+
+	clk_freq = clk_get_rate(new_clk);
+	clk_period_ns = 1000000000;
+	clk_period_ns *= 256;
+	do_div(clk_period_ns, clk_freq);
+
+	if (clk_period_ns > period_ns) {
+		new_clk = hlcdc->sys_clk;
+		clk_freq = clk_get_rate(new_clk);
+		clk_period_ns = 1000000000;
+		clk_period_ns *= 256;
+		do_div(clk_period_ns, clk_freq);
+	}
+
+	for (pres = ATMEL_HLCDC_PWMPS_MAX; pres >= 0; pres--) {
+		if ((clk_period_ns << pres) <= period_ns)
+			break;
+	}
+
+	if (pres > ATMEL_HLCDC_PWMPS_MAX)
+		return -EINVAL;
+
+	pwmcfg = ATMEL_HLCDC_PWMPS(pres);
+
+	if (new_clk != chip->cur_clk) {
+		u32 gencfg = 0;
+
+		clk_prepare_enable(new_clk);
+		clk_disable_unprepare(chip->cur_clk);
+		chip->cur_clk = new_clk;
+
+		if (new_clk != hlcdc->slow_clk)
+			gencfg = ATMEL_HLCDC_CLKPWMSEL;
+		regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(0),
+				   ATMEL_HLCDC_CLKPWMSEL, gencfg);
+	}
+
+	do_div(pwmcval, period_ns);
+	if (pwmcval > 255)
+		pwmcval = 255;
+
+	pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval);
+
+	regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
+			   ATMEL_HLCDC_PWMCVAL_MASK | ATMEL_HLCDC_PWMPS_MASK,
+			   pwmcfg);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_set_polarity(struct pwm_chip *c,
+					struct pwm_device *pwm,
+					enum pwm_polarity polarity)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 cfg = 0;
+
+	if (polarity == PWM_POLARITY_NORMAL)
+		cfg = ATMEL_HLCDC_PWMPOL;
+
+	regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
+			   ATMEL_HLCDC_PWMPOL, cfg);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_enable(struct pwm_chip *c,
+				  struct pwm_device *pwm)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 status;
+
+	regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PWM);
+	while (!regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status) &&
+	       !(status & ATMEL_HLCDC_PWM))
+		;
+
+	return 0;
+}
+
+static void atmel_hlcdc_pwm_disable(struct pwm_chip *c,
+				    struct pwm_device *pwm)
+{
+	struct atmel_hlcdc_pwm_chip *chip =
+				pwm_chip_to_atmel_hlcdc_pwm_chip(c);
+	struct atmel_hlcdc *hlcdc = chip->hlcdc;
+	u32 status;
+
+	regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PWM);
+	while (!regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status) &&
+	       (status & ATMEL_HLCDC_PWM))
+		;
+}
+
+static const struct pwm_ops atmel_hlcdc_pwm_ops = {
+	.config = atmel_hlcdc_pwm_config,
+	.set_polarity = atmel_hlcdc_pwm_set_polarity,
+	.enable = atmel_hlcdc_pwm_enable,
+	.disable = atmel_hlcdc_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
+{
+	struct atmel_hlcdc_pwm_chip *chip;
+	struct device *dev = &pdev->dev;
+	struct atmel_hlcdc *hlcdc;
+	int ret;
+
+	hlcdc = dev_get_drvdata(dev->parent);
+	if (!hlcdc)
+		return -EINVAL;
+
+	ret = clk_prepare_enable(hlcdc->periph_clk);
+	if (ret)
+		return ret;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->hlcdc = hlcdc;
+	chip->chip.ops = &atmel_hlcdc_pwm_ops;
+	chip->chip.dev = dev;
+	chip->chip.base = -1;
+	chip->chip.npwm = 1;
+	chip->chip.of_xlate = of_pwm_xlate_with_flags;
+	chip->chip.of_pwm_n_cells = 3;
+	chip->chip.can_sleep = 1;
+
+	ret = pwmchip_add(&chip->chip);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, chip);
+
+	return 0;
+}
+
+static int atmel_hlcdc_pwm_remove(struct platform_device *pdev)
+{
+	struct atmel_hlcdc_pwm_chip *chip = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(chip->hlcdc->periph_clk);
+
+	return pwmchip_remove(&chip->chip);
+}
+
+static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = {
+	{ .compatible = "atmel,hlcdc-pwm" },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver atmel_hlcdc_pwm_driver = {
+	.driver = {
+		.name = "atmel-hlcdc-pwm",
+		.of_match_table = atmel_hlcdc_pwm_dt_ids,
+	},
+	.probe = atmel_hlcdc_pwm_probe,
+	.remove = atmel_hlcdc_pwm_remove,
+};
+module_platform_driver(atmel_hlcdc_pwm_driver);
+
+MODULE_ALIAS("platform:atmel-hlcdc-pwm");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC PWM driver");
+MODULE_LICENSE("GPL");
-- 
1.8.3.2

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

* [RESEND PATCH v3 04/11] pwm: add DT bindings documentation for atmel-hlcdc-pwm driver
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The HLCDC IP available in some Atmel SoCs (i.e. sam9x5i.e. at91sam9n12,
at91sam9x5 family or sama5d3 family) provide a PWM device.

The DT bindings used for this PWM device is following the default 3 cells
bindings described in Documentation/devicetree/bindings/pwm/pwm.txt.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/pwm/atmel-hlcdc-pwm.txt    | 46 ++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt

diff --git a/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
new file mode 100644
index 0000000..d5fff47
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
@@ -0,0 +1,46 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) PWM driver
+
+The Atmel HLCDC PWM is subdevice of the HLCDC MFD device.
+See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,hlcdc-pwm"
+ - pinctr-names: the pin control state names. Should contain "default".
+ - pinctrl-0: should contain the pinctrl states described by pinctrl
+   default.
+ - #pwm-cells: should be set to 3. This PWM chip use the default 3 cells
+   bindings defined in Documentation/devicetree/bindings/pwm/pwm.txt.
+   The first cell encodes the PWM id (0 is the only acceptable value here,
+   because the chip only provide one PWM).
+   The second cell encodes the PWM period in nanoseconds.
+   The third cell encodes the PWM flags (the only supported flag is
+   PWM_POLARITY_INVERTED)
+
+Example:
+
+	hlcdc: hlcdc@f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+		status = "disabled";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2


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

* [RESEND PATCH v3 04/11] pwm: add DT bindings documentation for atmel-hlcdc-pwm driver
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The HLCDC IP available in some Atmel SoCs (i.e. sam9x5i.e. at91sam9n12,
at91sam9x5 family or sama5d3 family) provide a PWM device.

The DT bindings used for this PWM device is following the default 3 cells
bindings described in Documentation/devicetree/bindings/pwm/pwm.txt.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/pwm/atmel-hlcdc-pwm.txt    | 46 ++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt

diff --git a/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
new file mode 100644
index 0000000..d5fff47
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/atmel-hlcdc-pwm.txt
@@ -0,0 +1,46 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) PWM driver
+
+The Atmel HLCDC PWM is subdevice of the HLCDC MFD device.
+See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,hlcdc-pwm"
+ - pinctr-names: the pin control state names. Should contain "default".
+ - pinctrl-0: should contain the pinctrl states described by pinctrl
+   default.
+ - #pwm-cells: should be set to 3. This PWM chip use the default 3 cells
+   bindings defined in Documentation/devicetree/bindings/pwm/pwm.txt.
+   The first cell encodes the PWM id (0 is the only acceptable value here,
+   because the chip only provide one PWM).
+   The second cell encodes the PWM period in nanoseconds.
+   The third cell encodes the PWM flags (the only supported flag is
+   PWM_POLARITY_INVERTED)
+
+Example:
+
+	hlcdc: hlcdc at f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+		status = "disabled";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
controller device.

This display controller supports at least one primary plane and might
provide several overlays and an hardware cursor depending on the IP
version.

At the moment, this driver only implements an RGB connector to interface
with LCD panels, but support for other kind of external devices (like DRM
bridges) might be added later.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/Kconfig                         |   2 +
 drivers/gpu/drm/Makefile                        |   1 +
 drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
 drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
 11 files changed, 3382 insertions(+)
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index d1cc2f6..df6f0c1 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
 
 source "drivers/gpu/drm/armada/Kconfig"
 
+source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
+
 source "drivers/gpu/drm/rcar-du/Kconfig"
 
 source "drivers/gpu/drm/shmobile/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 48e38ba..28c8a61 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 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_OMAP)	+= omapdrm/
diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig
new file mode 100644
index 0000000..bc07315
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig
@@ -0,0 +1,11 @@
+config DRM_ATMEL_HLCDC
+	tristate "DRM Support for ATMEL HLCDC Display Controller"
+	depends on DRM && OF && MFD_ATMEL_HLCDC && COMMON_CLK
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this option if you have an ATMEL SoC with an HLCDC display
+	  controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile
new file mode 100644
index 0000000..bf9fe0b
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
@@ -0,0 +1,7 @@
+atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
+		atmel_hlcdc_dc.o \
+		atmel_hlcdc_layer.o \
+		atmel_hlcdc_panel.o \
+		atmel_hlcdc_plane.o
+
+obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc-dc.o
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
new file mode 100644
index 0000000..8b11af8
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Structure storing HW cursor status.
+ *
+ * @status: the current cursor status
+ * @req: the requested cursor changes
+ * @plane: the hardware cursor plane
+ * @lock: cursor lock held when modifying cursor req or status
+ */
+struct atmel_hlcdc_crtc_cursor {
+	struct atmel_hlcdc_plane *plane;
+	struct drm_gem_cma_object *gem;
+	u32 height;
+	u32 width;
+	int x;
+	int y;
+	struct mutex lock;
+};
+
+/**
+ * Atmel HLCDC CRTC structure
+ *
+ * @base: base DRM CRTC structure
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @event: pointer to the current page flip event
+ * @id: CRTC id (returned by drm_crtc_index)
+ * @dpms: DPMS mode
+ * @cursor: hardware cursor status
+ */
+struct atmel_hlcdc_crtc {
+	struct drm_crtc base;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_pending_vblank_event *event;
+	int id;
+	int dpms;
+	struct atmel_hlcdc_crtc_cursor cursor;
+};
+
+static inline struct atmel_hlcdc_crtc *
+drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct atmel_hlcdc_crtc, base);
+}
+
+
+static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
+{
+	struct drm_device *dev = c->dev;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	pm_runtime_get_sync(dev->dev);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		pm_runtime_forbid(dev->dev);
+	else
+		pm_runtime_allow(dev->dev);
+
+	pm_runtime_put_sync(dev->dev);
+}
+
+static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted,
+				     int x, int y,
+				     struct drm_framebuffer *old_fb)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct regmap *regmap = crtc->hlcdc->regmap;
+	struct drm_plane *plane = c->primary;
+	struct drm_framebuffer *fb;
+	struct videomode vm;
+
+	vm.vfront_porch = mode->vsync_start - mode->vdisplay;
+	vm.vback_porch = mode->vtotal - mode->vsync_end;
+	vm.vsync_len = mode->vsync_end - mode->vsync_start;
+	vm.hfront_porch = mode->hsync_start - mode->hdisplay;
+	vm.hback_porch = mode->htotal - mode->hsync_end;
+	vm.hsync_len = mode->hsync_end - mode->hsync_start;
+
+	if (vm.hsync_len > 0x40 || vm.hsync_len < 1 ||
+	    vm.vsync_len > 0x40 || vm.vsync_len < 1 ||
+	    vm.vfront_porch > 0x40 || vm.vfront_porch < 1 ||
+	    vm.vback_porch > 0x40 || vm.vback_porch < 0 ||
+	    vm.hfront_porch > 0x200 || vm.hfront_porch < 1 ||
+	    vm.hback_porch > 0x200 || vm.hback_porch < 1 ||
+	    mode->hdisplay > 2048 || mode->hdisplay < 1 ||
+	    mode->vdisplay > 2048 || mode->vdisplay < 1)
+		return -EINVAL;
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(1),
+		     (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(2),
+		     (vm.vfront_porch - 1) | (vm.vback_porch << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(3),
+		     (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(4),
+		     (mode->hdisplay - 1) | ((mode->vdisplay - 1) << 16));
+
+	fb = plane->fb;
+	plane->fb = old_fb;
+
+	return plane->funcs->update_plane(plane, c, fb,
+					  0, 0,
+					  mode->hdisplay, mode->vdisplay,
+					  c->x << 16, c->y << 16,
+					  mode->hdisplay << 16,
+					  mode->vdisplay << 16);
+}
+
+static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
+					const struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+
+static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
+
+	.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
+	.dpms = atmel_hlcdc_crtc_dpms,
+	.mode_set = atmel_hlcdc_crtc_mode_set,
+	.prepare = atmel_hlcdc_crtc_prepare,
+	.commit = atmel_hlcdc_crtc_commit,
+};
+
+static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+	drm_crtc_cleanup(c);
+	kfree(crtc);
+}
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
+				       struct drm_file *file)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct drm_pending_vblank_event *event;
+	struct drm_device *dev = c->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = crtc->event;
+	if (event && event->base.file_priv == file) {
+		event->base.destroy(&event->base);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void atmel_hlcdc_crtc_finish_page_flip(void *data)
+{
+	struct atmel_hlcdc_crtc *crtc = data;
+	struct drm_device *dev = crtc->base.dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (crtc->event) {
+		drm_send_vblank_event(dev, crtc->id, crtc->event);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
+				      struct drm_framebuffer *fb,
+				      struct drm_pending_vblank_event *event,
+				      uint32_t page_flip_flags)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane_update_req req;
+	struct drm_plane *plane = c->primary;
+	int ret;
+	int i;
+
+	if (crtc->event)
+		return -EBUSY;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = 0;
+	req.crtc_y = 0;
+	req.crtc_h = c->mode.crtc_vdisplay;
+	req.crtc_w = c->mode.crtc_hdisplay;
+	req.src_x = c->x << 16;
+	req.src_y = c->y << 16;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = fb->pixel_format;
+
+	for (i = 0; i < ATMEL_HLCDC_MAX_PLANES; i++) {
+		req.offsets[i] = fb->offsets[i];
+		req.pitches[i] = fb->pitches[i];
+		req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
+	}
+
+	req.crtc = c;
+	req.finished = atmel_hlcdc_crtc_finish_page_flip;
+	req.finished_data = crtc;
+
+	ret = atmel_hlcdc_plane_prepare_update_req(plane, &req);
+	if (ret)
+		return ret;
+
+	if (event) {
+		crtc->event = event;
+		drm_vblank_get(c->dev, crtc->id);
+	}
+
+	ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
+
+	if (ret) {
+		crtc->event = NULL;
+		drm_vblank_put(c->dev, crtc->id);
+	} else {
+		drm_framebuffer_reference(fb);
+		if (plane->fb)
+			drm_framebuffer_unreference(plane->fb);
+		plane->fb = fb;
+	}
+
+	return ret;
+}
+
+static int atmel_hlcdc_crtc_cursor_set(struct drm_crtc *c,
+				       struct drm_file *file_priv,
+				       uint32_t handle,
+				       uint32_t width, uint32_t height)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
+	struct drm_gem_cma_object *cma_gem = NULL;
+	struct atmel_hlcdc_plane_update_req req;
+	int ret;
+
+	if (unlikely(!plane))
+		return -ENOTSUPP;
+
+	mutex_lock(&crtc->cursor.lock);
+
+	if (handle) {
+		struct drm_gem_object *gem;
+
+		gem = drm_gem_object_lookup(c->dev, file_priv, handle);
+		if (unlikely(!gem)) {
+			ret = -ENOENT;
+			goto out;
+		}
+
+		cma_gem = to_drm_gem_cma_obj(gem);
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = crtc->cursor.x;
+	req.crtc_y = crtc->cursor.y;
+	req.crtc_h = height;
+	req.crtc_w = width;
+	req.src_x = 0;
+	req.src_y = 0;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = DRM_FORMAT_ARGB8888;
+	req.gems[0] = cma_gem;
+	req.offsets[0] = 0;
+	req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) * width;
+	req.crtc = c;
+
+	if (!req.gems[0] || !req.src_h || !req.src_w) {
+		cma_gem = crtc->cursor.gem;
+		ret = plane->base.funcs->disable_plane(&plane->base);
+		if (!ret && cma_gem) {
+			drm_gem_object_unreference_unlocked(&cma_gem->base);
+			crtc->cursor.gem = NULL;
+		}
+
+		goto out;
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		goto err_release_gem;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		goto err_release_gem;
+
+	crtc->cursor.height = width;
+	crtc->cursor.width = width;
+	if (crtc->cursor.gem)
+		drm_gem_object_unreference_unlocked(&crtc->cursor.gem->base);
+	crtc->cursor.gem = cma_gem;
+
+	goto out;
+
+err_release_gem:
+	if (cma_gem)
+		drm_gem_object_unreference_unlocked(&cma_gem->base);
+
+out:
+	mutex_unlock(&crtc->cursor.lock);
+	return ret;
+}
+
+static int atmel_hlcdc_crtc_cursor_move(struct drm_crtc *c, int x, int y)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
+	struct atmel_hlcdc_plane_update_req req;
+	int ret;
+
+	if (unlikely(!plane))
+		return -ENOTSUPP;
+
+	mutex_lock(&crtc->cursor.lock);
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = x;
+	req.crtc_y = y;
+	req.crtc_h = crtc->cursor.height;
+	req.crtc_w = crtc->cursor.width;
+	req.src_x = 0;
+	req.src_y = 0;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = DRM_FORMAT_ARGB8888;
+	req.gems[0] = crtc->cursor.gem;
+	req.offsets[0] = 0;
+	req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) *
+			 crtc->cursor.width;
+	req.crtc = c;
+
+	if (!req.gems[0] || !req.src_h || !req.src_w) {
+		struct drm_gem_cma_object *cma_gem = crtc->cursor.gem;
+
+		ret = plane->base.funcs->disable_plane(&plane->base);
+		if (!ret && cma_gem) {
+			drm_gem_object_unreference_unlocked(&cma_gem->base);
+			crtc->cursor.gem = NULL;
+		}
+
+		goto out;
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		goto out;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		goto out;
+
+	crtc->cursor.x = x;
+	crtc->cursor.y = y;
+
+out:
+	mutex_unlock(&crtc->cursor.lock);
+	return ret;
+}
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
+	.page_flip = atmel_hlcdc_crtc_page_flip,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = atmel_hlcdc_crtc_destroy,
+};
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_with_cursor_funcs = {
+	.page_flip = atmel_hlcdc_crtc_page_flip,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = atmel_hlcdc_crtc_destroy,
+	.cursor_set = atmel_hlcdc_crtc_cursor_set,
+	.cursor_move = atmel_hlcdc_crtc_cursor_move,
+};
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes = dc->planes;
+	const struct drm_crtc_funcs *funcs;
+	struct atmel_hlcdc_crtc *crtc;
+	int ret;
+	int i;
+
+	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+	if (!crtc) {
+		dev_err(dev->dev, "allocation failed\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&crtc->cursor.lock);
+	crtc->hlcdc = dc->hlcdc;
+	crtc->cursor.plane = planes->cursor;
+
+	if (planes->cursor)
+		funcs = &atmel_hlcdc_crtc_with_cursor_funcs;
+	else
+		funcs = &atmel_hlcdc_crtc_funcs;
+
+	ret = drm_crtc_init_with_planes(dev, &crtc->base,
+				&planes->primary->base,
+				planes->cursor ? &planes->cursor->base : NULL,
+				funcs);
+	if (ret < 0)
+		goto fail;
+
+	crtc->id = drm_crtc_index(&crtc->base);
+
+	if (planes->cursor)
+		planes->cursor->base.possible_crtcs = 1 << crtc->id;
+
+	for (i = 0; i < planes->noverlays; i++)
+		planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
+
+	drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+
+	return 0;
+
+fail:
+	atmel_hlcdc_crtc_destroy(&crtc->base);
+	return ret;
+}
+
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
new file mode 100644
index 0000000..bfecd0d
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "atmel_hlcdc_dc.h"
+
+#define ATMEL_HLCDC_LAYER_IRQS_OFFSET		8
+
+static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
+	{
+		.name = "base",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x40,
+		.id = 0,
+		.type = ATMEL_HLCDC_BASE_LAYER,
+		.nconfigs = 7,
+		.layout = {
+			.xstride = { 2 },
+			.default_color = 3,
+			.general_config = 4,
+			.disc_pos = 5,
+			.disc_size = 6,
+		},
+	},
+	{
+		.name = "overlay1",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x140,
+		.id = 1,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "overlay2",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x240,
+		.id = 2,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "high-end-overlay",
+		.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+		.regs_offset = 0x340,
+		.id = 3,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 42,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.memsize = 4,
+			.xstride = { 5, 7 },
+			.pstride = { 6, 8 },
+			.default_color = 9,
+			.chroma_key = 10,
+			.chroma_key_mask = 11,
+			.general_config = 12,
+			.csc = 14,
+		},
+	},
+	{
+		.name = "cursor",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x440,
+		.id = 4,
+		.type = ATMEL_HLCDC_CURSOR_LAYER,
+		.nconfigs = 10,
+		.max_width = 128,
+		.max_height = 128,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
+	.min_width = 0,
+	.min_height = 0,
+	.max_width = 2048,
+	.max_height = 2048,
+	.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
+	.layers = atmel_hlcdc_sama5d3_layers,
+};
+
+static const struct of_device_id atmel_hlcdc_of_match[] = {
+	{
+		.compatible = "atmel,sama5d3-hlcdc",
+		.data = &atmel_hlcdc_dc_sama5d3,
+	},
+	{ /* sentinel */ },
+};
+
+static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
+{
+	struct drm_device *dev = data;
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned long status;
+	unsigned int imr, isr;
+	int bit;
+
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return IRQ_NONE;
+
+	bit = ATMEL_HLCDC_LAYER_IRQS_OFFSET;
+	for_each_set_bit_from(bit, &status, ATMEL_HLCDC_LAYER_IRQS_OFFSET +
+					    ATMEL_HLCDC_MAX_LAYERS) {
+		int layerid = bit - ATMEL_HLCDC_LAYER_IRQS_OFFSET;
+		struct atmel_hlcdc_layer *layer = dc->layers[layerid];
+
+		if (layer)
+			atmel_hlcdc_layer_irq(layer);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	if (dc->fbdev) {
+		drm_fbdev_cma_hotplug_event(dc->fbdev);
+	} else {
+		dc->fbdev = drm_fbdev_cma_init(dev, 24,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(dc->fbdev))
+			dc->fbdev = NULL;
+	}
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = atmel_hlcdc_fb_create,
+	.output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+};
+
+static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes;
+	int ret;
+	int i;
+
+	drm_mode_config_init(dev);
+
+	ret = atmel_hlcdc_panel_create(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create panel: %d\n", ret);
+		return ret;
+	}
+
+	planes = atmel_hlcdc_create_planes(dev);
+	if (IS_ERR(planes)) {
+		dev_err(dev->dev, "failed to create planes\n");
+		return PTR_ERR(planes);
+	}
+
+	dc->planes = planes;
+
+	dc->layers[planes->primary->layer.desc->id] =
+						&planes->primary->layer;
+
+	if (planes->cursor)
+		dc->layers[planes->cursor->layer.desc->id] =
+							&planes->cursor->layer;
+
+	for (i = 0; i < planes->noverlays; i++)
+		dc->layers[planes->overlays[i]->layer.desc->id] =
+						&planes->overlays[i]->layer;
+
+	ret = atmel_hlcdc_crtc_create(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create crtc\n");
+		return ret;
+	}
+
+	dev->mode_config.min_width = dc->desc->min_width;
+	dev->mode_config.min_height = dc->desc->min_height;
+	dev->mode_config.max_width = dc->desc->max_width;
+	dev->mode_config.max_height = dc->desc->max_height;
+	dev->mode_config.funcs = &mode_config_funcs;
+
+	return 0;
+}
+
+static int atmel_hlcdc_dc_load(struct drm_device *dev, unsigned long flags)
+{
+	struct platform_device *pdev = dev->platformdev;
+	const struct of_device_id *match;
+	struct atmel_hlcdc_dc *dc;
+	int ret;
+
+	match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "invalid compatible string\n");
+		return -ENODEV;
+	}
+
+	if (!match->data) {
+		dev_err(&pdev->dev, "invalid hlcdc description\n");
+		return -EINVAL;
+	}
+
+	dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc) {
+		dev_err(dev->dev, "failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dc->desc = match->data;
+	dc->hlcdc = dev_get_drvdata(dev->dev->parent);
+	dev->dev_private = dc;
+
+	ret = clk_prepare_enable(dc->hlcdc->periph_clk);
+	if (ret) {
+		dev_err(dev->dev, "failed to enable periph_clk\n");
+		return ret;
+	}
+
+	pm_runtime_enable(dev->dev);
+
+	pm_runtime_put_sync(dev->dev);
+
+	ret = atmel_hlcdc_dc_modeset_init(dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize mode setting\n");
+		goto err_periph_clk_disable;
+	}
+
+	ret = drm_vblank_init(dev, 1);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize vblank\n");
+		goto err_periph_clk_disable;
+	}
+
+	pm_runtime_get_sync(dev->dev);
+	ret = drm_irq_install(dev);
+	pm_runtime_put_sync(dev->dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to install IRQ handler\n");
+		goto err_periph_clk_disable;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	drm_kms_helper_poll_init(dev);
+
+	/* force connectors detection */
+	drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_periph_clk_disable:
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+	return ret;
+}
+
+static int atmel_hlcdc_dc_unload(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	drm_kms_helper_poll_fini(dev);
+	drm_mode_config_cleanup(dev);
+	drm_vblank_cleanup(dev);
+
+	pm_runtime_get_sync(dev->dev);
+	drm_irq_uninstall(dev);
+	pm_runtime_put_sync(dev->dev);
+
+	dev->dev_private = NULL;
+
+	pm_runtime_disable(dev->dev);
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_preclose(struct drm_device *dev,
+				    struct drm_file *file)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+		atmel_hlcdc_crtc_cancel_page_flip(crtc, file);
+}
+
+static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	drm_fbdev_cma_restore_mode(dc->fbdev);
+}
+
+static void atmel_hlcdc_dc_irq_preinstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned int isr;
+
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+}
+
+static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	int i;
+
+	/* Enable interrupts on activated layers */
+	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+		if (dc->layers[i])
+			regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER,
+				     BIT(i + 8));
+	}
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
+{
+
+}
+
+static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc)
+{
+	return 0;
+}
+
+static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc)
+{
+}
+
+static const struct file_operations 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 atmel_hlcdc_dc_driver = {
+	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+	.load = atmel_hlcdc_dc_load,
+	.unload = atmel_hlcdc_dc_unload,
+	.preclose = atmel_hlcdc_dc_preclose,
+	.lastclose = atmel_hlcdc_dc_lastclose,
+	.irq_handler = atmel_hlcdc_dc_irq_handler,
+	.irq_preinstall = atmel_hlcdc_dc_irq_preinstall,
+	.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
+	.irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
+	.get_vblank_counter = drm_vblank_count,
+	.enable_vblank = atmel_hlcdc_dc_enable_vblank,
+	.disable_vblank = atmel_hlcdc_dc_disable_vblank,
+	.gem_free_object = drm_gem_cma_free_object,
+	.gem_vm_ops = &drm_gem_cma_vm_ops,
+	.dumb_create = drm_gem_cma_dumb_create,
+	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+	.fops = &fops,
+	.name = "atmel-hlcdc",
+	.desc = "Atmel HLCD Controller DRM",
+	.date = "20141504",
+	.major = 1,
+	.minor = 0,
+};
+
+static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	ret = drm_platform_init(&atmel_hlcdc_dc_driver, pdev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
+{
+	drm_put_dev(platform_get_drvdata(pdev));
+
+	return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
+	{ .compatible = "atmel,hlcdc-dc" },
+	{ },
+};
+
+static struct platform_driver atmel_hlcdc_dc_platform_driver = {
+	.probe	= atmel_hlcdc_dc_drm_probe,
+	.remove	= atmel_hlcdc_dc_drm_remove,
+	.driver	= {
+		.name	= "atmel-hlcdc-dc",
+		.owner	= THIS_MODULE,
+		.of_match_table = atmel_hlcdc_dc_of_match,
+	},
+};
+module_platform_driver(atmel_hlcdc_dc_platform_driver);
+
+MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel-hlcdc-dc");
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
new file mode 100644
index 0000000..1386998
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_ATMEL_HLCDC_H
+#define DRM_ATMEL_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/irqdomain.h>
+#include <linux/pwm.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_panel.h>
+#include <drm/drmP.h>
+
+#include "atmel_hlcdc_layer.h"
+
+#define ATMEL_HLCDC_MAX_LAYERS		5
+
+/**
+ * Atmel HLCDC Display Controller description structure.
+ *
+ * This structure describe the HLCDC IP capabilities and depends on the
+ * HLCDC IP version (or Atmel SoC family).
+ *
+ * @min_width: minimum width supported by the Display Controller
+ * @min_height: minimum height supported by the Display Controller
+ * @max_width: maximum width supported by the Display Controller
+ * @max_height: maximum height supported by the Display Controller
+ * @layer: a layer description table describing available layers
+ * @nlayers: layer description table size
+ */
+struct atmel_hlcdc_dc_desc {
+	int min_width;
+	int min_height;
+	int max_width;
+	int max_height;
+	const struct atmel_hlcdc_layer_desc *layers;
+	int nlayers;
+};
+
+/**
+ * Atmel HLCDC Plane properties.
+ *
+ * This structure stores plane property definitions.
+ *
+ * @alpha: alpha blending (or transparency) property
+ * @csc: YUV to RGB conversion factors property
+ */
+struct atmel_hlcdc_plane_properties {
+	struct drm_property *alpha;
+	struct drm_property *csc;
+};
+
+/**
+ * Atmel HLCDC Plane.
+ *
+ * @base: base DRM plane structure
+ * @layer: HLCDC layer structure
+ * @properties: pointer to the property definitions structure
+ * @alpha: current alpha blending (or transparency) status
+ */
+struct atmel_hlcdc_plane {
+	struct drm_plane base;
+	struct atmel_hlcdc_layer layer;
+	struct atmel_hlcdc_plane_properties *properties;
+};
+
+static inline struct atmel_hlcdc_plane *
+drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
+{
+	return container_of(p, struct atmel_hlcdc_plane, base);
+}
+
+static inline struct atmel_hlcdc_plane *
+atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
+{
+	return container_of(l, struct atmel_hlcdc_plane, layer);
+}
+
+/**
+ * Atmel HLCDC Plane update request structure.
+ *
+ * @crtc_x: x position of the plane relative to the CRTC
+ * @crtc_y: y position of the plane relative to the CRTC
+ * @crtc_w: visible width of the plane
+ * @crtc_h: visible height of the plane
+ * @src_x: x buffer position
+ * @src_y: y buffer position
+ * @src_w: buffer width
+ * @src_h: buffer height
+ * @pixel_format: pixel format
+ * @gems: GEM object object containing image buffers
+ * @offsets: offsets to apply to the GEM buffers
+ * @pitches: line size in bytes
+ * @crtc: crtc to display on
+ * @finished: finished callback
+ * @finished_data: data passed to the finished callback
+ * @bpp: bytes per pixel deduced from pixel_format
+ * @xstride: value to add to the pixel pointer between each line
+ * @pstride: value to add to the pixel pointer between each pixel
+ * @nplanes: number of planes (deduced from pixel_format)
+ */
+struct atmel_hlcdc_plane_update_req {
+	int crtc_x;
+	int crtc_y;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	uint32_t src_x;
+	uint32_t src_y;
+	uint32_t src_w;
+	uint32_t src_h;
+	uint32_t pixel_format;
+	struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
+	unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
+	unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
+	struct drm_crtc *crtc;
+	void (*finished)(void *data);
+	void *finished_data;
+
+	/* These fields are private and should not be touched */
+	int bpp[ATMEL_HLCDC_MAX_PLANES];
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int nplanes;
+};
+
+/**
+ * Atmel HLCDC Planes.
+ *
+ * This structure stores the instantiated HLCDC Planes and can be accessed by
+ * the HLCDC Display Controller or the HLCDC CRTC.
+ *
+ * @primary: primary plane
+ * @cursor: hardware cursor plane
+ * @overlays: overlay plane table
+ * @noverlays: number of overlay planes
+ */
+struct atmel_hlcdc_planes {
+	struct atmel_hlcdc_plane *primary;
+	struct atmel_hlcdc_plane *cursor;
+	struct atmel_hlcdc_plane **overlays;
+	int noverlays;
+};
+
+/**
+ * Atmel HLCDC Display Controller.
+ *
+ * @desc: HLCDC Display Controller description
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @fbdev: framebuffer device attached to the Display Controller
+ * @planes: instantiated planes
+ * @layers: active HLCDC layer
+ */
+struct atmel_hlcdc_dc {
+	const struct atmel_hlcdc_dc_desc *desc;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_fbdev_cma *fbdev;
+	struct atmel_hlcdc_planes *planes;
+	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
+};
+
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev);
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req);
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req);
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
+				       struct drm_file *file);
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev);
+
+int atmel_hlcdc_panel_create(struct drm_device *dev);
+
+struct atmel_hlcdc_pwm_chip *atmel_hlcdc_pwm_create(struct drm_device *dev,
+						    struct clk *slow_clk,
+						    struct clk *sys_clk,
+						    void __iomem *regs);
+
+int atmel_hlcdc_pwm_destroy(struct drm_device *dev,
+			    struct atmel_hlcdc_pwm_chip *chip);
+
+#endif /* DRM_ATMEL_HLCDC_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
new file mode 100644
index 0000000..57c50ec
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+
+#include "atmel_hlcdc_dc.h"
+
+static void
+atmel_hlcdc_layer_gem_flip_release(struct atmel_hlcdc_layer *layer,
+				   struct atmel_hlcdc_layer_gem_flip *flip)
+{
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!flip->gems[i])
+			break;
+
+		drm_gem_object_unreference_unlocked(flip->gems[i]);
+	}
+
+	kfree(flip);
+}
+
+static void atmel_hlcdc_layer_gc_work(struct work_struct *work)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc =
+			container_of(work,
+				     struct atmel_hlcdc_layer_gem_flip_gc,
+				     work);
+	struct atmel_hlcdc_layer *layer =
+			container_of(gc , struct atmel_hlcdc_layer, gc);
+
+	while (true) {
+		struct atmel_hlcdc_layer_gem_flip *flip;
+		unsigned long flags;
+
+		spin_lock_irqsave(&gc->list_lock, flags);
+		flip = list_first_entry_or_null(&gc->list,
+					struct atmel_hlcdc_layer_gem_flip,
+					node);
+		if (flip)
+			list_del(&flip->node);
+		spin_unlock_irqrestore(&gc->list_lock, flags);
+
+		if (!flip)
+			break;
+
+		atmel_hlcdc_layer_gem_flip_release(layer, flip);
+	}
+}
+
+static void
+atmel_hlcdc_layer_gem_flip_put(struct atmel_hlcdc_layer *layer,
+			       struct atmel_hlcdc_layer_gem_flip *flip)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+	unsigned long flags;
+
+	if (--flip->remaining_gems <= 0) {
+		spin_lock_irqsave(&gc->list_lock, flags);
+		list_add_tail(&flip->node,
+			      &gc->list);
+		spin_unlock_irqrestore(&gc->list_lock, flags);
+		schedule_work(&gc->work);
+	}
+}
+
+static void atmel_hlcdc_layer_start_queue(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		dma->cur[i] = dma->queue[i];
+		if (!dma->queue[i])
+			continue;
+		dma->queue[i] = NULL;
+
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+			     dma->cur[i]->addr);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+			     dma->cur[i]->ctrl);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+			     dma->cur[i]->next);
+	}
+}
+
+static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
+{
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned int cfg;
+	u32 action = 0;
+	int i;
+
+	if (upd->pending < 0 || upd->pending > 1)
+		return;
+
+	slot = &upd->slots[upd->pending];
+
+	for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CFG(layer, cfg),
+			     slot->configs[cfg]);
+		action |= ATMEL_HLCDC_LAYER_UPDATE;
+	}
+
+	if (slot->gem_flip && slot->gem_flip->remaining_gems) {
+		struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+
+		for (i = 0; i < layer->max_planes; i++) {
+			struct atmel_hlcdc_dma_channel_dscr *dscr;
+
+			if (!slot->gem_flip->gems[i])
+				break;
+
+			dscr =  slot->dscrs[i];
+			slot->dscrs[i] = NULL;
+
+			if (!dma->enabled) {
+				action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+					     dscr->addr);
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+					     dscr->ctrl);
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+					     dscr->next);
+				dma->cur[i] = dscr;
+			} else {
+				action |= ATMEL_HLCDC_LAYER_A2Q;
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
+					     dscr->next);
+				dma->queue[i] = dscr;
+			}
+		}
+
+		dma->enabled = true;
+		slot->gem_flip = NULL;
+	}
+
+	if (action)
+		regmap_write(regmap,
+			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
+			     action);
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!slot->dscrs[i])
+			continue;
+
+		slot->dscrs[i]->gem_flip = NULL;
+		slot->dscrs[i] = NULL;
+	}
+
+	if (slot->gem_flip) {
+		atmel_hlcdc_layer_gem_flip_put(layer, slot->gem_flip);
+		slot->gem_flip = NULL;
+	}
+
+	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+	memset(slot->configs, 0,
+	       sizeof(*slot->configs) * layer->desc->nconfigs);
+
+	upd->pending = -1;
+}
+
+static bool
+atmel_hlcdc_layer_dma_channel_active(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (dma->cur[i])
+			return true;
+	}
+
+	return false;
+}
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip *flip_gc[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct atmel_hlcdc_layer_gem_flip *flip = NULL;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	unsigned long flags;
+	unsigned int isr, imr;
+	unsigned int status;
+
+	int i;
+
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return;
+
+	memset(flip_gc, 0, sizeof(flip_gc));
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if ((status & ATMEL_HLCDC_LAYER_DONE_IRQ(i)) ||
+		    (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i))) {
+			dscr = dma->cur[i];
+			dma->cur[i] = NULL;
+			flip_gc[i] = dscr->gem_flip;
+			dscr->gem_flip = NULL;
+		}
+
+		if (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i)) {
+			dma->cur[i] = dma->queue[i];
+			flip = dma->queue[i]->gem_flip;
+			dma->queue[i] = NULL;
+		}
+	}
+
+	if (flip && flip->finished &&
+	    !atmel_hlcdc_layer_dma_channel_busy(layer))
+		flip->finished(flip->finished_data);
+
+	/*
+	 * The DMA channel might have been disabled before we were able to
+	 * add the new frame to the DMA transfer queue.
+	 * Try to re-enable the channel in this case.
+	 */
+	if (!atmel_hlcdc_layer_dma_channel_active(layer)) {
+		if (atmel_hlcdc_layer_dma_channel_busy(layer)) {
+			atmel_hlcdc_layer_start_queue(layer);
+
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_CHDR,
+				     ATMEL_HLCDC_LAYER_A2Q);
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_CHER,
+				     ATMEL_HLCDC_LAYER_DMA_CHAN);
+		} else {
+			dma->enabled = false;
+		}
+	}
+
+	if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
+		struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+		spin_lock(&upd->pending_lock);
+		atmel_hlcdc_layer_update_apply(layer);
+		spin_unlock(&upd->pending_lock);
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!flip_gc[i])
+			break;
+
+		atmel_hlcdc_layer_gem_flip_put(layer, flip_gc[i]);
+	}
+}
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!dma->cur[i])
+			break;
+
+		dma->cur[i]->ctrl = 0;
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	return 0;
+}
+
+static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int i;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+	memset(slot->configs, 0,
+	       sizeof(*slot->configs) * layer->desc->nconfigs);
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!slot->dscrs[i])
+			break;
+		slot->dscrs[i]->gem_flip = NULL;
+		slot->dscrs[i] = NULL;
+	}
+	spin_unlock_irqrestore(&layer->dma.lock, flags);
+
+	if (slot->gem_flip) {
+		atmel_hlcdc_layer_gem_flip_release(layer, slot->gem_flip);
+		slot->gem_flip = NULL;
+	}
+
+	upd->next = -1;
+}
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int i, j = 0;
+	int pending;
+
+	gem_flip = kzalloc(sizeof(*gem_flip), GFP_KERNEL);
+	if (!gem_flip)
+		return -ENOMEM;
+
+	mutex_lock(&upd->lock);
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	upd->next = pending ? 0 : 1;
+
+	slot = &upd->slots[upd->next];
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		if (!dma->dscrs[i].gem_flip) {
+			slot->dscrs[j++] = &dma->dscrs[i];
+			dma->dscrs[i].gem_flip = gem_flip;
+			if (j == layer->max_planes)
+				break;
+		}
+	}
+
+	if (j < layer->max_planes) {
+		for (i = 0; i < j; i++)
+			slot->dscrs[i]->gem_flip = NULL;
+	}
+	spin_unlock_irqrestore(&layer->dma.lock, flags);
+
+	if (j < layer->max_planes) {
+		mutex_unlock(&upd->lock);
+		kfree(gem_flip);
+		return -EBUSY;
+	}
+
+	slot->gem_flip = gem_flip;
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	if (pending >= 0) {
+		memcpy(upd->slots[upd->next].configs,
+		       upd->slots[upd->pending].configs,
+		       layer->desc->nconfigs * sizeof(u32));
+		memcpy(upd->slots[upd->next].updated_configs,
+		       upd->slots[upd->pending].updated_configs,
+		       DIV_ROUND_UP(layer->desc->nconfigs,
+				    BITS_PER_BYTE * sizeof(unsigned long)) *
+		       sizeof(unsigned long));
+	}
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	if (pending < 0) {
+		regmap_bulk_read(regmap,
+				 layer->desc->regs_offset +
+				 ATMEL_HLCDC_LAYER_CFG(layer, 0),
+				 upd->slots[upd->next].configs,
+				 layer->desc->nconfigs);
+	}
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+	atmel_hlcdc_layer_update_reset(layer);
+	mutex_unlock(&upd->lock);
+}
+
+void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
+				      int plane_id,
+				      struct drm_gem_cma_object *gem,
+				      unsigned int offset)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	struct drm_gem_object *old_gem;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (plane_id >= layer->max_planes || plane_id < 0)
+		return;
+
+	slot = &upd->slots[upd->next];
+	dscr = slot->dscrs[plane_id];
+	dscr->addr = gem->paddr + offset;
+	dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
+	gem_flip = dscr->gem_flip;
+
+	old_gem = gem_flip->gems[plane_id];
+
+	if (gem) {
+		drm_gem_object_reference(&gem->base);
+		gem_flip->gems[plane_id] = &gem->base;
+		gem_flip->remaining_gems++;
+	} else {
+		gem_flip->gems[plane_id] = NULL;
+	}
+
+	if (old_gem) {
+		drm_gem_object_unreference_unlocked(old_gem);
+		gem_flip->remaining_gems--;
+	}
+}
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+					   void (*finished)(void *data),
+					   void *finished_data)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	slot->gem_flip->finished = finished;
+	slot->gem_flip->finished_data = finished_data;
+}
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (cfg >= layer->desc->nconfigs)
+		return;
+
+	slot = &upd->slots[upd->next];
+	slot->configs[cfg] &= ~mask;
+	slot->configs[cfg] |= (val & mask);
+	set_bit(cfg, slot->updated_configs);
+}
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int pending;
+
+	if (upd->next < 0  || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	upd->pending = upd->next;
+	upd->next = pending;
+	if (pending >= 0 && !slot->gem_flip->remaining_gems) {
+		struct atmel_hlcdc_layer_gem_flip *gem_flip = slot->gem_flip;
+		struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+
+		memcpy(dscrs, slot->dscrs, sizeof(dscrs));
+		slot->gem_flip = upd->slots[pending].gem_flip;
+		memcpy(slot->dscrs, upd->slots[pending].dscrs,
+		       sizeof(slot->dscrs));
+		upd->slots[pending].gem_flip = gem_flip;
+		memcpy(upd->slots[pending].dscrs, dscrs, sizeof(dscrs));
+	}
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	if (pending >= 0) {
+		atmel_hlcdc_layer_update_reset(layer);
+		mutex_unlock(&upd->lock);
+		return;
+	}
+
+	spin_lock_irqsave(&dma->lock, flags);
+	if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
+		spin_lock(&upd->pending_lock);
+		atmel_hlcdc_layer_update_apply(layer);
+		spin_unlock(&upd->pending_lock);
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	atmel_hlcdc_layer_update_reset(layer);
+	mutex_unlock(&upd->lock);
+}
+
+static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
+				      struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	dma_addr_t dma_addr;
+	int i;
+
+	dma->dscrs = dma_alloc_coherent(dev->dev,
+					layer->max_planes * 4 *
+					sizeof(*dma->dscrs),
+					&dma_addr, GFP_KERNEL);
+	if (!dma->dscrs)
+		return -ENOMEM;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		dscr->next = dma_addr + (i * sizeof(*dscr));
+	}
+
+	spin_lock_init(&dma->lock);
+
+	return 0;
+}
+
+static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
+					  struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		if (!dscr->gem_flip)
+			continue;
+
+		atmel_hlcdc_layer_gem_flip_put(layer, dscr->gem_flip);
+	}
+
+	dma_free_coherent(dev->dev, layer->max_planes * 4 *
+			  sizeof(*dma->dscrs), dma->dscrs,
+			  dma->dscrs[0].next);
+}
+
+static void atmel_hlcdc_layer_gc_init(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+
+	INIT_LIST_HEAD(&gc->list);
+	spin_lock_init(&gc->list_lock);
+	INIT_WORK(&gc->work, atmel_hlcdc_layer_gc_work);
+}
+
+static void atmel_hlcdc_layer_gc_cleanup(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+
+	flush_work(&gc->work);
+}
+
+static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
+				struct atmel_hlcdc_layer *layer,
+				const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	int updated_size;
+	void *buffer;
+	int i;
+
+	updated_size = DIV_ROUND_UP(desc->nconfigs,
+				    BITS_PER_BYTE *
+				    sizeof(unsigned long));
+
+	buffer = devm_kzalloc(dev->dev,
+			      ((desc->nconfigs * sizeof(u32)) +
+				(updated_size * sizeof(unsigned long))) * 2,
+			      GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i = 0; i < 2; i++) {
+		upd->slots[i].updated_configs = buffer;
+		buffer += updated_size * sizeof(unsigned long);
+		upd->slots[i].configs = buffer;
+		buffer += desc->nconfigs * sizeof(u32);
+	}
+
+	upd->pending = -1;
+	upd->next = -1;
+	spin_lock_init(&upd->pending_lock);
+	mutex_init(&upd->lock);
+
+	return 0;
+}
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct regmap *regmap = dc->hlcdc->regmap;
+	unsigned int tmp;
+	int ret;
+	int i;
+
+	layer->hlcdc = dc->hlcdc;
+	layer->desc = desc;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+	for (i = 0; i < desc->formats->nformats; i++) {
+		int nplanes = drm_format_num_planes(desc->formats->formats[i]);
+
+		if (nplanes > layer->max_planes)
+			layer->max_planes = nplanes;
+	}
+
+	atmel_hlcdc_layer_gc_init(layer);
+	ret = atmel_hlcdc_layer_dma_init(dev, layer);
+	if (ret)
+		return ret;
+
+	ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
+	if (ret)
+		return ret;
+
+	/* Flush Status Register */
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
+		    &tmp);
+
+	for (i = 0; i < layer->max_planes; i++)
+		regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER,
+			     ATMEL_HLCDC_LAYER_ADD_IRQ(i) |
+			     ATMEL_HLCDC_LAYER_DONE_IRQ(i));
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer)
+{
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+
+	atmel_hlcdc_layer_dma_cleanup(dev, layer);
+	atmel_hlcdc_layer_gc_cleanup(layer);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
new file mode 100644
index 0000000..006d479
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_ATMEL_HLCDC_LAYER_H
+#define DRM_ATMEL_HLCDC_LAYER_H
+
+#include <linux/mfd/atmel-hlcdc.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drmP.h>
+
+#define ATMEL_HLCDC_LAYER_CHER			0x0
+#define ATMEL_HLCDC_LAYER_CHDR			0x4
+#define ATMEL_HLCDC_LAYER_CHSR			0x8
+#define ATMEL_HLCDC_LAYER_DMA_CHAN		BIT(0)
+#define ATMEL_HLCDC_LAYER_UPDATE		BIT(1)
+#define ATMEL_HLCDC_LAYER_A2Q			BIT(2)
+#define ATMEL_HLCDC_LAYER_RST			BIT(8)
+
+#define ATMEL_HLCDC_LAYER_IER			0xc
+#define ATMEL_HLCDC_LAYER_IDR			0x10
+#define ATMEL_HLCDC_LAYER_IMR			0x14
+#define ATMEL_HLCDC_LAYER_ISR			0x18
+#define ATMEL_HLCDC_LAYER_DFETCH		BIT(0)
+#define ATMEL_HLCDC_LAYER_LFETCH		BIT(1)
+#define ATMEL_HLCDC_LAYER_DMA_IRQ(n)		BIT(2 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_DSCR_IRQ(n)		BIT(3 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_ADD_IRQ(n)		BIT(4 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_DONE_IRQ(n)		BIT(5 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_OVR_IRQ(n)		BIT(6 + ((n) * 8))
+
+#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n)		(((n) * 0x10) + 0x1c)
+#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n)		(((n) * 0x10) + 0x20)
+#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n)		(((n) * 0x10) + 0x24)
+#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n)		(((n) * 0x10) + 0x28)
+#define ATMEL_HLCDC_LAYER_CFG(p, c)		(((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
+
+#define ATMEL_HLCDC_LAYER_DMA_CFG_ID		0
+#define ATMEL_HLCDC_LAYER_DMA_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
+
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID		1
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
+#define ATMEL_HLCDC_LAYER_RGB			(0 << 0)
+#define ATMEL_HLCDC_LAYER_CLUT			(1 << 0)
+#define ATMEL_HLCDC_LAYER_YUV			(2 << 0)
+#define ATMEL_HLCDC_RGB_MODE(m)			(((m) & 0xf) << 4)
+#define ATMEL_HLCDC_CLUT_MODE(m)		(((m) & 0x3) << 8)
+#define ATMEL_HLCDC_YUV_MODE(m)			(((m) & 0xf) << 12)
+#define ATMEL_HLCDC_YUV422ROT			(1 << 16)
+#define ATMEL_HLCDC_YUV422SWP			(1 << 17)
+#define ATMEL_HLCDC_DSCALEOPT			(1 << 20)
+
+#define ATMEL_HLCDC_XRGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
+#define ATMEL_HLCDC_ARGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
+#define ATMEL_HLCDC_RGBA4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
+#define ATMEL_HLCDC_RGB565_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
+#define ATMEL_HLCDC_ARGB1555_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
+#define ATMEL_HLCDC_XRGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
+#define ATMEL_HLCDC_RGB888_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
+#define ATMEL_HLCDC_ARGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
+#define ATMEL_HLCDC_RGBA8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
+
+#define ATMEL_HLCDC_AYUV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
+#define ATMEL_HLCDC_YUYV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
+#define ATMEL_HLCDC_UYVY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
+#define ATMEL_HLCDC_YVYU_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
+#define ATMEL_HLCDC_VYUY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
+#define ATMEL_HLCDC_NV61_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
+#define ATMEL_HLCDC_YUV422_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
+#define ATMEL_HLCDC_NV21_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
+#define ATMEL_HLCDC_YUV420_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
+
+#define ATMEL_HLCDC_LAYER_POS_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
+#define ATMEL_HLCDC_LAYER_SIZE_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
+#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
+#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
+#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
+#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
+#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
+#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
+
+#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
+#define ATMEL_HLCDC_LAYER_CRKEY			BIT(0)
+#define ATMEL_HLCDC_LAYER_INV			BIT(1)
+#define ATMEL_HLCDC_LAYER_ITER2BL		BIT(2)
+#define ATMEL_HLCDC_LAYER_ITER			BIT(3)
+#define ATMEL_HLCDC_LAYER_REVALPHA		BIT(4)
+#define ATMEL_HLCDC_LAYER_GAEN			BIT(5)
+#define ATMEL_HLCDC_LAYER_LAEN			BIT(6)
+#define ATMEL_HLCDC_LAYER_OVR			BIT(7)
+#define ATMEL_HLCDC_LAYER_DMA			BIT(8)
+#define ATMEL_HLCDC_LAYER_REP			BIT(9)
+#define ATMEL_HLCDC_LAYER_DSTKEY		BIT(10)
+#define ATMEL_HLCDC_LAYER_GA_MASK		GENMASK(23, 16)
+#define ATMEL_HLCDC_LAYER_GA_SHIFT		16
+
+#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
+
+#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
+
+#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
+
+#define ATMEL_HLCDC_MAX_PLANES			3
+
+/**
+ * Atmel HLCDC Layer registers layout structure
+ *
+ * Each HLCDC layer has its own register organization and a given register
+ * by be placed differently on 2 different layers depending on its
+ * capabilities.
+ * This structure stores common registers layout for a given layer and is
+ * used by HLCDC layer code to chose the appropriate register to write to
+ * or to read from.
+ *
+ * For all fields, a value of zero means "unsupported".
+ *
+ * See Atmel's datasheet for a detailled description of these registers.
+ *
+ * @xstride: xstride registers
+ * @pstride: pstride registers
+ * @pos: position register
+ * @size: displayed size register
+ * @memsize: memory size register
+ * @default_color: default color register
+ * @chroma_key: chroma key register
+ * @chroma_key_mask: chroma key mask register
+ * @general_config: general layer config register
+ * @disc_pos: discard area position register
+ * @disc_size: discard area size register
+ * @csc: color space conversion register
+ */
+struct atmel_hlcdc_layer_cfg_layout {
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int pos;
+	int size;
+	int memsize;
+	int default_color;
+	int chroma_key;
+	int chroma_key_mask;
+	int general_config;
+	int disc_pos;
+	int disc_size;
+	int csc;
+};
+
+/**
+ * Atmel HLCDC GEM flip structure
+ *
+ * This structure is allocated when someone asked for a layer update (most
+ * likely a DRM plane update, either primary, overlay or cursor plane) and
+ * released when the layer do not need the reference GEM objects anymore
+ * (i.e. the layer was disabled or updated).
+ *
+ * @node: list element structure. Used to attach the GEM flip structure to
+ *	  the garbage collector when the layer no longer need the referenced
+ *	  GEM objects.
+ * @gems: the referenced GEM objects. The number of GEM object referenced
+ *	  depends on the chosen format.
+ * @remaining_gems: the number of GEM object still referenced by the layer.
+ *		    When no more objects are referenced the GEM flip structure
+ *		    is added to the garbage collector.
+ */
+struct atmel_hlcdc_layer_gem_flip {
+	struct list_head node;
+	struct drm_gem_object *gems[ATMEL_HLCDC_MAX_PLANES];
+	int remaining_gems;
+	void (*finished)(void *data);
+	void *finished_data;
+};
+
+/**
+ * Atmel HLCDC DMA descriptor structure
+ *
+ * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
+ *
+ * The structure fields must remain in this specific order, because they're
+ * used by the HLCDC DMA engine, which expect them in this order.
+ *
+ * @addr: buffer DMA address
+ * @ctrl: DMA transfer options
+ * @next: next DMA descriptor to fetch
+ * @gem_flip: the attached gem_flip operation
+ */
+struct atmel_hlcdc_dma_channel_dscr {
+	dma_addr_t addr;
+	u32 ctrl;
+	dma_addr_t next;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+} __aligned(sizeof(u64));
+
+/**
+ * Atmel HLCDC layer types
+ */
+enum atmel_hlcdc_layer_type {
+	ATMEL_HLCDC_BASE_LAYER,
+	ATMEL_HLCDC_OVERLAY_LAYER,
+	ATMEL_HLCDC_CURSOR_LAYER,
+	ATMEL_HLCDC_PP_LAYER,
+};
+
+/**
+ * Atmel HLCDC Supported formats structure
+ *
+ * This structure list all the formats supported by a given layer.
+ *
+ * @nformats: number of supported formats
+ * @formats: supported formats
+ */
+struct atmel_hlcdc_formats {
+	int nformats;
+	uint32_t *formats;
+};
+
+/**
+ * Atmel HLCDC Layer description structure
+ *
+ * This structure describe the capabilities provided by a given layer.
+ *
+ * @name: layer name
+ * @type: layer type
+ * @id: layer id
+ * @regs_offset: offset of the layer registers from the HLCDC registers base
+ * @nconfigs: number of config registers provided by this layer
+ * @layout: config registers layout
+ * @max_width: maximum width supported by this layer (0 means unlimited)
+ * @max_height: maximum height supported by this layer (0 means unlimited)
+ */
+struct atmel_hlcdc_layer_desc {
+	const char *name;
+	enum atmel_hlcdc_layer_type type;
+	int id;
+	int regs_offset;
+	int nconfigs;
+	struct atmel_hlcdc_formats *formats;
+	struct atmel_hlcdc_layer_cfg_layout layout;
+	int max_width;
+	int max_height;
+};
+
+/**
+ * Atmel HLCDC Layer Update Slot structure
+ *
+ * This structure stores layer update requests to be applied on next frame.
+ * This is the base structure behind the atomic layer update infrastructure.
+ *
+ * Atomic layer update provides a way to update all layer's parameters
+ * simultaneously. This is needed to avoid incompatible sequential updates
+ * like this one:
+ * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
+ *    (2 planes/buffers)
+ * 2) the format update is applied but the DMA channel for the second
+ *    plane/buffer is not enabled
+ * 3) enable the DMA channel for the second plane
+ *
+ *@dscrs: DMA channel descriptors
+ *@gem_flip: gem_flip object
+ *@updated_configs: bitmask used to record modified configs
+ *@configs: new config values
+ */
+struct atmel_hlcdc_layer_update_slot {
+	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	unsigned long *updated_configs;
+	u32 *configs;
+};
+
+/**
+ * Atmel HLCDC Layer Update structure
+ *
+ * This structure provides a way to queue layer update requests.
+ *
+ * At a given time there is at most:
+ *  - one pending update request, which means the update request has been
+ *    commited (or validated) and is waiting for the DMA channel(s) to be
+ *    available
+ *  - one request being prepared, which means someone started a layer update
+ *    but has not commited it yet. There cannot be more than one started
+ *    request, because the update lock is taken when starting a layer update
+ *    and release when commiting or rolling back the request.
+ *
+ *@slots: update slots. One is used for pending request and the other one
+ *	  for started update request
+ *@pending: the pending slot index or -1 if no request is pending
+ *@next: the started update slot index or -1 no update has been started
+ *@pending_lock: lock to access the pending field
+ *@lock: layer update lock
+ */
+struct atmel_hlcdc_layer_update {
+	struct atmel_hlcdc_layer_update_slot slots[2];
+	int pending;
+	int next;
+	spinlock_t pending_lock;
+	struct mutex lock;
+};
+
+/**
+ * Atmel HLCDC Layer GEM flip garbage collector structure
+ *
+ * This structure is used to schedule GEM object release when we are in
+ * interrupt context (within atmel_hlcdc_layer_irq function).
+ *
+ *@list: GEM flip objects to release
+ *@list_lock: lock to access the GEM flip list
+ *@work: work queue scheduled when there are GEM flip to collect
+ *@finished: action to execute the GEM flip and all attached objects have been
+ *	     released
+ *@finished_data: data passed to the finished callback
+ *@finished_lock: lock to access finished related fields
+ */
+struct atmel_hlcdc_layer_gem_flip_gc {
+	struct list_head list;
+	spinlock_t list_lock;
+	struct work_struct work;
+};
+
+/**
+ * Atmel HLCDC Layer DMA channel structure
+ *
+ * This structure stores informations on the DMA channel associated to a
+ * given layer.
+ *
+ *@enabled: DMA channel status
+ *@lock: lock to access the DMA channel fields
+ *@cur: current DMA transfers (one for each plane/buffer)
+ *@queue: next DMA transfers, to be launch on next frame update
+ *@dscrs: allocated DMA descriptors
+ */
+struct atmel_hlcdc_layer_dma_channel {
+	bool enabled;
+	spinlock_t lock;
+	struct atmel_hlcdc_dma_channel_dscr *cur[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_dma_channel_dscr *queue[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_dma_channel_dscr *dscrs;
+};
+
+/**
+ * Atmel HLCDC Layer structure
+ *
+ * This structure stores information on the layer instance.
+ *
+ *@desc: layer description
+ *@max_planes: maximum planes/buffers that can be associated with this layer.
+ *	       This depends on the supported formats.
+ *@hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ *@dma: dma channel
+ *@gc: GEM flip garbage collector
+ *@update: update handler
+ */
+struct atmel_hlcdc_layer {
+	const struct atmel_hlcdc_layer_desc *desc;
+	int max_planes;
+	struct atmel_hlcdc *hlcdc;
+	struct atmel_hlcdc_layer_dma_channel dma;
+	struct atmel_hlcdc_layer_gem_flip_gc gc;
+	struct atmel_hlcdc_layer_update update;
+};
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc);
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_set_finished(struct atmel_hlcdc_layer *layer,
+				    void (*finished)(void *data),
+				    void *data);
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val);
+
+void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
+				      int plane_id,
+				      struct drm_gem_cma_object *gem,
+				      unsigned int offset);
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+					   void (*finished)(void *data),
+					   void *finished_data);
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
+
+static inline bool
+atmel_hlcdc_layer_dma_channel_busy(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (dma->queue[i])
+			return true;
+	}
+
+	return false;
+}
+
+#endif /* DRM_ATMEL_HLCDC_LAYER_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
new file mode 100644
index 0000000..3295021
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC RGB output mode
+ */
+enum atmel_hlcdc_connector_rgb_mode {
+	ATMEL_HLCDC_CONNECTOR_RGB444,
+	ATMEL_HLCDC_CONNECTOR_RGB565,
+	ATMEL_HLCDC_CONNECTOR_RGB666,
+	ATMEL_HLCDC_CONNECTOR_RGB888,
+};
+
+/**
+ * Atmel HLCDC Panel structure
+ *
+ * This structure stores informations about an DRM panel connected through
+ * the RGB connector.
+ *
+ * @mode: RGB output mode
+ * @connector: DRM connector
+ * @encoder: DRM encoder
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @panel: pointer to the attached DRM panel
+ * @pinctrl: pinctrl state used by the current RGB output mode
+ * @np: DRM panel DT node
+ * @dpms: current DPMS mode
+ */
+struct atmel_hlcdc_panel {
+	enum atmel_hlcdc_connector_rgb_mode mode;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_panel *panel;
+	struct pinctrl *pinctrl;
+	struct device_node *np;
+	int dpms;
+};
+
+static const char * const pin_state_names[] = {
+	[ATMEL_HLCDC_CONNECTOR_RGB444] = "rgb-444",
+	[ATMEL_HLCDC_CONNECTOR_RGB565] = "rgb-565",
+	[ATMEL_HLCDC_CONNECTOR_RGB666] = "rgb-666",
+	[ATMEL_HLCDC_CONNECTOR_RGB888] = "rgb-888",
+};
+
+static inline struct atmel_hlcdc_panel *
+drm_connector_to_atmel_hlcdc_panel(struct drm_connector *connector)
+{
+	return container_of(connector, struct atmel_hlcdc_panel, connector);
+}
+
+static inline struct atmel_hlcdc_panel *
+drm_encoder_to_atmel_hlcdc_panel(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct atmel_hlcdc_panel, encoder);
+}
+
+static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
+					   int mode)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_encoder_to_atmel_hlcdc_panel(encoder);
+	struct regmap *regmap = panel->hlcdc->regmap;
+	unsigned int status;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	if (mode == panel->dpms)
+		return;
+
+	if (mode != DRM_MODE_DPMS_ON) {
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+		clk_disable_unprepare(panel->hlcdc->sys_clk);
+		if (panel->panel)
+			drm_panel_disable(panel->panel);
+	} else {
+		if (panel->panel)
+			drm_panel_enable(panel->panel);
+		clk_prepare_enable(panel->hlcdc->sys_clk);
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+	}
+
+	panel->dpms = mode;
+}
+
+static bool
+atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
+				     const struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted)
+{
+	return true;
+}
+
+static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void
+atmel_hlcdc_panel_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_encoder_to_atmel_hlcdc_panel(encoder);
+	unsigned long prate = clk_get_rate(panel->hlcdc->sys_clk);
+	unsigned long mode_rate = mode->clock * 1000;
+	int div;
+	u32 cfg0 = 0;
+
+	if ((prate / 2) < mode_rate) {
+		prate *= 2;
+		cfg0 |= ATMEL_HLCDC_CLKSEL;
+	}
+
+	div = DIV_ROUND_UP(prate, mode_rate);
+	if (div < 2)
+		div = 2;
+
+	cfg0 |= ATMEL_HLCDC_CLKDIV(div);
+
+	regmap_update_bits(panel->hlcdc->regmap, ATMEL_HLCDC_CFG(0),
+			   ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK, cfg0);
+}
+
+static struct drm_encoder_helper_funcs encoder_helper_funcs = {
+	.dpms = atmel_hlcdc_panel_encoder_dpms,
+	.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
+	.prepare = atmel_hlcdc_panel_encoder_prepare,
+	.commit = atmel_hlcdc_panel_encoder_commit,
+	.mode_set = atmel_hlcdc_panel_encoder_mode_set,
+};
+
+static void atmel_hlcdc_panel_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+	memset(encoder, 0, sizeof(*encoder));
+}
+
+static const struct drm_encoder_funcs encoder_funcs = {
+	.destroy = atmel_hlcdc_panel_encoder_destroy,
+};
+
+static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+	int ret;
+
+	if (!panel->panel)
+		return -ENOENT;
+
+	ret = panel->panel->funcs->get_modes(panel->panel);
+	return ret;
+}
+
+static int atmel_hlcdc_panel_mode_valid(struct drm_connector *connector,
+					struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+atmel_hlcdc_panel_best_encoder(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	return &panel->encoder;
+}
+
+static struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = atmel_hlcdc_panel_get_modes,
+	.mode_valid = atmel_hlcdc_panel_mode_valid,
+	.best_encoder = atmel_hlcdc_panel_best_encoder,
+};
+
+static enum drm_connector_status
+atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	if (!panel->panel) {
+		panel->panel = of_drm_find_panel(panel->np);
+		if (panel->panel)
+			drm_panel_attach(panel->panel, &panel->connector);
+	}
+
+	if (panel->panel)
+		return connector_status_connected;
+
+	return connector_status_disconnected;
+}
+
+static void
+atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	if (panel->panel)
+		drm_panel_detach(panel->panel);
+
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+
+	pinctrl_put(panel->pinctrl);
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = atmel_hlcdc_panel_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = atmel_hlcdc_panel_connector_destroy,
+};
+
+int atmel_hlcdc_panel_create(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_panel *panel;
+	struct of_phandle_args out_args;
+	u32 cfg;
+	int ret;
+
+	panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
+	if (!panel)
+		return -ENOMEM;
+
+	ret = of_parse_phandle_with_fixed_args(dev->dev->of_node,
+					       "atmel,panel", 2, 0,
+					       &out_args);
+	if (ret) {
+		dev_err(dev->dev, "failed to retrieve panel info from DT\n");
+		return ret;
+	}
+
+	switch (out_args.args[0]) {
+	case ATMEL_HLCDC_CONNECTOR_RGB444:
+	case ATMEL_HLCDC_CONNECTOR_RGB565:
+	case ATMEL_HLCDC_CONNECTOR_RGB666:
+	case ATMEL_HLCDC_CONNECTOR_RGB888:
+		break;
+	default:
+		dev_err(dev->dev, "unknown RGB mode\n");
+		return -EINVAL;
+	}
+
+	panel->np = out_args.np;
+	panel->mode = out_args.args[0];
+	panel->pinctrl = pinctrl_get_select(dev->dev,
+					    pin_state_names[panel->mode]);
+	if (IS_ERR(panel->pinctrl)) {
+		dev_err(dev->dev, "could not request pinctrl state\n");
+		return PTR_ERR(panel->pinctrl);
+	}
+
+	cfg = out_args.args[1] & (ATMEL_HLCDC_HSPOL |
+				  ATMEL_HLCDC_VSPOL |
+				  ATMEL_HLCDC_VSPDLYS |
+				  ATMEL_HLCDC_VSPDLYE |
+				  ATMEL_HLCDC_DISPPOL |
+				  ATMEL_HLCDC_DISPDLY |
+				  ATMEL_HLCDC_VSPSU |
+				  ATMEL_HLCDC_VSPHO);
+	cfg |= panel->mode << 8;
+
+	regmap_write(dc->hlcdc->regmap,
+		     ATMEL_HLCDC_CFG(5),
+		     cfg);
+
+	panel->dpms = DRM_MODE_DPMS_OFF;
+
+	panel->hlcdc = dc->hlcdc;
+
+	drm_connector_init(dev, &panel->connector, &connector_funcs,
+			   DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(&panel->connector, &connector_helper_funcs);
+	panel->connector.dpms = DRM_MODE_DPMS_OFF;
+	panel->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+
+	drm_encoder_init(dev, &panel->encoder, &encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS);
+	drm_encoder_helper_add(&panel->encoder, &encoder_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&panel->connector, &panel->encoder);
+	drm_sysfs_connector_add(&panel->connector);
+
+	panel->encoder.possible_crtcs = 0x1;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
new file mode 100644
index 0000000..0c7469b
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "atmel_hlcdc_dc.h"
+
+#define SUBPIXEL_MASK			0xffff
+
+static uint32_t rgb_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
+	.formats = rgb_formats,
+	.nformats = ARRAY_SIZE(rgb_formats),
+};
+
+static uint32_t rgb_and_yuv_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_AYUV,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YUV420,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
+	.formats = rgb_and_yuv_formats,
+	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
+};
+
+static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB4444:
+		*mode = ATMEL_HLCDC_XRGB4444_MODE;
+		break;
+	case DRM_FORMAT_ARGB4444:
+		*mode = ATMEL_HLCDC_ARGB4444_MODE;
+		break;
+	case DRM_FORMAT_RGBA4444:
+		*mode = ATMEL_HLCDC_RGBA4444_MODE;
+		break;
+	case DRM_FORMAT_RGB565:
+		*mode = ATMEL_HLCDC_RGB565_MODE;
+		break;
+	case DRM_FORMAT_RGB888:
+		*mode = ATMEL_HLCDC_RGB888_MODE;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		*mode = ATMEL_HLCDC_ARGB1555_MODE;
+		break;
+	case DRM_FORMAT_XRGB8888:
+		*mode = ATMEL_HLCDC_XRGB8888_MODE;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		*mode = ATMEL_HLCDC_ARGB8888_MODE;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		*mode = ATMEL_HLCDC_RGBA8888_MODE;
+		break;
+	case DRM_FORMAT_AYUV:
+		*mode = ATMEL_HLCDC_AYUV_MODE;
+		break;
+	case DRM_FORMAT_YUYV:
+		*mode = ATMEL_HLCDC_YUYV_MODE;
+		break;
+	case DRM_FORMAT_UYVY:
+		*mode = ATMEL_HLCDC_UYVY_MODE;
+		break;
+	case DRM_FORMAT_YVYU:
+		*mode = ATMEL_HLCDC_YVYU_MODE;
+		break;
+	case DRM_FORMAT_VYUY:
+		*mode = ATMEL_HLCDC_VYUY_MODE;
+		break;
+	case DRM_FORMAT_NV21:
+		*mode = ATMEL_HLCDC_NV21_MODE;
+		break;
+	case DRM_FORMAT_NV61:
+		*mode = ATMEL_HLCDC_NV61_MODE;
+		break;
+	case DRM_FORMAT_YUV420:
+		*mode = ATMEL_HLCDC_YUV420_MODE;
+		break;
+	case DRM_FORMAT_YUV422:
+		*mode = ATMEL_HLCDC_YUV422_MODE;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static bool atmel_hlcdc_format_embedds_alpha(u32 format)
+{
+	int i;
+
+	for (i = 0; i < sizeof(format); i++) {
+		char tmp = (format >> (8 * i)) & 0xff;
+
+		if (tmp == 'A')
+			return true;
+	}
+
+	return false;
+}
+
+static u32 heo_downscaling_xcoef[] = {
+	0x11343311,
+	0x000000f7,
+	0x1635300c,
+	0x000000f9,
+	0x1b362c08,
+	0x000000fb,
+	0x1f372804,
+	0x000000fe,
+	0x24382400,
+	0x00000000,
+	0x28371ffe,
+	0x00000004,
+	0x2c361bfb,
+	0x00000008,
+	0x303516f9,
+	0x0000000c,
+};
+
+static u32 heo_downscaling_ycoef[] = {
+	0x00123737,
+	0x00173732,
+	0x001b382d,
+	0x001f3928,
+	0x00243824,
+	0x0028391f,
+	0x002d381b,
+	0x00323717,
+};
+
+static u32 heo_upscaling_xcoef[] = {
+	0xf74949f7,
+	0x00000000,
+	0xf55f33fb,
+	0x000000fe,
+	0xf5701efe,
+	0x000000ff,
+	0xf87c0dff,
+	0x00000000,
+	0x00800000,
+	0x00000000,
+	0x0d7cf800,
+	0x000000ff,
+	0x1e70f5ff,
+	0x000000fe,
+	0x335ff5fe,
+	0x000000fb,
+};
+
+static u32 heo_upscaling_ycoef[] = {
+	0x00004040,
+	0x00075920,
+	0x00056f0c,
+	0x00027b03,
+	0x00008000,
+	0x00037b02,
+	0x000c6f05,
+	0x00205907,
+};
+
+static void
+atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (layout->size)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->size,
+					     0xffffffff,
+					     (req->crtc_w - 1) |
+					     ((req->crtc_h - 1) << 16));
+
+	if (layout->memsize)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->memsize,
+					     0xffffffff,
+					     (req->src_w - 1) |
+					     ((req->src_h - 1) << 16));
+
+	if (layout->pos)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->pos,
+					     0xffffffff,
+					     req->crtc_x |
+					     (req->crtc_y  << 16));
+
+	/* TODO: rework the rescaling part */
+	if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
+		u32 factor_reg = 0;
+
+		if (req->crtc_w != req->src_w) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_xcoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_xcoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     17 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= factor | 0x80000000;
+		}
+
+		if (req->crtc_h != req->src_h) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_ycoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_ycoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     33 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= (factor << 16) | 0x80000000;
+		}
+
+		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
+					     factor_reg);
+	}
+}
+
+static void
+atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
+
+	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
+		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
+		       ATMEL_HLCDC_LAYER_ITER;
+
+		if (atmel_hlcdc_format_embedds_alpha(req->pixel_format))
+			cfg |= ATMEL_HLCDC_LAYER_LAEN;
+		else
+			cfg |= ATMEL_HLCDC_LAYER_GAEN;
+	}
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
+				     ATMEL_HLCDC_LAYER_ITER2BL |
+				     ATMEL_HLCDC_LAYER_ITER |
+				     ATMEL_HLCDC_LAYER_GAEN |
+				     ATMEL_HLCDC_LAYER_LAEN |
+				     ATMEL_HLCDC_LAYER_OVR |
+				     ATMEL_HLCDC_LAYER_DMA, cfg);
+}
+
+static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	u32 mode;
+	int ret;
+
+	ret = atmel_hlcdc_format_to_plane_mode(req->pixel_format, &mode);
+	if (ret)
+		return;
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
+				     0xffffffff,
+				     mode);
+}
+
+static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_layer *layer = &plane->layer;
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+							&layer->desc->layout;
+	int i;
+
+	for (i = 0; i < req->nplanes; i++) {
+		atmel_hlcdc_layer_update_set_gem(&plane->layer, i,
+						 req->gems[i],
+						 req->offsets[i]);
+		if (layout->xstride[i])
+			atmel_hlcdc_layer_update_cfg(&plane->layer,
+						layout->xstride[i],
+						0xffffffff,
+						req->pitches[i] -
+						(req->bpp[i] * req->src_w));
+	}
+}
+
+static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (!layout->size &&
+	    (req->crtc->mode.crtc_hdisplay != req->crtc_w ||
+	     req->crtc->mode.crtc_vdisplay != req->crtc_h))
+		return -EINVAL;
+
+	if (plane->layer.desc->max_height &&
+	    req->crtc_h > plane->layer.desc->max_height)
+		return -EINVAL;
+
+	if (plane->layer.desc->max_width &&
+	    req->crtc_w > plane->layer.desc->max_width)
+		return -EINVAL;
+
+	if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
+	    (!layout->memsize ||
+	     atmel_hlcdc_format_embedds_alpha(req->pixel_format)))
+		return -EINVAL;
+
+	return 0;
+}
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	unsigned int patched_crtc_w;
+	unsigned int patched_crtc_h;
+	int x_offset = 0;
+	int y_offset = 0;
+	int i;
+
+	if ((req->src_x | req->src_y | req->src_w | req->src_h) &
+	    SUBPIXEL_MASK)
+		return -EINVAL;
+
+	req->src_x >>= 16;
+	req->src_y >>= 16;
+	req->src_w >>= 16;
+	req->src_h >>= 16;
+
+	req->nplanes = drm_format_num_planes(req->pixel_format);
+	if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
+		return -EINVAL;
+
+	if (req->crtc_x + req->crtc_w > req->crtc->mode.hdisplay)
+		patched_crtc_w = req->crtc->mode.hdisplay - req->crtc_x;
+	else
+		patched_crtc_w = req->crtc_w;
+
+	if (req->crtc_x < 0) {
+		patched_crtc_w += req->crtc_x;
+		x_offset = -req->crtc_x;
+		req->crtc_x = 0;
+	}
+
+	if (req->crtc_y + req->crtc_h > req->crtc->mode.vdisplay)
+		patched_crtc_h = req->crtc->mode.vdisplay - req->crtc_y;
+	else
+		patched_crtc_h = req->crtc_h;
+
+	if (req->crtc_y < 0) {
+		patched_crtc_h += req->crtc_y;
+		y_offset = -req->crtc_y;
+		req->crtc_y = 0;
+	}
+
+	req->src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
+				       req->crtc_w);
+	req->src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
+				       req->crtc_h);
+	req->crtc_w = patched_crtc_w;
+	req->crtc_h = patched_crtc_h;
+
+	for (i = 0; i < req->nplanes; i++) {
+		req->bpp[i] = drm_format_plane_cpp(req->pixel_format, i);
+		if (!req->bpp[i])
+			return -EINVAL;
+
+		req->offsets[i] += (x_offset + (y_offset * patched_crtc_w)) *
+				   req->bpp[i];
+	}
+
+	return atmel_hlcdc_plane_check_update_req(p, req);
+}
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	int ret;
+
+	ret = atmel_hlcdc_layer_update_start(&plane->layer);
+	if (ret)
+		return ret;
+
+	atmel_hlcdc_plane_update_pos_and_size(plane, req);
+	atmel_hlcdc_plane_update_general_settings(plane, req);
+	atmel_hlcdc_plane_update_format(plane, req);
+	atmel_hlcdc_plane_update_buffers(plane, req);
+	atmel_hlcdc_layer_update_set_finished(&plane->layer, req->finished,
+					      req->finished_data);
+
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_update(struct drm_plane *p,
+				    struct drm_crtc *crtc,
+				    struct drm_framebuffer *fb,
+				    int crtc_x, int crtc_y,
+				    unsigned int crtc_w, unsigned int crtc_h,
+				    uint32_t src_x, uint32_t src_y,
+				    uint32_t src_w, uint32_t src_h)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_update_req req;
+	int ret = 0;
+	int i;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = crtc_x;
+	req.crtc_y = crtc_y;
+	req.crtc_w = crtc_w;
+	req.crtc_h = crtc_h;
+	req.src_x = src_x;
+	req.src_y = src_y;
+	req.src_w = src_w;
+	req.src_h = src_h;
+	req.pixel_format = fb->pixel_format;
+	req.crtc = crtc;
+
+	for (i = 0; i < plane->layer.max_planes; i++) {
+		req.offsets[i] = fb->offsets[i];
+		req.pitches[i] = fb->pitches[i];
+		req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		return ret;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		return ret;
+
+	drm_framebuffer_reference(fb);
+	if (plane->base.fb)
+		drm_framebuffer_unreference(plane->base.fb);
+	plane->base.fb = fb;
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_disable(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	return atmel_hlcdc_layer_disable(&plane->layer);
+}
+
+static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	if (plane->base.fb)
+		drm_framebuffer_unreference(plane->base.fb);
+
+	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
+
+	drm_plane_cleanup(p);
+	devm_kfree(p->dev->dev, plane);
+}
+
+static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
+				       u8 alpha)
+{
+	atmel_hlcdc_layer_update_start(&plane->layer);
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     plane->layer.desc->layout.general_config,
+				     ATMEL_HLCDC_LAYER_GA_MASK,
+				     alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
+					  struct drm_property *property,
+					  uint64_t value)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_properties *props = plane->properties;
+
+	if (property == props->alpha)
+		atmel_hlcdc_plane_set_alpha(plane, value);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
+				const struct atmel_hlcdc_layer_desc *desc,
+				struct atmel_hlcdc_plane_properties *props)
+{
+	struct regmap *regmap = plane->layer.hlcdc->regmap;
+
+	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
+	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
+		drm_object_attach_property(&plane->base.base,
+					   props->alpha, 255);
+
+		/* Set default alpha value */
+		regmap_update_bits(regmap,
+				desc->regs_offset +
+				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
+				ATMEL_HLCDC_LAYER_GA_MASK,
+				ATMEL_HLCDC_LAYER_GA_MASK);
+	}
+
+	if (desc->layout.csc) {
+		/*
+		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
+		 * userspace modify these factors (using a BLOB property ?).
+		 */
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
+			     0x4c900091);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
+			     0x7a5f5090);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
+			     0x40040890);
+	}
+}
+
+static struct drm_plane_funcs layer_plane_funcs = {
+	.update_plane = atmel_hlcdc_plane_update,
+	.disable_plane = atmel_hlcdc_plane_disable,
+	.set_property = atmel_hlcdc_plane_set_property,
+	.destroy = atmel_hlcdc_plane_destroy,
+};
+
+static struct atmel_hlcdc_plane *
+atmel_hlcdc_plane_create(struct drm_device *dev,
+			 const struct atmel_hlcdc_layer_desc *desc,
+			 struct atmel_hlcdc_plane_properties *props)
+{
+	struct atmel_hlcdc_plane *plane;
+	enum drm_plane_type type;
+	int ret;
+
+	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+	if (!plane)
+		return ERR_PTR(-ENOMEM);
+
+	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
+		type = DRM_PLANE_TYPE_PRIMARY;
+	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
+		type = DRM_PLANE_TYPE_CURSOR;
+	else
+		type = DRM_PLANE_TYPE_OVERLAY;
+
+	ret = drm_universal_plane_init(dev, &plane->base, 0,
+				       &layer_plane_funcs,
+				       desc->formats->formats,
+				       desc->formats->nformats, type);
+	if (ret)
+		return ERR_PTR(ret);
+
+	/* Set default property values*/
+	atmel_hlcdc_plane_init_properties(plane, desc, props);
+
+	return plane;
+}
+
+static struct atmel_hlcdc_plane_properties *
+atmel_hlcdc_plane_create_properties(struct drm_device *dev)
+{
+	struct atmel_hlcdc_plane_properties *props;
+
+	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
+	if (!props)
+		return ERR_PTR(-ENOMEM);
+
+	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
+	if (!props->alpha)
+		return ERR_PTR(-ENOMEM);
+
+	return props;
+}
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_plane_properties *props;
+	struct atmel_hlcdc_planes *planes;
+	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
+	int nlayers = dc->desc->nlayers;
+	int i;
+
+	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
+	if (!planes)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < nlayers; i++) {
+		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
+			planes->noverlays++;
+	}
+
+	if (planes->noverlays) {
+		planes->overlays = devm_kzalloc(dev->dev,
+						planes->noverlays *
+						sizeof(*planes->overlays),
+						GFP_KERNEL);
+		if (!planes->overlays)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	props = atmel_hlcdc_plane_create_properties(dev);
+	if (IS_ERR(props))
+		return ERR_CAST(props);
+
+	planes->noverlays = 0;
+	for (i = 0; i < nlayers; i++) {
+		struct atmel_hlcdc_plane *plane;
+
+		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
+			continue;
+
+		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
+		if (IS_ERR(plane))
+			return ERR_CAST(plane);
+
+		plane->properties = props;
+
+		switch (descs[i].type) {
+		case ATMEL_HLCDC_BASE_LAYER:
+			if (planes->primary)
+				return ERR_PTR(-EINVAL);
+			planes->primary = plane;
+			break;
+
+		case ATMEL_HLCDC_OVERLAY_LAYER:
+			planes->overlays[planes->noverlays++] = plane;
+			break;
+
+		case ATMEL_HLCDC_CURSOR_LAYER:
+			if (planes->cursor)
+				return ERR_PTR(-EINVAL);
+			planes->cursor = plane;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return planes;
+}
-- 
1.8.3.2


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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
controller device.

This display controller supports at least one primary plane and might
provide several overlays and an hardware cursor depending on the IP
version.

At the moment, this driver only implements an RGB connector to interface
with LCD panels, but support for other kind of external devices (like DRM
bridges) might be added later.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/Kconfig                         |   2 +
 drivers/gpu/drm/Makefile                        |   1 +
 drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
 drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
 11 files changed, 3382 insertions(+)
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
 create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index d1cc2f6..df6f0c1 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
 
 source "drivers/gpu/drm/armada/Kconfig"
 
+source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
+
 source "drivers/gpu/drm/rcar-du/Kconfig"
 
 source "drivers/gpu/drm/shmobile/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 48e38ba..28c8a61 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 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_OMAP)	+= omapdrm/
diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig
new file mode 100644
index 0000000..bc07315
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig
@@ -0,0 +1,11 @@
+config DRM_ATMEL_HLCDC
+	tristate "DRM Support for ATMEL HLCDC Display Controller"
+	depends on DRM && OF && MFD_ATMEL_HLCDC && COMMON_CLK
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this option if you have an ATMEL SoC with an HLCDC display
+	  controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile
new file mode 100644
index 0000000..bf9fe0b
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
@@ -0,0 +1,7 @@
+atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
+		atmel_hlcdc_dc.o \
+		atmel_hlcdc_layer.o \
+		atmel_hlcdc_panel.o \
+		atmel_hlcdc_plane.o
+
+obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc-dc.o
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
new file mode 100644
index 0000000..8b11af8
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Structure storing HW cursor status.
+ *
+ * @status: the current cursor status
+ * @req: the requested cursor changes
+ * @plane: the hardware cursor plane
+ * @lock: cursor lock held when modifying cursor req or status
+ */
+struct atmel_hlcdc_crtc_cursor {
+	struct atmel_hlcdc_plane *plane;
+	struct drm_gem_cma_object *gem;
+	u32 height;
+	u32 width;
+	int x;
+	int y;
+	struct mutex lock;
+};
+
+/**
+ * Atmel HLCDC CRTC structure
+ *
+ * @base: base DRM CRTC structure
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @event: pointer to the current page flip event
+ * @id: CRTC id (returned by drm_crtc_index)
+ * @dpms: DPMS mode
+ * @cursor: hardware cursor status
+ */
+struct atmel_hlcdc_crtc {
+	struct drm_crtc base;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_pending_vblank_event *event;
+	int id;
+	int dpms;
+	struct atmel_hlcdc_crtc_cursor cursor;
+};
+
+static inline struct atmel_hlcdc_crtc *
+drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct atmel_hlcdc_crtc, base);
+}
+
+
+static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
+{
+	struct drm_device *dev = c->dev;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	pm_runtime_get_sync(dev->dev);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		pm_runtime_forbid(dev->dev);
+	else
+		pm_runtime_allow(dev->dev);
+
+	pm_runtime_put_sync(dev->dev);
+}
+
+static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted,
+				     int x, int y,
+				     struct drm_framebuffer *old_fb)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct regmap *regmap = crtc->hlcdc->regmap;
+	struct drm_plane *plane = c->primary;
+	struct drm_framebuffer *fb;
+	struct videomode vm;
+
+	vm.vfront_porch = mode->vsync_start - mode->vdisplay;
+	vm.vback_porch = mode->vtotal - mode->vsync_end;
+	vm.vsync_len = mode->vsync_end - mode->vsync_start;
+	vm.hfront_porch = mode->hsync_start - mode->hdisplay;
+	vm.hback_porch = mode->htotal - mode->hsync_end;
+	vm.hsync_len = mode->hsync_end - mode->hsync_start;
+
+	if (vm.hsync_len > 0x40 || vm.hsync_len < 1 ||
+	    vm.vsync_len > 0x40 || vm.vsync_len < 1 ||
+	    vm.vfront_porch > 0x40 || vm.vfront_porch < 1 ||
+	    vm.vback_porch > 0x40 || vm.vback_porch < 0 ||
+	    vm.hfront_porch > 0x200 || vm.hfront_porch < 1 ||
+	    vm.hback_porch > 0x200 || vm.hback_porch < 1 ||
+	    mode->hdisplay > 2048 || mode->hdisplay < 1 ||
+	    mode->vdisplay > 2048 || mode->vdisplay < 1)
+		return -EINVAL;
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(1),
+		     (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(2),
+		     (vm.vfront_porch - 1) | (vm.vback_porch << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(3),
+		     (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(4),
+		     (mode->hdisplay - 1) | ((mode->vdisplay - 1) << 16));
+
+	fb = plane->fb;
+	plane->fb = old_fb;
+
+	return plane->funcs->update_plane(plane, c, fb,
+					  0, 0,
+					  mode->hdisplay, mode->vdisplay,
+					  c->x << 16, c->y << 16,
+					  mode->hdisplay << 16,
+					  mode->vdisplay << 16);
+}
+
+static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
+					const struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+
+static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
+
+	.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
+	.dpms = atmel_hlcdc_crtc_dpms,
+	.mode_set = atmel_hlcdc_crtc_mode_set,
+	.prepare = atmel_hlcdc_crtc_prepare,
+	.commit = atmel_hlcdc_crtc_commit,
+};
+
+static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+	drm_crtc_cleanup(c);
+	kfree(crtc);
+}
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
+				       struct drm_file *file)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct drm_pending_vblank_event *event;
+	struct drm_device *dev = c->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = crtc->event;
+	if (event && event->base.file_priv == file) {
+		event->base.destroy(&event->base);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void atmel_hlcdc_crtc_finish_page_flip(void *data)
+{
+	struct atmel_hlcdc_crtc *crtc = data;
+	struct drm_device *dev = crtc->base.dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (crtc->event) {
+		drm_send_vblank_event(dev, crtc->id, crtc->event);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
+				      struct drm_framebuffer *fb,
+				      struct drm_pending_vblank_event *event,
+				      uint32_t page_flip_flags)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane_update_req req;
+	struct drm_plane *plane = c->primary;
+	int ret;
+	int i;
+
+	if (crtc->event)
+		return -EBUSY;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = 0;
+	req.crtc_y = 0;
+	req.crtc_h = c->mode.crtc_vdisplay;
+	req.crtc_w = c->mode.crtc_hdisplay;
+	req.src_x = c->x << 16;
+	req.src_y = c->y << 16;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = fb->pixel_format;
+
+	for (i = 0; i < ATMEL_HLCDC_MAX_PLANES; i++) {
+		req.offsets[i] = fb->offsets[i];
+		req.pitches[i] = fb->pitches[i];
+		req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
+	}
+
+	req.crtc = c;
+	req.finished = atmel_hlcdc_crtc_finish_page_flip;
+	req.finished_data = crtc;
+
+	ret = atmel_hlcdc_plane_prepare_update_req(plane, &req);
+	if (ret)
+		return ret;
+
+	if (event) {
+		crtc->event = event;
+		drm_vblank_get(c->dev, crtc->id);
+	}
+
+	ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
+
+	if (ret) {
+		crtc->event = NULL;
+		drm_vblank_put(c->dev, crtc->id);
+	} else {
+		drm_framebuffer_reference(fb);
+		if (plane->fb)
+			drm_framebuffer_unreference(plane->fb);
+		plane->fb = fb;
+	}
+
+	return ret;
+}
+
+static int atmel_hlcdc_crtc_cursor_set(struct drm_crtc *c,
+				       struct drm_file *file_priv,
+				       uint32_t handle,
+				       uint32_t width, uint32_t height)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
+	struct drm_gem_cma_object *cma_gem = NULL;
+	struct atmel_hlcdc_plane_update_req req;
+	int ret;
+
+	if (unlikely(!plane))
+		return -ENOTSUPP;
+
+	mutex_lock(&crtc->cursor.lock);
+
+	if (handle) {
+		struct drm_gem_object *gem;
+
+		gem = drm_gem_object_lookup(c->dev, file_priv, handle);
+		if (unlikely(!gem)) {
+			ret = -ENOENT;
+			goto out;
+		}
+
+		cma_gem = to_drm_gem_cma_obj(gem);
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = crtc->cursor.x;
+	req.crtc_y = crtc->cursor.y;
+	req.crtc_h = height;
+	req.crtc_w = width;
+	req.src_x = 0;
+	req.src_y = 0;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = DRM_FORMAT_ARGB8888;
+	req.gems[0] = cma_gem;
+	req.offsets[0] = 0;
+	req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) * width;
+	req.crtc = c;
+
+	if (!req.gems[0] || !req.src_h || !req.src_w) {
+		cma_gem = crtc->cursor.gem;
+		ret = plane->base.funcs->disable_plane(&plane->base);
+		if (!ret && cma_gem) {
+			drm_gem_object_unreference_unlocked(&cma_gem->base);
+			crtc->cursor.gem = NULL;
+		}
+
+		goto out;
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		goto err_release_gem;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		goto err_release_gem;
+
+	crtc->cursor.height = width;
+	crtc->cursor.width = width;
+	if (crtc->cursor.gem)
+		drm_gem_object_unreference_unlocked(&crtc->cursor.gem->base);
+	crtc->cursor.gem = cma_gem;
+
+	goto out;
+
+err_release_gem:
+	if (cma_gem)
+		drm_gem_object_unreference_unlocked(&cma_gem->base);
+
+out:
+	mutex_unlock(&crtc->cursor.lock);
+	return ret;
+}
+
+static int atmel_hlcdc_crtc_cursor_move(struct drm_crtc *c, int x, int y)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
+	struct atmel_hlcdc_plane_update_req req;
+	int ret;
+
+	if (unlikely(!plane))
+		return -ENOTSUPP;
+
+	mutex_lock(&crtc->cursor.lock);
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = x;
+	req.crtc_y = y;
+	req.crtc_h = crtc->cursor.height;
+	req.crtc_w = crtc->cursor.width;
+	req.src_x = 0;
+	req.src_y = 0;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.pixel_format = DRM_FORMAT_ARGB8888;
+	req.gems[0] = crtc->cursor.gem;
+	req.offsets[0] = 0;
+	req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) *
+			 crtc->cursor.width;
+	req.crtc = c;
+
+	if (!req.gems[0] || !req.src_h || !req.src_w) {
+		struct drm_gem_cma_object *cma_gem = crtc->cursor.gem;
+
+		ret = plane->base.funcs->disable_plane(&plane->base);
+		if (!ret && cma_gem) {
+			drm_gem_object_unreference_unlocked(&cma_gem->base);
+			crtc->cursor.gem = NULL;
+		}
+
+		goto out;
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		goto out;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		goto out;
+
+	crtc->cursor.x = x;
+	crtc->cursor.y = y;
+
+out:
+	mutex_unlock(&crtc->cursor.lock);
+	return ret;
+}
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
+	.page_flip = atmel_hlcdc_crtc_page_flip,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = atmel_hlcdc_crtc_destroy,
+};
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_with_cursor_funcs = {
+	.page_flip = atmel_hlcdc_crtc_page_flip,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = atmel_hlcdc_crtc_destroy,
+	.cursor_set = atmel_hlcdc_crtc_cursor_set,
+	.cursor_move = atmel_hlcdc_crtc_cursor_move,
+};
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes = dc->planes;
+	const struct drm_crtc_funcs *funcs;
+	struct atmel_hlcdc_crtc *crtc;
+	int ret;
+	int i;
+
+	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+	if (!crtc) {
+		dev_err(dev->dev, "allocation failed\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&crtc->cursor.lock);
+	crtc->hlcdc = dc->hlcdc;
+	crtc->cursor.plane = planes->cursor;
+
+	if (planes->cursor)
+		funcs = &atmel_hlcdc_crtc_with_cursor_funcs;
+	else
+		funcs = &atmel_hlcdc_crtc_funcs;
+
+	ret = drm_crtc_init_with_planes(dev, &crtc->base,
+				&planes->primary->base,
+				planes->cursor ? &planes->cursor->base : NULL,
+				funcs);
+	if (ret < 0)
+		goto fail;
+
+	crtc->id = drm_crtc_index(&crtc->base);
+
+	if (planes->cursor)
+		planes->cursor->base.possible_crtcs = 1 << crtc->id;
+
+	for (i = 0; i < planes->noverlays; i++)
+		planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
+
+	drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+
+	return 0;
+
+fail:
+	atmel_hlcdc_crtc_destroy(&crtc->base);
+	return ret;
+}
+
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
new file mode 100644
index 0000000..bfecd0d
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "atmel_hlcdc_dc.h"
+
+#define ATMEL_HLCDC_LAYER_IRQS_OFFSET		8
+
+static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
+	{
+		.name = "base",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x40,
+		.id = 0,
+		.type = ATMEL_HLCDC_BASE_LAYER,
+		.nconfigs = 7,
+		.layout = {
+			.xstride = { 2 },
+			.default_color = 3,
+			.general_config = 4,
+			.disc_pos = 5,
+			.disc_size = 6,
+		},
+	},
+	{
+		.name = "overlay1",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x140,
+		.id = 1,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "overlay2",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x240,
+		.id = 2,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "high-end-overlay",
+		.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+		.regs_offset = 0x340,
+		.id = 3,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 42,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.memsize = 4,
+			.xstride = { 5, 7 },
+			.pstride = { 6, 8 },
+			.default_color = 9,
+			.chroma_key = 10,
+			.chroma_key_mask = 11,
+			.general_config = 12,
+			.csc = 14,
+		},
+	},
+	{
+		.name = "cursor",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x440,
+		.id = 4,
+		.type = ATMEL_HLCDC_CURSOR_LAYER,
+		.nconfigs = 10,
+		.max_width = 128,
+		.max_height = 128,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
+	.min_width = 0,
+	.min_height = 0,
+	.max_width = 2048,
+	.max_height = 2048,
+	.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
+	.layers = atmel_hlcdc_sama5d3_layers,
+};
+
+static const struct of_device_id atmel_hlcdc_of_match[] = {
+	{
+		.compatible = "atmel,sama5d3-hlcdc",
+		.data = &atmel_hlcdc_dc_sama5d3,
+	},
+	{ /* sentinel */ },
+};
+
+static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
+{
+	struct drm_device *dev = data;
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned long status;
+	unsigned int imr, isr;
+	int bit;
+
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return IRQ_NONE;
+
+	bit = ATMEL_HLCDC_LAYER_IRQS_OFFSET;
+	for_each_set_bit_from(bit, &status, ATMEL_HLCDC_LAYER_IRQS_OFFSET +
+					    ATMEL_HLCDC_MAX_LAYERS) {
+		int layerid = bit - ATMEL_HLCDC_LAYER_IRQS_OFFSET;
+		struct atmel_hlcdc_layer *layer = dc->layers[layerid];
+
+		if (layer)
+			atmel_hlcdc_layer_irq(layer);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	if (dc->fbdev) {
+		drm_fbdev_cma_hotplug_event(dc->fbdev);
+	} else {
+		dc->fbdev = drm_fbdev_cma_init(dev, 24,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(dc->fbdev))
+			dc->fbdev = NULL;
+	}
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = atmel_hlcdc_fb_create,
+	.output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+};
+
+static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes;
+	int ret;
+	int i;
+
+	drm_mode_config_init(dev);
+
+	ret = atmel_hlcdc_panel_create(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create panel: %d\n", ret);
+		return ret;
+	}
+
+	planes = atmel_hlcdc_create_planes(dev);
+	if (IS_ERR(planes)) {
+		dev_err(dev->dev, "failed to create planes\n");
+		return PTR_ERR(planes);
+	}
+
+	dc->planes = planes;
+
+	dc->layers[planes->primary->layer.desc->id] =
+						&planes->primary->layer;
+
+	if (planes->cursor)
+		dc->layers[planes->cursor->layer.desc->id] =
+							&planes->cursor->layer;
+
+	for (i = 0; i < planes->noverlays; i++)
+		dc->layers[planes->overlays[i]->layer.desc->id] =
+						&planes->overlays[i]->layer;
+
+	ret = atmel_hlcdc_crtc_create(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create crtc\n");
+		return ret;
+	}
+
+	dev->mode_config.min_width = dc->desc->min_width;
+	dev->mode_config.min_height = dc->desc->min_height;
+	dev->mode_config.max_width = dc->desc->max_width;
+	dev->mode_config.max_height = dc->desc->max_height;
+	dev->mode_config.funcs = &mode_config_funcs;
+
+	return 0;
+}
+
+static int atmel_hlcdc_dc_load(struct drm_device *dev, unsigned long flags)
+{
+	struct platform_device *pdev = dev->platformdev;
+	const struct of_device_id *match;
+	struct atmel_hlcdc_dc *dc;
+	int ret;
+
+	match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "invalid compatible string\n");
+		return -ENODEV;
+	}
+
+	if (!match->data) {
+		dev_err(&pdev->dev, "invalid hlcdc description\n");
+		return -EINVAL;
+	}
+
+	dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc) {
+		dev_err(dev->dev, "failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dc->desc = match->data;
+	dc->hlcdc = dev_get_drvdata(dev->dev->parent);
+	dev->dev_private = dc;
+
+	ret = clk_prepare_enable(dc->hlcdc->periph_clk);
+	if (ret) {
+		dev_err(dev->dev, "failed to enable periph_clk\n");
+		return ret;
+	}
+
+	pm_runtime_enable(dev->dev);
+
+	pm_runtime_put_sync(dev->dev);
+
+	ret = atmel_hlcdc_dc_modeset_init(dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize mode setting\n");
+		goto err_periph_clk_disable;
+	}
+
+	ret = drm_vblank_init(dev, 1);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize vblank\n");
+		goto err_periph_clk_disable;
+	}
+
+	pm_runtime_get_sync(dev->dev);
+	ret = drm_irq_install(dev);
+	pm_runtime_put_sync(dev->dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to install IRQ handler\n");
+		goto err_periph_clk_disable;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	drm_kms_helper_poll_init(dev);
+
+	/* force connectors detection */
+	drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_periph_clk_disable:
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+	return ret;
+}
+
+static int atmel_hlcdc_dc_unload(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	drm_kms_helper_poll_fini(dev);
+	drm_mode_config_cleanup(dev);
+	drm_vblank_cleanup(dev);
+
+	pm_runtime_get_sync(dev->dev);
+	drm_irq_uninstall(dev);
+	pm_runtime_put_sync(dev->dev);
+
+	dev->dev_private = NULL;
+
+	pm_runtime_disable(dev->dev);
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_preclose(struct drm_device *dev,
+				    struct drm_file *file)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+		atmel_hlcdc_crtc_cancel_page_flip(crtc, file);
+}
+
+static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	drm_fbdev_cma_restore_mode(dc->fbdev);
+}
+
+static void atmel_hlcdc_dc_irq_preinstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned int isr;
+
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+}
+
+static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	int i;
+
+	/* Enable interrupts on activated layers */
+	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+		if (dc->layers[i])
+			regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER,
+				     BIT(i + 8));
+	}
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
+{
+
+}
+
+static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc)
+{
+	return 0;
+}
+
+static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc)
+{
+}
+
+static const struct file_operations 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 atmel_hlcdc_dc_driver = {
+	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+	.load = atmel_hlcdc_dc_load,
+	.unload = atmel_hlcdc_dc_unload,
+	.preclose = atmel_hlcdc_dc_preclose,
+	.lastclose = atmel_hlcdc_dc_lastclose,
+	.irq_handler = atmel_hlcdc_dc_irq_handler,
+	.irq_preinstall = atmel_hlcdc_dc_irq_preinstall,
+	.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
+	.irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
+	.get_vblank_counter = drm_vblank_count,
+	.enable_vblank = atmel_hlcdc_dc_enable_vblank,
+	.disable_vblank = atmel_hlcdc_dc_disable_vblank,
+	.gem_free_object = drm_gem_cma_free_object,
+	.gem_vm_ops = &drm_gem_cma_vm_ops,
+	.dumb_create = drm_gem_cma_dumb_create,
+	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+	.fops = &fops,
+	.name = "atmel-hlcdc",
+	.desc = "Atmel HLCD Controller DRM",
+	.date = "20141504",
+	.major = 1,
+	.minor = 0,
+};
+
+static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	ret = drm_platform_init(&atmel_hlcdc_dc_driver, pdev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
+{
+	drm_put_dev(platform_get_drvdata(pdev));
+
+	return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
+	{ .compatible = "atmel,hlcdc-dc" },
+	{ },
+};
+
+static struct platform_driver atmel_hlcdc_dc_platform_driver = {
+	.probe	= atmel_hlcdc_dc_drm_probe,
+	.remove	= atmel_hlcdc_dc_drm_remove,
+	.driver	= {
+		.name	= "atmel-hlcdc-dc",
+		.owner	= THIS_MODULE,
+		.of_match_table = atmel_hlcdc_dc_of_match,
+	},
+};
+module_platform_driver(atmel_hlcdc_dc_platform_driver);
+
+MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel-hlcdc-dc");
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
new file mode 100644
index 0000000..1386998
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_ATMEL_HLCDC_H
+#define DRM_ATMEL_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/irqdomain.h>
+#include <linux/pwm.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_panel.h>
+#include <drm/drmP.h>
+
+#include "atmel_hlcdc_layer.h"
+
+#define ATMEL_HLCDC_MAX_LAYERS		5
+
+/**
+ * Atmel HLCDC Display Controller description structure.
+ *
+ * This structure describe the HLCDC IP capabilities and depends on the
+ * HLCDC IP version (or Atmel SoC family).
+ *
+ * @min_width: minimum width supported by the Display Controller
+ * @min_height: minimum height supported by the Display Controller
+ * @max_width: maximum width supported by the Display Controller
+ * @max_height: maximum height supported by the Display Controller
+ * @layer: a layer description table describing available layers
+ * @nlayers: layer description table size
+ */
+struct atmel_hlcdc_dc_desc {
+	int min_width;
+	int min_height;
+	int max_width;
+	int max_height;
+	const struct atmel_hlcdc_layer_desc *layers;
+	int nlayers;
+};
+
+/**
+ * Atmel HLCDC Plane properties.
+ *
+ * This structure stores plane property definitions.
+ *
+ * @alpha: alpha blending (or transparency) property
+ * @csc: YUV to RGB conversion factors property
+ */
+struct atmel_hlcdc_plane_properties {
+	struct drm_property *alpha;
+	struct drm_property *csc;
+};
+
+/**
+ * Atmel HLCDC Plane.
+ *
+ * @base: base DRM plane structure
+ * @layer: HLCDC layer structure
+ * @properties: pointer to the property definitions structure
+ * @alpha: current alpha blending (or transparency) status
+ */
+struct atmel_hlcdc_plane {
+	struct drm_plane base;
+	struct atmel_hlcdc_layer layer;
+	struct atmel_hlcdc_plane_properties *properties;
+};
+
+static inline struct atmel_hlcdc_plane *
+drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
+{
+	return container_of(p, struct atmel_hlcdc_plane, base);
+}
+
+static inline struct atmel_hlcdc_plane *
+atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
+{
+	return container_of(l, struct atmel_hlcdc_plane, layer);
+}
+
+/**
+ * Atmel HLCDC Plane update request structure.
+ *
+ * @crtc_x: x position of the plane relative to the CRTC
+ * @crtc_y: y position of the plane relative to the CRTC
+ * @crtc_w: visible width of the plane
+ * @crtc_h: visible height of the plane
+ * @src_x: x buffer position
+ * @src_y: y buffer position
+ * @src_w: buffer width
+ * @src_h: buffer height
+ * @pixel_format: pixel format
+ * @gems: GEM object object containing image buffers
+ * @offsets: offsets to apply to the GEM buffers
+ * @pitches: line size in bytes
+ * @crtc: crtc to display on
+ * @finished: finished callback
+ * @finished_data: data passed to the finished callback
+ * @bpp: bytes per pixel deduced from pixel_format
+ * @xstride: value to add to the pixel pointer between each line
+ * @pstride: value to add to the pixel pointer between each pixel
+ * @nplanes: number of planes (deduced from pixel_format)
+ */
+struct atmel_hlcdc_plane_update_req {
+	int crtc_x;
+	int crtc_y;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	uint32_t src_x;
+	uint32_t src_y;
+	uint32_t src_w;
+	uint32_t src_h;
+	uint32_t pixel_format;
+	struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
+	unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
+	unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
+	struct drm_crtc *crtc;
+	void (*finished)(void *data);
+	void *finished_data;
+
+	/* These fields are private and should not be touched */
+	int bpp[ATMEL_HLCDC_MAX_PLANES];
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int nplanes;
+};
+
+/**
+ * Atmel HLCDC Planes.
+ *
+ * This structure stores the instantiated HLCDC Planes and can be accessed by
+ * the HLCDC Display Controller or the HLCDC CRTC.
+ *
+ * @primary: primary plane
+ * @cursor: hardware cursor plane
+ * @overlays: overlay plane table
+ * @noverlays: number of overlay planes
+ */
+struct atmel_hlcdc_planes {
+	struct atmel_hlcdc_plane *primary;
+	struct atmel_hlcdc_plane *cursor;
+	struct atmel_hlcdc_plane **overlays;
+	int noverlays;
+};
+
+/**
+ * Atmel HLCDC Display Controller.
+ *
+ * @desc: HLCDC Display Controller description
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @fbdev: framebuffer device attached to the Display Controller
+ * @planes: instantiated planes
+ * @layers: active HLCDC layer
+ */
+struct atmel_hlcdc_dc {
+	const struct atmel_hlcdc_dc_desc *desc;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_fbdev_cma *fbdev;
+	struct atmel_hlcdc_planes *planes;
+	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
+};
+
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev);
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req);
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req);
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
+				       struct drm_file *file);
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev);
+
+int atmel_hlcdc_panel_create(struct drm_device *dev);
+
+struct atmel_hlcdc_pwm_chip *atmel_hlcdc_pwm_create(struct drm_device *dev,
+						    struct clk *slow_clk,
+						    struct clk *sys_clk,
+						    void __iomem *regs);
+
+int atmel_hlcdc_pwm_destroy(struct drm_device *dev,
+			    struct atmel_hlcdc_pwm_chip *chip);
+
+#endif /* DRM_ATMEL_HLCDC_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
new file mode 100644
index 0000000..57c50ec
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+
+#include "atmel_hlcdc_dc.h"
+
+static void
+atmel_hlcdc_layer_gem_flip_release(struct atmel_hlcdc_layer *layer,
+				   struct atmel_hlcdc_layer_gem_flip *flip)
+{
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!flip->gems[i])
+			break;
+
+		drm_gem_object_unreference_unlocked(flip->gems[i]);
+	}
+
+	kfree(flip);
+}
+
+static void atmel_hlcdc_layer_gc_work(struct work_struct *work)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc =
+			container_of(work,
+				     struct atmel_hlcdc_layer_gem_flip_gc,
+				     work);
+	struct atmel_hlcdc_layer *layer =
+			container_of(gc , struct atmel_hlcdc_layer, gc);
+
+	while (true) {
+		struct atmel_hlcdc_layer_gem_flip *flip;
+		unsigned long flags;
+
+		spin_lock_irqsave(&gc->list_lock, flags);
+		flip = list_first_entry_or_null(&gc->list,
+					struct atmel_hlcdc_layer_gem_flip,
+					node);
+		if (flip)
+			list_del(&flip->node);
+		spin_unlock_irqrestore(&gc->list_lock, flags);
+
+		if (!flip)
+			break;
+
+		atmel_hlcdc_layer_gem_flip_release(layer, flip);
+	}
+}
+
+static void
+atmel_hlcdc_layer_gem_flip_put(struct atmel_hlcdc_layer *layer,
+			       struct atmel_hlcdc_layer_gem_flip *flip)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+	unsigned long flags;
+
+	if (--flip->remaining_gems <= 0) {
+		spin_lock_irqsave(&gc->list_lock, flags);
+		list_add_tail(&flip->node,
+			      &gc->list);
+		spin_unlock_irqrestore(&gc->list_lock, flags);
+		schedule_work(&gc->work);
+	}
+}
+
+static void atmel_hlcdc_layer_start_queue(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		dma->cur[i] = dma->queue[i];
+		if (!dma->queue[i])
+			continue;
+		dma->queue[i] = NULL;
+
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+			     dma->cur[i]->addr);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+			     dma->cur[i]->ctrl);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+			     dma->cur[i]->next);
+	}
+}
+
+static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
+{
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned int cfg;
+	u32 action = 0;
+	int i;
+
+	if (upd->pending < 0 || upd->pending > 1)
+		return;
+
+	slot = &upd->slots[upd->pending];
+
+	for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CFG(layer, cfg),
+			     slot->configs[cfg]);
+		action |= ATMEL_HLCDC_LAYER_UPDATE;
+	}
+
+	if (slot->gem_flip && slot->gem_flip->remaining_gems) {
+		struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+
+		for (i = 0; i < layer->max_planes; i++) {
+			struct atmel_hlcdc_dma_channel_dscr *dscr;
+
+			if (!slot->gem_flip->gems[i])
+				break;
+
+			dscr =  slot->dscrs[i];
+			slot->dscrs[i] = NULL;
+
+			if (!dma->enabled) {
+				action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+					     dscr->addr);
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+					     dscr->ctrl);
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+					     dscr->next);
+				dma->cur[i] = dscr;
+			} else {
+				action |= ATMEL_HLCDC_LAYER_A2Q;
+				regmap_write(regmap,
+					     desc->regs_offset +
+					     ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
+					     dscr->next);
+				dma->queue[i] = dscr;
+			}
+		}
+
+		dma->enabled = true;
+		slot->gem_flip = NULL;
+	}
+
+	if (action)
+		regmap_write(regmap,
+			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
+			     action);
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!slot->dscrs[i])
+			continue;
+
+		slot->dscrs[i]->gem_flip = NULL;
+		slot->dscrs[i] = NULL;
+	}
+
+	if (slot->gem_flip) {
+		atmel_hlcdc_layer_gem_flip_put(layer, slot->gem_flip);
+		slot->gem_flip = NULL;
+	}
+
+	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+	memset(slot->configs, 0,
+	       sizeof(*slot->configs) * layer->desc->nconfigs);
+
+	upd->pending = -1;
+}
+
+static bool
+atmel_hlcdc_layer_dma_channel_active(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (dma->cur[i])
+			return true;
+	}
+
+	return false;
+}
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip *flip_gc[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct atmel_hlcdc_layer_gem_flip *flip = NULL;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	unsigned long flags;
+	unsigned int isr, imr;
+	unsigned int status;
+
+	int i;
+
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return;
+
+	memset(flip_gc, 0, sizeof(flip_gc));
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if ((status & ATMEL_HLCDC_LAYER_DONE_IRQ(i)) ||
+		    (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i))) {
+			dscr = dma->cur[i];
+			dma->cur[i] = NULL;
+			flip_gc[i] = dscr->gem_flip;
+			dscr->gem_flip = NULL;
+		}
+
+		if (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i)) {
+			dma->cur[i] = dma->queue[i];
+			flip = dma->queue[i]->gem_flip;
+			dma->queue[i] = NULL;
+		}
+	}
+
+	if (flip && flip->finished &&
+	    !atmel_hlcdc_layer_dma_channel_busy(layer))
+		flip->finished(flip->finished_data);
+
+	/*
+	 * The DMA channel might have been disabled before we were able to
+	 * add the new frame to the DMA transfer queue.
+	 * Try to re-enable the channel in this case.
+	 */
+	if (!atmel_hlcdc_layer_dma_channel_active(layer)) {
+		if (atmel_hlcdc_layer_dma_channel_busy(layer)) {
+			atmel_hlcdc_layer_start_queue(layer);
+
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_CHDR,
+				     ATMEL_HLCDC_LAYER_A2Q);
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_CHER,
+				     ATMEL_HLCDC_LAYER_DMA_CHAN);
+		} else {
+			dma->enabled = false;
+		}
+	}
+
+	if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
+		struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+		spin_lock(&upd->pending_lock);
+		atmel_hlcdc_layer_update_apply(layer);
+		spin_unlock(&upd->pending_lock);
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!flip_gc[i])
+			break;
+
+		atmel_hlcdc_layer_gem_flip_put(layer, flip_gc[i]);
+	}
+}
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!dma->cur[i])
+			break;
+
+		dma->cur[i]->ctrl = 0;
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	return 0;
+}
+
+static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int i;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+	memset(slot->configs, 0,
+	       sizeof(*slot->configs) * layer->desc->nconfigs);
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!slot->dscrs[i])
+			break;
+		slot->dscrs[i]->gem_flip = NULL;
+		slot->dscrs[i] = NULL;
+	}
+	spin_unlock_irqrestore(&layer->dma.lock, flags);
+
+	if (slot->gem_flip) {
+		atmel_hlcdc_layer_gem_flip_release(layer, slot->gem_flip);
+		slot->gem_flip = NULL;
+	}
+
+	upd->next = -1;
+}
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int i, j = 0;
+	int pending;
+
+	gem_flip = kzalloc(sizeof(*gem_flip), GFP_KERNEL);
+	if (!gem_flip)
+		return -ENOMEM;
+
+	mutex_lock(&upd->lock);
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	upd->next = pending ? 0 : 1;
+
+	slot = &upd->slots[upd->next];
+
+	spin_lock_irqsave(&dma->lock, flags);
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		if (!dma->dscrs[i].gem_flip) {
+			slot->dscrs[j++] = &dma->dscrs[i];
+			dma->dscrs[i].gem_flip = gem_flip;
+			if (j == layer->max_planes)
+				break;
+		}
+	}
+
+	if (j < layer->max_planes) {
+		for (i = 0; i < j; i++)
+			slot->dscrs[i]->gem_flip = NULL;
+	}
+	spin_unlock_irqrestore(&layer->dma.lock, flags);
+
+	if (j < layer->max_planes) {
+		mutex_unlock(&upd->lock);
+		kfree(gem_flip);
+		return -EBUSY;
+	}
+
+	slot->gem_flip = gem_flip;
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	if (pending >= 0) {
+		memcpy(upd->slots[upd->next].configs,
+		       upd->slots[upd->pending].configs,
+		       layer->desc->nconfigs * sizeof(u32));
+		memcpy(upd->slots[upd->next].updated_configs,
+		       upd->slots[upd->pending].updated_configs,
+		       DIV_ROUND_UP(layer->desc->nconfigs,
+				    BITS_PER_BYTE * sizeof(unsigned long)) *
+		       sizeof(unsigned long));
+	}
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	if (pending < 0) {
+		regmap_bulk_read(regmap,
+				 layer->desc->regs_offset +
+				 ATMEL_HLCDC_LAYER_CFG(layer, 0),
+				 upd->slots[upd->next].configs,
+				 layer->desc->nconfigs);
+	}
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+	atmel_hlcdc_layer_update_reset(layer);
+	mutex_unlock(&upd->lock);
+}
+
+void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
+				      int plane_id,
+				      struct drm_gem_cma_object *gem,
+				      unsigned int offset)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	struct drm_gem_object *old_gem;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (plane_id >= layer->max_planes || plane_id < 0)
+		return;
+
+	slot = &upd->slots[upd->next];
+	dscr = slot->dscrs[plane_id];
+	dscr->addr = gem->paddr + offset;
+	dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
+	gem_flip = dscr->gem_flip;
+
+	old_gem = gem_flip->gems[plane_id];
+
+	if (gem) {
+		drm_gem_object_reference(&gem->base);
+		gem_flip->gems[plane_id] = &gem->base;
+		gem_flip->remaining_gems++;
+	} else {
+		gem_flip->gems[plane_id] = NULL;
+	}
+
+	if (old_gem) {
+		drm_gem_object_unreference_unlocked(old_gem);
+		gem_flip->remaining_gems--;
+	}
+}
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+					   void (*finished)(void *data),
+					   void *finished_data)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	slot->gem_flip->finished = finished;
+	slot->gem_flip->finished_data = finished_data;
+}
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (cfg >= layer->desc->nconfigs)
+		return;
+
+	slot = &upd->slots[upd->next];
+	slot->configs[cfg] &= ~mask;
+	slot->configs[cfg] |= (val & mask);
+	set_bit(cfg, slot->updated_configs);
+}
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int pending;
+
+	if (upd->next < 0  || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	spin_lock_irqsave(&upd->pending_lock, flags);
+	pending = upd->pending;
+	upd->pending = upd->next;
+	upd->next = pending;
+	if (pending >= 0 && !slot->gem_flip->remaining_gems) {
+		struct atmel_hlcdc_layer_gem_flip *gem_flip = slot->gem_flip;
+		struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+
+		memcpy(dscrs, slot->dscrs, sizeof(dscrs));
+		slot->gem_flip = upd->slots[pending].gem_flip;
+		memcpy(slot->dscrs, upd->slots[pending].dscrs,
+		       sizeof(slot->dscrs));
+		upd->slots[pending].gem_flip = gem_flip;
+		memcpy(upd->slots[pending].dscrs, dscrs, sizeof(dscrs));
+	}
+	spin_unlock_irqrestore(&upd->pending_lock, flags);
+
+	if (pending >= 0) {
+		atmel_hlcdc_layer_update_reset(layer);
+		mutex_unlock(&upd->lock);
+		return;
+	}
+
+	spin_lock_irqsave(&dma->lock, flags);
+	if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
+		spin_lock(&upd->pending_lock);
+		atmel_hlcdc_layer_update_apply(layer);
+		spin_unlock(&upd->pending_lock);
+	}
+	spin_unlock_irqrestore(&dma->lock, flags);
+
+	atmel_hlcdc_layer_update_reset(layer);
+	mutex_unlock(&upd->lock);
+}
+
+static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
+				      struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	dma_addr_t dma_addr;
+	int i;
+
+	dma->dscrs = dma_alloc_coherent(dev->dev,
+					layer->max_planes * 4 *
+					sizeof(*dma->dscrs),
+					&dma_addr, GFP_KERNEL);
+	if (!dma->dscrs)
+		return -ENOMEM;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		dscr->next = dma_addr + (i * sizeof(*dscr));
+	}
+
+	spin_lock_init(&dma->lock);
+
+	return 0;
+}
+
+static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
+					  struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		if (!dscr->gem_flip)
+			continue;
+
+		atmel_hlcdc_layer_gem_flip_put(layer, dscr->gem_flip);
+	}
+
+	dma_free_coherent(dev->dev, layer->max_planes * 4 *
+			  sizeof(*dma->dscrs), dma->dscrs,
+			  dma->dscrs[0].next);
+}
+
+static void atmel_hlcdc_layer_gc_init(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+
+	INIT_LIST_HEAD(&gc->list);
+	spin_lock_init(&gc->list_lock);
+	INIT_WORK(&gc->work, atmel_hlcdc_layer_gc_work);
+}
+
+static void atmel_hlcdc_layer_gc_cleanup(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
+
+	flush_work(&gc->work);
+}
+
+static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
+				struct atmel_hlcdc_layer *layer,
+				const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	int updated_size;
+	void *buffer;
+	int i;
+
+	updated_size = DIV_ROUND_UP(desc->nconfigs,
+				    BITS_PER_BYTE *
+				    sizeof(unsigned long));
+
+	buffer = devm_kzalloc(dev->dev,
+			      ((desc->nconfigs * sizeof(u32)) +
+				(updated_size * sizeof(unsigned long))) * 2,
+			      GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i = 0; i < 2; i++) {
+		upd->slots[i].updated_configs = buffer;
+		buffer += updated_size * sizeof(unsigned long);
+		upd->slots[i].configs = buffer;
+		buffer += desc->nconfigs * sizeof(u32);
+	}
+
+	upd->pending = -1;
+	upd->next = -1;
+	spin_lock_init(&upd->pending_lock);
+	mutex_init(&upd->lock);
+
+	return 0;
+}
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct regmap *regmap = dc->hlcdc->regmap;
+	unsigned int tmp;
+	int ret;
+	int i;
+
+	layer->hlcdc = dc->hlcdc;
+	layer->desc = desc;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+	for (i = 0; i < desc->formats->nformats; i++) {
+		int nplanes = drm_format_num_planes(desc->formats->formats[i]);
+
+		if (nplanes > layer->max_planes)
+			layer->max_planes = nplanes;
+	}
+
+	atmel_hlcdc_layer_gc_init(layer);
+	ret = atmel_hlcdc_layer_dma_init(dev, layer);
+	if (ret)
+		return ret;
+
+	ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
+	if (ret)
+		return ret;
+
+	/* Flush Status Register */
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
+		    &tmp);
+
+	for (i = 0; i < layer->max_planes; i++)
+		regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER,
+			     ATMEL_HLCDC_LAYER_ADD_IRQ(i) |
+			     ATMEL_HLCDC_LAYER_DONE_IRQ(i));
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer)
+{
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+
+	atmel_hlcdc_layer_dma_cleanup(dev, layer);
+	atmel_hlcdc_layer_gc_cleanup(layer);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
new file mode 100644
index 0000000..006d479
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRM_ATMEL_HLCDC_LAYER_H
+#define DRM_ATMEL_HLCDC_LAYER_H
+
+#include <linux/mfd/atmel-hlcdc.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drmP.h>
+
+#define ATMEL_HLCDC_LAYER_CHER			0x0
+#define ATMEL_HLCDC_LAYER_CHDR			0x4
+#define ATMEL_HLCDC_LAYER_CHSR			0x8
+#define ATMEL_HLCDC_LAYER_DMA_CHAN		BIT(0)
+#define ATMEL_HLCDC_LAYER_UPDATE		BIT(1)
+#define ATMEL_HLCDC_LAYER_A2Q			BIT(2)
+#define ATMEL_HLCDC_LAYER_RST			BIT(8)
+
+#define ATMEL_HLCDC_LAYER_IER			0xc
+#define ATMEL_HLCDC_LAYER_IDR			0x10
+#define ATMEL_HLCDC_LAYER_IMR			0x14
+#define ATMEL_HLCDC_LAYER_ISR			0x18
+#define ATMEL_HLCDC_LAYER_DFETCH		BIT(0)
+#define ATMEL_HLCDC_LAYER_LFETCH		BIT(1)
+#define ATMEL_HLCDC_LAYER_DMA_IRQ(n)		BIT(2 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_DSCR_IRQ(n)		BIT(3 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_ADD_IRQ(n)		BIT(4 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_DONE_IRQ(n)		BIT(5 + ((n) * 8))
+#define ATMEL_HLCDC_LAYER_OVR_IRQ(n)		BIT(6 + ((n) * 8))
+
+#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n)		(((n) * 0x10) + 0x1c)
+#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n)		(((n) * 0x10) + 0x20)
+#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n)		(((n) * 0x10) + 0x24)
+#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n)		(((n) * 0x10) + 0x28)
+#define ATMEL_HLCDC_LAYER_CFG(p, c)		(((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
+
+#define ATMEL_HLCDC_LAYER_DMA_CFG_ID		0
+#define ATMEL_HLCDC_LAYER_DMA_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
+
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID		1
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
+#define ATMEL_HLCDC_LAYER_RGB			(0 << 0)
+#define ATMEL_HLCDC_LAYER_CLUT			(1 << 0)
+#define ATMEL_HLCDC_LAYER_YUV			(2 << 0)
+#define ATMEL_HLCDC_RGB_MODE(m)			(((m) & 0xf) << 4)
+#define ATMEL_HLCDC_CLUT_MODE(m)		(((m) & 0x3) << 8)
+#define ATMEL_HLCDC_YUV_MODE(m)			(((m) & 0xf) << 12)
+#define ATMEL_HLCDC_YUV422ROT			(1 << 16)
+#define ATMEL_HLCDC_YUV422SWP			(1 << 17)
+#define ATMEL_HLCDC_DSCALEOPT			(1 << 20)
+
+#define ATMEL_HLCDC_XRGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
+#define ATMEL_HLCDC_ARGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
+#define ATMEL_HLCDC_RGBA4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
+#define ATMEL_HLCDC_RGB565_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
+#define ATMEL_HLCDC_ARGB1555_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
+#define ATMEL_HLCDC_XRGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
+#define ATMEL_HLCDC_RGB888_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
+#define ATMEL_HLCDC_ARGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
+#define ATMEL_HLCDC_RGBA8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
+
+#define ATMEL_HLCDC_AYUV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
+#define ATMEL_HLCDC_YUYV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
+#define ATMEL_HLCDC_UYVY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
+#define ATMEL_HLCDC_YVYU_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
+#define ATMEL_HLCDC_VYUY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
+#define ATMEL_HLCDC_NV61_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
+#define ATMEL_HLCDC_YUV422_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
+#define ATMEL_HLCDC_NV21_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
+#define ATMEL_HLCDC_YUV420_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
+
+#define ATMEL_HLCDC_LAYER_POS_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
+#define ATMEL_HLCDC_LAYER_SIZE_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
+#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
+#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
+#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
+#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
+#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
+#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
+
+#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
+#define ATMEL_HLCDC_LAYER_CRKEY			BIT(0)
+#define ATMEL_HLCDC_LAYER_INV			BIT(1)
+#define ATMEL_HLCDC_LAYER_ITER2BL		BIT(2)
+#define ATMEL_HLCDC_LAYER_ITER			BIT(3)
+#define ATMEL_HLCDC_LAYER_REVALPHA		BIT(4)
+#define ATMEL_HLCDC_LAYER_GAEN			BIT(5)
+#define ATMEL_HLCDC_LAYER_LAEN			BIT(6)
+#define ATMEL_HLCDC_LAYER_OVR			BIT(7)
+#define ATMEL_HLCDC_LAYER_DMA			BIT(8)
+#define ATMEL_HLCDC_LAYER_REP			BIT(9)
+#define ATMEL_HLCDC_LAYER_DSTKEY		BIT(10)
+#define ATMEL_HLCDC_LAYER_GA_MASK		GENMASK(23, 16)
+#define ATMEL_HLCDC_LAYER_GA_SHIFT		16
+
+#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
+
+#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
+
+#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
+
+#define ATMEL_HLCDC_MAX_PLANES			3
+
+/**
+ * Atmel HLCDC Layer registers layout structure
+ *
+ * Each HLCDC layer has its own register organization and a given register
+ * by be placed differently on 2 different layers depending on its
+ * capabilities.
+ * This structure stores common registers layout for a given layer and is
+ * used by HLCDC layer code to chose the appropriate register to write to
+ * or to read from.
+ *
+ * For all fields, a value of zero means "unsupported".
+ *
+ * See Atmel's datasheet for a detailled description of these registers.
+ *
+ * @xstride: xstride registers
+ * @pstride: pstride registers
+ * @pos: position register
+ * @size: displayed size register
+ * @memsize: memory size register
+ * @default_color: default color register
+ * @chroma_key: chroma key register
+ * @chroma_key_mask: chroma key mask register
+ * @general_config: general layer config register
+ * @disc_pos: discard area position register
+ * @disc_size: discard area size register
+ * @csc: color space conversion register
+ */
+struct atmel_hlcdc_layer_cfg_layout {
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int pos;
+	int size;
+	int memsize;
+	int default_color;
+	int chroma_key;
+	int chroma_key_mask;
+	int general_config;
+	int disc_pos;
+	int disc_size;
+	int csc;
+};
+
+/**
+ * Atmel HLCDC GEM flip structure
+ *
+ * This structure is allocated when someone asked for a layer update (most
+ * likely a DRM plane update, either primary, overlay or cursor plane) and
+ * released when the layer do not need the reference GEM objects anymore
+ * (i.e. the layer was disabled or updated).
+ *
+ * @node: list element structure. Used to attach the GEM flip structure to
+ *	  the garbage collector when the layer no longer need the referenced
+ *	  GEM objects.
+ * @gems: the referenced GEM objects. The number of GEM object referenced
+ *	  depends on the chosen format.
+ * @remaining_gems: the number of GEM object still referenced by the layer.
+ *		    When no more objects are referenced the GEM flip structure
+ *		    is added to the garbage collector.
+ */
+struct atmel_hlcdc_layer_gem_flip {
+	struct list_head node;
+	struct drm_gem_object *gems[ATMEL_HLCDC_MAX_PLANES];
+	int remaining_gems;
+	void (*finished)(void *data);
+	void *finished_data;
+};
+
+/**
+ * Atmel HLCDC DMA descriptor structure
+ *
+ * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
+ *
+ * The structure fields must remain in this specific order, because they're
+ * used by the HLCDC DMA engine, which expect them in this order.
+ *
+ * @addr: buffer DMA address
+ * @ctrl: DMA transfer options
+ * @next: next DMA descriptor to fetch
+ * @gem_flip: the attached gem_flip operation
+ */
+struct atmel_hlcdc_dma_channel_dscr {
+	dma_addr_t addr;
+	u32 ctrl;
+	dma_addr_t next;
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+} __aligned(sizeof(u64));
+
+/**
+ * Atmel HLCDC layer types
+ */
+enum atmel_hlcdc_layer_type {
+	ATMEL_HLCDC_BASE_LAYER,
+	ATMEL_HLCDC_OVERLAY_LAYER,
+	ATMEL_HLCDC_CURSOR_LAYER,
+	ATMEL_HLCDC_PP_LAYER,
+};
+
+/**
+ * Atmel HLCDC Supported formats structure
+ *
+ * This structure list all the formats supported by a given layer.
+ *
+ * @nformats: number of supported formats
+ * @formats: supported formats
+ */
+struct atmel_hlcdc_formats {
+	int nformats;
+	uint32_t *formats;
+};
+
+/**
+ * Atmel HLCDC Layer description structure
+ *
+ * This structure describe the capabilities provided by a given layer.
+ *
+ * @name: layer name
+ * @type: layer type
+ * @id: layer id
+ * @regs_offset: offset of the layer registers from the HLCDC registers base
+ * @nconfigs: number of config registers provided by this layer
+ * @layout: config registers layout
+ * @max_width: maximum width supported by this layer (0 means unlimited)
+ * @max_height: maximum height supported by this layer (0 means unlimited)
+ */
+struct atmel_hlcdc_layer_desc {
+	const char *name;
+	enum atmel_hlcdc_layer_type type;
+	int id;
+	int regs_offset;
+	int nconfigs;
+	struct atmel_hlcdc_formats *formats;
+	struct atmel_hlcdc_layer_cfg_layout layout;
+	int max_width;
+	int max_height;
+};
+
+/**
+ * Atmel HLCDC Layer Update Slot structure
+ *
+ * This structure stores layer update requests to be applied on next frame.
+ * This is the base structure behind the atomic layer update infrastructure.
+ *
+ * Atomic layer update provides a way to update all layer's parameters
+ * simultaneously. This is needed to avoid incompatible sequential updates
+ * like this one:
+ * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
+ *    (2 planes/buffers)
+ * 2) the format update is applied but the DMA channel for the second
+ *    plane/buffer is not enabled
+ * 3) enable the DMA channel for the second plane
+ *
+ *@dscrs: DMA channel descriptors
+ *@gem_flip: gem_flip object
+ *@updated_configs: bitmask used to record modified configs
+ *@configs: new config values
+ */
+struct atmel_hlcdc_layer_update_slot {
+	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_layer_gem_flip *gem_flip;
+	unsigned long *updated_configs;
+	u32 *configs;
+};
+
+/**
+ * Atmel HLCDC Layer Update structure
+ *
+ * This structure provides a way to queue layer update requests.
+ *
+ * At a given time there is at most:
+ *  - one pending update request, which means the update request has been
+ *    commited (or validated) and is waiting for the DMA channel(s) to be
+ *    available
+ *  - one request being prepared, which means someone started a layer update
+ *    but has not commited it yet. There cannot be more than one started
+ *    request, because the update lock is taken when starting a layer update
+ *    and release when commiting or rolling back the request.
+ *
+ *@slots: update slots. One is used for pending request and the other one
+ *	  for started update request
+ *@pending: the pending slot index or -1 if no request is pending
+ *@next: the started update slot index or -1 no update has been started
+ *@pending_lock: lock to access the pending field
+ *@lock: layer update lock
+ */
+struct atmel_hlcdc_layer_update {
+	struct atmel_hlcdc_layer_update_slot slots[2];
+	int pending;
+	int next;
+	spinlock_t pending_lock;
+	struct mutex lock;
+};
+
+/**
+ * Atmel HLCDC Layer GEM flip garbage collector structure
+ *
+ * This structure is used to schedule GEM object release when we are in
+ * interrupt context (within atmel_hlcdc_layer_irq function).
+ *
+ *@list: GEM flip objects to release
+ *@list_lock: lock to access the GEM flip list
+ *@work: work queue scheduled when there are GEM flip to collect
+ *@finished: action to execute the GEM flip and all attached objects have been
+ *	     released
+ *@finished_data: data passed to the finished callback
+ *@finished_lock: lock to access finished related fields
+ */
+struct atmel_hlcdc_layer_gem_flip_gc {
+	struct list_head list;
+	spinlock_t list_lock;
+	struct work_struct work;
+};
+
+/**
+ * Atmel HLCDC Layer DMA channel structure
+ *
+ * This structure stores informations on the DMA channel associated to a
+ * given layer.
+ *
+ *@enabled: DMA channel status
+ *@lock: lock to access the DMA channel fields
+ *@cur: current DMA transfers (one for each plane/buffer)
+ *@queue: next DMA transfers, to be launch on next frame update
+ *@dscrs: allocated DMA descriptors
+ */
+struct atmel_hlcdc_layer_dma_channel {
+	bool enabled;
+	spinlock_t lock;
+	struct atmel_hlcdc_dma_channel_dscr *cur[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_dma_channel_dscr *queue[ATMEL_HLCDC_MAX_PLANES];
+	struct atmel_hlcdc_dma_channel_dscr *dscrs;
+};
+
+/**
+ * Atmel HLCDC Layer structure
+ *
+ * This structure stores information on the layer instance.
+ *
+ *@desc: layer description
+ *@max_planes: maximum planes/buffers that can be associated with this layer.
+ *	       This depends on the supported formats.
+ *@hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ *@dma: dma channel
+ *@gc: GEM flip garbage collector
+ *@update: update handler
+ */
+struct atmel_hlcdc_layer {
+	const struct atmel_hlcdc_layer_desc *desc;
+	int max_planes;
+	struct atmel_hlcdc *hlcdc;
+	struct atmel_hlcdc_layer_dma_channel dma;
+	struct atmel_hlcdc_layer_gem_flip_gc gc;
+	struct atmel_hlcdc_layer_update update;
+};
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc);
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_set_finished(struct atmel_hlcdc_layer *layer,
+				    void (*finished)(void *data),
+				    void *data);
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val);
+
+void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
+				      int plane_id,
+				      struct drm_gem_cma_object *gem,
+				      unsigned int offset);
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+					   void (*finished)(void *data),
+					   void *finished_data);
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
+
+static inline bool
+atmel_hlcdc_layer_dma_channel_busy(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (dma->queue[i])
+			return true;
+	}
+
+	return false;
+}
+
+#endif /* DRM_ATMEL_HLCDC_LAYER_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
new file mode 100644
index 0000000..3295021
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC RGB output mode
+ */
+enum atmel_hlcdc_connector_rgb_mode {
+	ATMEL_HLCDC_CONNECTOR_RGB444,
+	ATMEL_HLCDC_CONNECTOR_RGB565,
+	ATMEL_HLCDC_CONNECTOR_RGB666,
+	ATMEL_HLCDC_CONNECTOR_RGB888,
+};
+
+/**
+ * Atmel HLCDC Panel structure
+ *
+ * This structure stores informations about an DRM panel connected through
+ * the RGB connector.
+ *
+ * @mode: RGB output mode
+ * @connector: DRM connector
+ * @encoder: DRM encoder
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @panel: pointer to the attached DRM panel
+ * @pinctrl: pinctrl state used by the current RGB output mode
+ * @np: DRM panel DT node
+ * @dpms: current DPMS mode
+ */
+struct atmel_hlcdc_panel {
+	enum atmel_hlcdc_connector_rgb_mode mode;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_panel *panel;
+	struct pinctrl *pinctrl;
+	struct device_node *np;
+	int dpms;
+};
+
+static const char * const pin_state_names[] = {
+	[ATMEL_HLCDC_CONNECTOR_RGB444] = "rgb-444",
+	[ATMEL_HLCDC_CONNECTOR_RGB565] = "rgb-565",
+	[ATMEL_HLCDC_CONNECTOR_RGB666] = "rgb-666",
+	[ATMEL_HLCDC_CONNECTOR_RGB888] = "rgb-888",
+};
+
+static inline struct atmel_hlcdc_panel *
+drm_connector_to_atmel_hlcdc_panel(struct drm_connector *connector)
+{
+	return container_of(connector, struct atmel_hlcdc_panel, connector);
+}
+
+static inline struct atmel_hlcdc_panel *
+drm_encoder_to_atmel_hlcdc_panel(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct atmel_hlcdc_panel, encoder);
+}
+
+static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
+					   int mode)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_encoder_to_atmel_hlcdc_panel(encoder);
+	struct regmap *regmap = panel->hlcdc->regmap;
+	unsigned int status;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	if (mode == panel->dpms)
+		return;
+
+	if (mode != DRM_MODE_DPMS_ON) {
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+		clk_disable_unprepare(panel->hlcdc->sys_clk);
+		if (panel->panel)
+			drm_panel_disable(panel->panel);
+	} else {
+		if (panel->panel)
+			drm_panel_enable(panel->panel);
+		clk_prepare_enable(panel->hlcdc->sys_clk);
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+	}
+
+	panel->dpms = mode;
+}
+
+static bool
+atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
+				     const struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted)
+{
+	return true;
+}
+
+static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void
+atmel_hlcdc_panel_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_encoder_to_atmel_hlcdc_panel(encoder);
+	unsigned long prate = clk_get_rate(panel->hlcdc->sys_clk);
+	unsigned long mode_rate = mode->clock * 1000;
+	int div;
+	u32 cfg0 = 0;
+
+	if ((prate / 2) < mode_rate) {
+		prate *= 2;
+		cfg0 |= ATMEL_HLCDC_CLKSEL;
+	}
+
+	div = DIV_ROUND_UP(prate, mode_rate);
+	if (div < 2)
+		div = 2;
+
+	cfg0 |= ATMEL_HLCDC_CLKDIV(div);
+
+	regmap_update_bits(panel->hlcdc->regmap, ATMEL_HLCDC_CFG(0),
+			   ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK, cfg0);
+}
+
+static struct drm_encoder_helper_funcs encoder_helper_funcs = {
+	.dpms = atmel_hlcdc_panel_encoder_dpms,
+	.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
+	.prepare = atmel_hlcdc_panel_encoder_prepare,
+	.commit = atmel_hlcdc_panel_encoder_commit,
+	.mode_set = atmel_hlcdc_panel_encoder_mode_set,
+};
+
+static void atmel_hlcdc_panel_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+	memset(encoder, 0, sizeof(*encoder));
+}
+
+static const struct drm_encoder_funcs encoder_funcs = {
+	.destroy = atmel_hlcdc_panel_encoder_destroy,
+};
+
+static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+	int ret;
+
+	if (!panel->panel)
+		return -ENOENT;
+
+	ret = panel->panel->funcs->get_modes(panel->panel);
+	return ret;
+}
+
+static int atmel_hlcdc_panel_mode_valid(struct drm_connector *connector,
+					struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+atmel_hlcdc_panel_best_encoder(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	return &panel->encoder;
+}
+
+static struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = atmel_hlcdc_panel_get_modes,
+	.mode_valid = atmel_hlcdc_panel_mode_valid,
+	.best_encoder = atmel_hlcdc_panel_best_encoder,
+};
+
+static enum drm_connector_status
+atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	if (!panel->panel) {
+		panel->panel = of_drm_find_panel(panel->np);
+		if (panel->panel)
+			drm_panel_attach(panel->panel, &panel->connector);
+	}
+
+	if (panel->panel)
+		return connector_status_connected;
+
+	return connector_status_disconnected;
+}
+
+static void
+atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_panel *panel =
+			drm_connector_to_atmel_hlcdc_panel(connector);
+
+	if (panel->panel)
+		drm_panel_detach(panel->panel);
+
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+
+	pinctrl_put(panel->pinctrl);
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = atmel_hlcdc_panel_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = atmel_hlcdc_panel_connector_destroy,
+};
+
+int atmel_hlcdc_panel_create(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_panel *panel;
+	struct of_phandle_args out_args;
+	u32 cfg;
+	int ret;
+
+	panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
+	if (!panel)
+		return -ENOMEM;
+
+	ret = of_parse_phandle_with_fixed_args(dev->dev->of_node,
+					       "atmel,panel", 2, 0,
+					       &out_args);
+	if (ret) {
+		dev_err(dev->dev, "failed to retrieve panel info from DT\n");
+		return ret;
+	}
+
+	switch (out_args.args[0]) {
+	case ATMEL_HLCDC_CONNECTOR_RGB444:
+	case ATMEL_HLCDC_CONNECTOR_RGB565:
+	case ATMEL_HLCDC_CONNECTOR_RGB666:
+	case ATMEL_HLCDC_CONNECTOR_RGB888:
+		break;
+	default:
+		dev_err(dev->dev, "unknown RGB mode\n");
+		return -EINVAL;
+	}
+
+	panel->np = out_args.np;
+	panel->mode = out_args.args[0];
+	panel->pinctrl = pinctrl_get_select(dev->dev,
+					    pin_state_names[panel->mode]);
+	if (IS_ERR(panel->pinctrl)) {
+		dev_err(dev->dev, "could not request pinctrl state\n");
+		return PTR_ERR(panel->pinctrl);
+	}
+
+	cfg = out_args.args[1] & (ATMEL_HLCDC_HSPOL |
+				  ATMEL_HLCDC_VSPOL |
+				  ATMEL_HLCDC_VSPDLYS |
+				  ATMEL_HLCDC_VSPDLYE |
+				  ATMEL_HLCDC_DISPPOL |
+				  ATMEL_HLCDC_DISPDLY |
+				  ATMEL_HLCDC_VSPSU |
+				  ATMEL_HLCDC_VSPHO);
+	cfg |= panel->mode << 8;
+
+	regmap_write(dc->hlcdc->regmap,
+		     ATMEL_HLCDC_CFG(5),
+		     cfg);
+
+	panel->dpms = DRM_MODE_DPMS_OFF;
+
+	panel->hlcdc = dc->hlcdc;
+
+	drm_connector_init(dev, &panel->connector, &connector_funcs,
+			   DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(&panel->connector, &connector_helper_funcs);
+	panel->connector.dpms = DRM_MODE_DPMS_OFF;
+	panel->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+
+	drm_encoder_init(dev, &panel->encoder, &encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS);
+	drm_encoder_helper_add(&panel->encoder, &encoder_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&panel->connector, &panel->encoder);
+	drm_sysfs_connector_add(&panel->connector);
+
+	panel->encoder.possible_crtcs = 0x1;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
new file mode 100644
index 0000000..0c7469b
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "atmel_hlcdc_dc.h"
+
+#define SUBPIXEL_MASK			0xffff
+
+static uint32_t rgb_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
+	.formats = rgb_formats,
+	.nformats = ARRAY_SIZE(rgb_formats),
+};
+
+static uint32_t rgb_and_yuv_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_AYUV,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YUV420,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
+	.formats = rgb_and_yuv_formats,
+	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
+};
+
+static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB4444:
+		*mode = ATMEL_HLCDC_XRGB4444_MODE;
+		break;
+	case DRM_FORMAT_ARGB4444:
+		*mode = ATMEL_HLCDC_ARGB4444_MODE;
+		break;
+	case DRM_FORMAT_RGBA4444:
+		*mode = ATMEL_HLCDC_RGBA4444_MODE;
+		break;
+	case DRM_FORMAT_RGB565:
+		*mode = ATMEL_HLCDC_RGB565_MODE;
+		break;
+	case DRM_FORMAT_RGB888:
+		*mode = ATMEL_HLCDC_RGB888_MODE;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		*mode = ATMEL_HLCDC_ARGB1555_MODE;
+		break;
+	case DRM_FORMAT_XRGB8888:
+		*mode = ATMEL_HLCDC_XRGB8888_MODE;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		*mode = ATMEL_HLCDC_ARGB8888_MODE;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		*mode = ATMEL_HLCDC_RGBA8888_MODE;
+		break;
+	case DRM_FORMAT_AYUV:
+		*mode = ATMEL_HLCDC_AYUV_MODE;
+		break;
+	case DRM_FORMAT_YUYV:
+		*mode = ATMEL_HLCDC_YUYV_MODE;
+		break;
+	case DRM_FORMAT_UYVY:
+		*mode = ATMEL_HLCDC_UYVY_MODE;
+		break;
+	case DRM_FORMAT_YVYU:
+		*mode = ATMEL_HLCDC_YVYU_MODE;
+		break;
+	case DRM_FORMAT_VYUY:
+		*mode = ATMEL_HLCDC_VYUY_MODE;
+		break;
+	case DRM_FORMAT_NV21:
+		*mode = ATMEL_HLCDC_NV21_MODE;
+		break;
+	case DRM_FORMAT_NV61:
+		*mode = ATMEL_HLCDC_NV61_MODE;
+		break;
+	case DRM_FORMAT_YUV420:
+		*mode = ATMEL_HLCDC_YUV420_MODE;
+		break;
+	case DRM_FORMAT_YUV422:
+		*mode = ATMEL_HLCDC_YUV422_MODE;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static bool atmel_hlcdc_format_embedds_alpha(u32 format)
+{
+	int i;
+
+	for (i = 0; i < sizeof(format); i++) {
+		char tmp = (format >> (8 * i)) & 0xff;
+
+		if (tmp == 'A')
+			return true;
+	}
+
+	return false;
+}
+
+static u32 heo_downscaling_xcoef[] = {
+	0x11343311,
+	0x000000f7,
+	0x1635300c,
+	0x000000f9,
+	0x1b362c08,
+	0x000000fb,
+	0x1f372804,
+	0x000000fe,
+	0x24382400,
+	0x00000000,
+	0x28371ffe,
+	0x00000004,
+	0x2c361bfb,
+	0x00000008,
+	0x303516f9,
+	0x0000000c,
+};
+
+static u32 heo_downscaling_ycoef[] = {
+	0x00123737,
+	0x00173732,
+	0x001b382d,
+	0x001f3928,
+	0x00243824,
+	0x0028391f,
+	0x002d381b,
+	0x00323717,
+};
+
+static u32 heo_upscaling_xcoef[] = {
+	0xf74949f7,
+	0x00000000,
+	0xf55f33fb,
+	0x000000fe,
+	0xf5701efe,
+	0x000000ff,
+	0xf87c0dff,
+	0x00000000,
+	0x00800000,
+	0x00000000,
+	0x0d7cf800,
+	0x000000ff,
+	0x1e70f5ff,
+	0x000000fe,
+	0x335ff5fe,
+	0x000000fb,
+};
+
+static u32 heo_upscaling_ycoef[] = {
+	0x00004040,
+	0x00075920,
+	0x00056f0c,
+	0x00027b03,
+	0x00008000,
+	0x00037b02,
+	0x000c6f05,
+	0x00205907,
+};
+
+static void
+atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (layout->size)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->size,
+					     0xffffffff,
+					     (req->crtc_w - 1) |
+					     ((req->crtc_h - 1) << 16));
+
+	if (layout->memsize)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->memsize,
+					     0xffffffff,
+					     (req->src_w - 1) |
+					     ((req->src_h - 1) << 16));
+
+	if (layout->pos)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->pos,
+					     0xffffffff,
+					     req->crtc_x |
+					     (req->crtc_y  << 16));
+
+	/* TODO: rework the rescaling part */
+	if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
+		u32 factor_reg = 0;
+
+		if (req->crtc_w != req->src_w) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_xcoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_xcoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     17 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= factor | 0x80000000;
+		}
+
+		if (req->crtc_h != req->src_h) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_ycoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_ycoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     33 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= (factor << 16) | 0x80000000;
+		}
+
+		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
+					     factor_reg);
+	}
+}
+
+static void
+atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
+
+	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
+		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
+		       ATMEL_HLCDC_LAYER_ITER;
+
+		if (atmel_hlcdc_format_embedds_alpha(req->pixel_format))
+			cfg |= ATMEL_HLCDC_LAYER_LAEN;
+		else
+			cfg |= ATMEL_HLCDC_LAYER_GAEN;
+	}
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
+				     ATMEL_HLCDC_LAYER_ITER2BL |
+				     ATMEL_HLCDC_LAYER_ITER |
+				     ATMEL_HLCDC_LAYER_GAEN |
+				     ATMEL_HLCDC_LAYER_LAEN |
+				     ATMEL_HLCDC_LAYER_OVR |
+				     ATMEL_HLCDC_LAYER_DMA, cfg);
+}
+
+static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	u32 mode;
+	int ret;
+
+	ret = atmel_hlcdc_format_to_plane_mode(req->pixel_format, &mode);
+	if (ret)
+		return;
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
+				     0xffffffff,
+				     mode);
+}
+
+static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_layer *layer = &plane->layer;
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+							&layer->desc->layout;
+	int i;
+
+	for (i = 0; i < req->nplanes; i++) {
+		atmel_hlcdc_layer_update_set_gem(&plane->layer, i,
+						 req->gems[i],
+						 req->offsets[i]);
+		if (layout->xstride[i])
+			atmel_hlcdc_layer_update_cfg(&plane->layer,
+						layout->xstride[i],
+						0xffffffff,
+						req->pitches[i] -
+						(req->bpp[i] * req->src_w));
+	}
+}
+
+static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (!layout->size &&
+	    (req->crtc->mode.crtc_hdisplay != req->crtc_w ||
+	     req->crtc->mode.crtc_vdisplay != req->crtc_h))
+		return -EINVAL;
+
+	if (plane->layer.desc->max_height &&
+	    req->crtc_h > plane->layer.desc->max_height)
+		return -EINVAL;
+
+	if (plane->layer.desc->max_width &&
+	    req->crtc_w > plane->layer.desc->max_width)
+		return -EINVAL;
+
+	if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
+	    (!layout->memsize ||
+	     atmel_hlcdc_format_embedds_alpha(req->pixel_format)))
+		return -EINVAL;
+
+	return 0;
+}
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	unsigned int patched_crtc_w;
+	unsigned int patched_crtc_h;
+	int x_offset = 0;
+	int y_offset = 0;
+	int i;
+
+	if ((req->src_x | req->src_y | req->src_w | req->src_h) &
+	    SUBPIXEL_MASK)
+		return -EINVAL;
+
+	req->src_x >>= 16;
+	req->src_y >>= 16;
+	req->src_w >>= 16;
+	req->src_h >>= 16;
+
+	req->nplanes = drm_format_num_planes(req->pixel_format);
+	if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
+		return -EINVAL;
+
+	if (req->crtc_x + req->crtc_w > req->crtc->mode.hdisplay)
+		patched_crtc_w = req->crtc->mode.hdisplay - req->crtc_x;
+	else
+		patched_crtc_w = req->crtc_w;
+
+	if (req->crtc_x < 0) {
+		patched_crtc_w += req->crtc_x;
+		x_offset = -req->crtc_x;
+		req->crtc_x = 0;
+	}
+
+	if (req->crtc_y + req->crtc_h > req->crtc->mode.vdisplay)
+		patched_crtc_h = req->crtc->mode.vdisplay - req->crtc_y;
+	else
+		patched_crtc_h = req->crtc_h;
+
+	if (req->crtc_y < 0) {
+		patched_crtc_h += req->crtc_y;
+		y_offset = -req->crtc_y;
+		req->crtc_y = 0;
+	}
+
+	req->src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
+				       req->crtc_w);
+	req->src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
+				       req->crtc_h);
+	req->crtc_w = patched_crtc_w;
+	req->crtc_h = patched_crtc_h;
+
+	for (i = 0; i < req->nplanes; i++) {
+		req->bpp[i] = drm_format_plane_cpp(req->pixel_format, i);
+		if (!req->bpp[i])
+			return -EINVAL;
+
+		req->offsets[i] += (x_offset + (y_offset * patched_crtc_w)) *
+				   req->bpp[i];
+	}
+
+	return atmel_hlcdc_plane_check_update_req(p, req);
+}
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	int ret;
+
+	ret = atmel_hlcdc_layer_update_start(&plane->layer);
+	if (ret)
+		return ret;
+
+	atmel_hlcdc_plane_update_pos_and_size(plane, req);
+	atmel_hlcdc_plane_update_general_settings(plane, req);
+	atmel_hlcdc_plane_update_format(plane, req);
+	atmel_hlcdc_plane_update_buffers(plane, req);
+	atmel_hlcdc_layer_update_set_finished(&plane->layer, req->finished,
+					      req->finished_data);
+
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_update(struct drm_plane *p,
+				    struct drm_crtc *crtc,
+				    struct drm_framebuffer *fb,
+				    int crtc_x, int crtc_y,
+				    unsigned int crtc_w, unsigned int crtc_h,
+				    uint32_t src_x, uint32_t src_y,
+				    uint32_t src_w, uint32_t src_h)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_update_req req;
+	int ret = 0;
+	int i;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = crtc_x;
+	req.crtc_y = crtc_y;
+	req.crtc_w = crtc_w;
+	req.crtc_h = crtc_h;
+	req.src_x = src_x;
+	req.src_y = src_y;
+	req.src_w = src_w;
+	req.src_h = src_h;
+	req.pixel_format = fb->pixel_format;
+	req.crtc = crtc;
+
+	for (i = 0; i < plane->layer.max_planes; i++) {
+		req.offsets[i] = fb->offsets[i];
+		req.pitches[i] = fb->pitches[i];
+		req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
+	}
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
+	if (ret)
+		return ret;
+
+	ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+	if (ret)
+		return ret;
+
+	drm_framebuffer_reference(fb);
+	if (plane->base.fb)
+		drm_framebuffer_unreference(plane->base.fb);
+	plane->base.fb = fb;
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_disable(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	return atmel_hlcdc_layer_disable(&plane->layer);
+}
+
+static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	if (plane->base.fb)
+		drm_framebuffer_unreference(plane->base.fb);
+
+	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
+
+	drm_plane_cleanup(p);
+	devm_kfree(p->dev->dev, plane);
+}
+
+static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
+				       u8 alpha)
+{
+	atmel_hlcdc_layer_update_start(&plane->layer);
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     plane->layer.desc->layout.general_config,
+				     ATMEL_HLCDC_LAYER_GA_MASK,
+				     alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
+					  struct drm_property *property,
+					  uint64_t value)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_properties *props = plane->properties;
+
+	if (property == props->alpha)
+		atmel_hlcdc_plane_set_alpha(plane, value);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
+				const struct atmel_hlcdc_layer_desc *desc,
+				struct atmel_hlcdc_plane_properties *props)
+{
+	struct regmap *regmap = plane->layer.hlcdc->regmap;
+
+	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
+	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
+		drm_object_attach_property(&plane->base.base,
+					   props->alpha, 255);
+
+		/* Set default alpha value */
+		regmap_update_bits(regmap,
+				desc->regs_offset +
+				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
+				ATMEL_HLCDC_LAYER_GA_MASK,
+				ATMEL_HLCDC_LAYER_GA_MASK);
+	}
+
+	if (desc->layout.csc) {
+		/*
+		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
+		 * userspace modify these factors (using a BLOB property ?).
+		 */
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
+			     0x4c900091);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
+			     0x7a5f5090);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
+			     0x40040890);
+	}
+}
+
+static struct drm_plane_funcs layer_plane_funcs = {
+	.update_plane = atmel_hlcdc_plane_update,
+	.disable_plane = atmel_hlcdc_plane_disable,
+	.set_property = atmel_hlcdc_plane_set_property,
+	.destroy = atmel_hlcdc_plane_destroy,
+};
+
+static struct atmel_hlcdc_plane *
+atmel_hlcdc_plane_create(struct drm_device *dev,
+			 const struct atmel_hlcdc_layer_desc *desc,
+			 struct atmel_hlcdc_plane_properties *props)
+{
+	struct atmel_hlcdc_plane *plane;
+	enum drm_plane_type type;
+	int ret;
+
+	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+	if (!plane)
+		return ERR_PTR(-ENOMEM);
+
+	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
+		type = DRM_PLANE_TYPE_PRIMARY;
+	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
+		type = DRM_PLANE_TYPE_CURSOR;
+	else
+		type = DRM_PLANE_TYPE_OVERLAY;
+
+	ret = drm_universal_plane_init(dev, &plane->base, 0,
+				       &layer_plane_funcs,
+				       desc->formats->formats,
+				       desc->formats->nformats, type);
+	if (ret)
+		return ERR_PTR(ret);
+
+	/* Set default property values*/
+	atmel_hlcdc_plane_init_properties(plane, desc, props);
+
+	return plane;
+}
+
+static struct atmel_hlcdc_plane_properties *
+atmel_hlcdc_plane_create_properties(struct drm_device *dev)
+{
+	struct atmel_hlcdc_plane_properties *props;
+
+	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
+	if (!props)
+		return ERR_PTR(-ENOMEM);
+
+	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
+	if (!props->alpha)
+		return ERR_PTR(-ENOMEM);
+
+	return props;
+}
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_plane_properties *props;
+	struct atmel_hlcdc_planes *planes;
+	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
+	int nlayers = dc->desc->nlayers;
+	int i;
+
+	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
+	if (!planes)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < nlayers; i++) {
+		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
+			planes->noverlays++;
+	}
+
+	if (planes->noverlays) {
+		planes->overlays = devm_kzalloc(dev->dev,
+						planes->noverlays *
+						sizeof(*planes->overlays),
+						GFP_KERNEL);
+		if (!planes->overlays)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	props = atmel_hlcdc_plane_create_properties(dev);
+	if (IS_ERR(props))
+		return ERR_CAST(props);
+
+	planes->noverlays = 0;
+	for (i = 0; i < nlayers; i++) {
+		struct atmel_hlcdc_plane *plane;
+
+		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
+			continue;
+
+		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
+		if (IS_ERR(plane))
+			return ERR_CAST(plane);
+
+		plane->properties = props;
+
+		switch (descs[i].type) {
+		case ATMEL_HLCDC_BASE_LAYER:
+			if (planes->primary)
+				return ERR_PTR(-EINVAL);
+			planes->primary = plane;
+			break;
+
+		case ATMEL_HLCDC_OVERLAY_LAYER:
+			planes->overlays[planes->noverlays++] = plane;
+			break;
+
+		case ATMEL_HLCDC_CURSOR_LAYER:
+			if (planes->cursor)
+				return ERR_PTR(-EINVAL);
+			planes->cursor = plane;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return planes;
+}
-- 
1.8.3.2

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:42   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
controller device.

The HLCDC block provides a single RGB output port, and only supports LCD
panels connection to LCD panels for now.

The atmel,panel property link the HLCDC RGB output with the LCD panel
connected on this port (note that the HLCDC RGB connector implementation
makes use of the DRM panel framework).

Connection to other external devices (DRM bridges) might be added later by
mean of a new atmel,xxx (atmel,bridge) property.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
new file mode 100644
index 0000000..594bdb2
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
@@ -0,0 +1,59 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
+
+The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
+See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,hlcdc-dc"
+ - interrupts: the HLCDC interrupt definition
+ - pinctrl-names: the pin control state names. Should contain "default",
+   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
+ - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
+   names.
+ - atmel,panel: Should contain a phandle with 2 parameters.
+   The first cell is a phandle to a DRM panel device
+   The second cell encodes the RGB mode, which can take the following values:
+   * 0: RGB444
+   * 1: RGB565
+   * 2: RGB666
+   * 3: RGB888
+   The third cell encodes specific flags describing LCD signals configuration
+   (see Atmel's datasheet for a full description of these fields):
+   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
+   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
+   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
+   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
+   * bit 4: DISPPOL: Display Signal Polarity
+   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
+   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
+   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
+   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
+
+Example:
+
+	hlcdc: hlcdc@f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+		status = "disabled";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2


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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-07 16:42   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
controller device.

The HLCDC block provides a single RGB output port, and only supports LCD
panels connection to LCD panels for now.

The atmel,panel property link the HLCDC RGB output with the LCD panel
connected on this port (note that the HLCDC RGB connector implementation
makes use of the DRM panel framework).

Connection to other external devices (DRM bridges) might be added later by
mean of a new atmel,xxx (atmel,bridge) property.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
new file mode 100644
index 0000000..594bdb2
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
@@ -0,0 +1,59 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
+
+The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
+See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be one of the following:
+   "atmel,hlcdc-dc"
+ - interrupts: the HLCDC interrupt definition
+ - pinctrl-names: the pin control state names. Should contain "default",
+   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
+ - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
+   names.
+ - atmel,panel: Should contain a phandle with 2 parameters.
+   The first cell is a phandle to a DRM panel device
+   The second cell encodes the RGB mode, which can take the following values:
+   * 0: RGB444
+   * 1: RGB565
+   * 2: RGB666
+   * 3: RGB888
+   The third cell encodes specific flags describing LCD signals configuration
+   (see Atmel's datasheet for a full description of these fields):
+   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
+   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
+   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
+   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
+   * bit 4: DISPPOL: Display Signal Polarity
+   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
+   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
+   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
+   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
+
+Example:
+
+	hlcdc: hlcdc at f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+		status = "disabled";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-dc";
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+			pinctrl-0 = <&pinctrl_lcd_base>;
+			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
+			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
-- 
1.8.3.2

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

* [RESEND PATCH v3 07/11] ARM: AT91/dt: split sama5d3 lcd pin definitions to match RGB mode configs
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:43   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

The HLCDC (HLCD Controller) IP supports 4 different output mode (RGB444,
RGB565, RGB666 and RGB888) and the pin muxing will depend on the chosen
RGB mode.

Split pin definitions to be able to set pin config according to the
selected mode.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 127 ++++++++++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 31 deletions(-)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 85d3027..2186b89 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -15,38 +15,103 @@
 		apb {
 			pinctrl@fffff200 {
 				lcd {
-					pinctrl_lcd: lcd-0 {
+					pinctrl_lcd_pwm: lcd-pwm-0 {
+						atmel,pins = <AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDPWM */
+					};
+
+					pinctrl_lcd_base: lcd-base-0 {
+						atmel,pins =
+							<AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDVSYNC */
+							 AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDHSYNC */
+							 AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDDISP */
+							 AT91_PIOA 29 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDDEN */
+							 AT91_PIOA 28 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDPCK */
+					};
+
+					pinctrl_lcd_rgb444: lcd-rgb-0 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD11 pin */
+					};
+
+					pinctrl_lcd_rgb565: lcd-rgb-1 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD15 pin */
+					};
+
+					pinctrl_lcd_rgb666: lcd-rgb-2 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD17 pin */
+					};
+
+					pinctrl_lcd_rgb888: lcd-rgb-3 {
 						atmel,pins =
-							<AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA24 periph A LCDPWM */
-							 AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA26 periph A LCDVSYNC */
-							 AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA27 periph A LCDHSYNC */
-							 AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA25 periph A LCDDISP */
-							 AT91_PIOA 29 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA29 periph A LCDDEN */
-							 AT91_PIOA 28 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA28 periph A LCDPCK */
-							 AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA0 periph A LCDD0 pin */
-							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA1 periph A LCDD1 pin */
-							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA2 periph A LCDD2 pin */
-							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA3 periph A LCDD3 pin */
-							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA4 periph A LCDD4 pin */
-							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA5 periph A LCDD5 pin */
-							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA6 periph A LCDD6 pin */
-							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA7 periph A LCDD7 pin */
-							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA8 periph A LCDD8 pin */
-							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA9 periph A LCDD9 pin */
-							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA10 periph A LCDD10 pin */
-							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA11 periph A LCDD11 pin */
-							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA12 periph A LCDD12 pin */
-							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA13 periph A LCDD13 pin */
-							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA14 periph A LCDD14 pin */
-							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA15 periph A LCDD15 pin */
-							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC14 periph C LCDD16 pin */
-							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC13 periph C LCDD17 pin */
-							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC12 periph C LCDD18 pin */
-							 AT91_PIOC 11 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC11 periph C LCDD19 pin */
-							 AT91_PIOC 10 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC10 periph C LCDD20 pin */
-							 AT91_PIOC 15 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC15 periph C LCDD21 pin */
-							 AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PE27 periph C LCDD22 pin */
-							 AT91_PIOE 28 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* PE28 periph C LCDD23 pin */
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD17 pin */
+							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD18 pin */
+							 AT91_PIOC 11 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD19 pin */
+							 AT91_PIOC 10 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD20 pin */
+							 AT91_PIOC 15 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD21 pin */
+							 AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD22 pin */
+							 AT91_PIOE 28 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD23 pin */
 					};
 				};
 			};
-- 
1.8.3.2


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

* [RESEND PATCH v3 07/11] ARM: AT91/dt: split sama5d3 lcd pin definitions to match RGB mode configs
@ 2014-07-07 16:43   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

The HLCDC (HLCD Controller) IP supports 4 different output mode (RGB444,
RGB565, RGB666 and RGB888) and the pin muxing will depend on the chosen
RGB mode.

Split pin definitions to be able to set pin config according to the
selected mode.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 127 ++++++++++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 31 deletions(-)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 85d3027..2186b89 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -15,38 +15,103 @@
 		apb {
 			pinctrl at fffff200 {
 				lcd {
-					pinctrl_lcd: lcd-0 {
+					pinctrl_lcd_pwm: lcd-pwm-0 {
+						atmel,pins = <AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDPWM */
+					};
+
+					pinctrl_lcd_base: lcd-base-0 {
+						atmel,pins =
+							<AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDVSYNC */
+							 AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDHSYNC */
+							 AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDDISP */
+							 AT91_PIOA 29 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDDEN */
+							 AT91_PIOA 28 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDPCK */
+					};
+
+					pinctrl_lcd_rgb444: lcd-rgb-0 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD11 pin */
+					};
+
+					pinctrl_lcd_rgb565: lcd-rgb-1 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD15 pin */
+					};
+
+					pinctrl_lcd_rgb666: lcd-rgb-2 {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD17 pin */
+					};
+
+					pinctrl_lcd_rgb888: lcd-rgb-3 {
 						atmel,pins =
-							<AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA24 periph A LCDPWM */
-							 AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA26 periph A LCDVSYNC */
-							 AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA27 periph A LCDHSYNC */
-							 AT91_PIOA 25 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA25 periph A LCDDISP */
-							 AT91_PIOA 29 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA29 periph A LCDDEN */
-							 AT91_PIOA 28 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA28 periph A LCDPCK */
-							 AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA0 periph A LCDD0 pin */
-							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA1 periph A LCDD1 pin */
-							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA2 periph A LCDD2 pin */
-							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA3 periph A LCDD3 pin */
-							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA4 periph A LCDD4 pin */
-							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA5 periph A LCDD5 pin */
-							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA6 periph A LCDD6 pin */
-							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA7 periph A LCDD7 pin */
-							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA8 periph A LCDD8 pin */
-							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA9 periph A LCDD9 pin */
-							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA10 periph A LCDD10 pin */
-							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA11 periph A LCDD11 pin */
-							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA12 periph A LCDD12 pin */
-							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA13 periph A LCDD13 pin */
-							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA14 periph A LCDD14 pin */
-							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PA15 periph A LCDD15 pin */
-							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC14 periph C LCDD16 pin */
-							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC13 periph C LCDD17 pin */
-							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC12 periph C LCDD18 pin */
-							 AT91_PIOC 11 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC11 periph C LCDD19 pin */
-							 AT91_PIOC 10 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC10 periph C LCDD20 pin */
-							 AT91_PIOC 15 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC15 periph C LCDD21 pin */
-							 AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PE27 periph C LCDD22 pin */
-							 AT91_PIOE 28 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* PE28 periph C LCDD23 pin */
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD17 pin */
+							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD18 pin */
+							 AT91_PIOC 11 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD19 pin */
+							 AT91_PIOC 10 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD20 pin */
+							 AT91_PIOC 15 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD21 pin */
+							 AT91_PIOE 27 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD22 pin */
+							 AT91_PIOE 28 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD23 pin */
 					};
 				};
 			};
-- 
1.8.3.2

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

* [RESEND PATCH v3 08/11] ARM: AT91/dt: add alternative pin muxing for sama5d3 lcd pins
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:43   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

Define alternative pin muxing for the LCDC pins.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 50 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 2186b89..9642eef 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -82,6 +82,28 @@
 							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
 							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
 							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 16 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 17 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD17 pin */
+					};
+
+					pinctrl_lcd_rgb666_alt: lcd-rgb-2-alt {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
 							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
 							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD17 pin */
 					};
@@ -104,6 +126,34 @@
 							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
 							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
 							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 16 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 17 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD17 pin */
+							 AT91_PIOC 18 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD18 pin */
+							 AT91_PIOC 19 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD19 pin */
+							 AT91_PIOC 20 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD20 pin */
+							 AT91_PIOC 21 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD21 pin */
+							 AT91_PIOE 22 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD22 pin */
+							 AT91_PIOE 23 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD23 pin */
+					};
+
+					pinctrl_lcd_rgb888_alt: lcd-rgb-3-alt {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
 							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
 							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD17 pin */
 							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD18 pin */
-- 
1.8.3.2


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

* [RESEND PATCH v3 08/11] ARM: AT91/dt: add alternative pin muxing for sama5d3 lcd pins
@ 2014-07-07 16:43   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

Define alternative pin muxing for the LCDC pins.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 50 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 2186b89..9642eef 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -82,6 +82,28 @@
 							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
 							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
 							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 16 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 17 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD17 pin */
+					};
+
+					pinctrl_lcd_rgb666_alt: lcd-rgb-2-alt {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
 							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
 							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* LCDD17 pin */
 					};
@@ -104,6 +126,34 @@
 							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
 							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
 							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
+							 AT91_PIOC 16 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD16 pin */
+							 AT91_PIOC 17 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD17 pin */
+							 AT91_PIOC 18 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD18 pin */
+							 AT91_PIOC 19 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD19 pin */
+							 AT91_PIOC 20 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD20 pin */
+							 AT91_PIOC 21 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD21 pin */
+							 AT91_PIOE 22 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD22 pin */
+							 AT91_PIOE 23 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* LCDD23 pin */
+					};
+
+					pinctrl_lcd_rgb888_alt: lcd-rgb-3-alt {
+						atmel,pins =
+							<AT91_PIOA 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD0 pin */
+							 AT91_PIOA 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD1 pin */
+							 AT91_PIOA 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD2 pin */
+							 AT91_PIOA 3 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD3 pin */
+							 AT91_PIOA 4 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD4 pin */
+							 AT91_PIOA 5 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD5 pin */
+							 AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD6 pin */
+							 AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD7 pin */
+							 AT91_PIOA 8 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD8 pin */
+							 AT91_PIOA 9 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD9 pin */
+							 AT91_PIOA 10 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD10 pin */
+							 AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD11 pin */
+							 AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD12 pin */
+							 AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD13 pin */
+							 AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD14 pin */
+							 AT91_PIOA 15 AT91_PERIPH_A AT91_PINCTRL_NONE	/* LCDD15 pin */
 							 AT91_PIOC 14 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD16 pin */
 							 AT91_PIOC 13 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD17 pin */
 							 AT91_PIOC 12 AT91_PERIPH_C AT91_PINCTRL_NONE	/* LCDD18 pin */
-- 
1.8.3.2

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

* [RESEND PATCH v3 09/11] ARM: at91/dt: define the HLCDC node available on sama5d3 SoCs
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:43   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

Define the HLCDC (HLCD Controller) IP available on some sama5d3 SoCs
(i.e. sama5d31, sama5d33, sama5d34 and sama5d36) in sama5d3 dtsi file.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 9642eef..f6aa637 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -166,6 +166,26 @@
 				};
 			};
 
+			hlcdc: hlcdc@f0030000 {
+				compatible = "atmel,sama5d3-hlcdc";
+				reg = <0xf0030000 0x2000>;
+				clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+				clock-names = "periph_clk","sys_clk", "slow_clk";
+				status = "disabled";
+
+				hlcdc-display-controller {
+					compatible = "atmel,hlcdc-dc";
+					interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+				};
+
+				hlcdc_pwm: hlcdc-pwm {
+					compatible = "atmel,hlcdc-pwm";
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_lcd_pwm>;
+					#pwm-cells = <3>;
+				};
+			};
+
 			pmc: pmc@fffffc00 {
 				periphck {
 					lcdc_clk: lcdc_clk {
-- 
1.8.3.2


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

* [RESEND PATCH v3 09/11] ARM: at91/dt: define the HLCDC node available on sama5d3 SoCs
@ 2014-07-07 16:43   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

Define the HLCDC (HLCD Controller) IP available on some sama5d3 SoCs
(i.e. sama5d31, sama5d33, sama5d34 and sama5d36) in sama5d3 dtsi file.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3_lcd.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3_lcd.dtsi b/arch/arm/boot/dts/sama5d3_lcd.dtsi
index 9642eef..f6aa637 100644
--- a/arch/arm/boot/dts/sama5d3_lcd.dtsi
+++ b/arch/arm/boot/dts/sama5d3_lcd.dtsi
@@ -166,6 +166,26 @@
 				};
 			};
 
+			hlcdc: hlcdc at f0030000 {
+				compatible = "atmel,sama5d3-hlcdc";
+				reg = <0xf0030000 0x2000>;
+				clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+				clock-names = "periph_clk","sys_clk", "slow_clk";
+				status = "disabled";
+
+				hlcdc-display-controller {
+					compatible = "atmel,hlcdc-dc";
+					interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+				};
+
+				hlcdc_pwm: hlcdc-pwm {
+					compatible = "atmel,hlcdc-pwm";
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_lcd_pwm>;
+					#pwm-cells = <3>;
+				};
+			};
+
 			pmc: pmc at fffffc00 {
 				periphck {
 					lcdc_clk: lcdc_clk {
-- 
1.8.3.2

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

* [RESEND PATCH v3 10/11] ARM: at91/dt: add LCD panel description to sama5d3xdm.dtsi
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:43   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

Add LCD panel related nodes (backlight, regulators and panel) to sama5d3
Display Module dtsi.

Reference LCD pin muxing used by sama5d3xek boards.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3xdm.dtsi | 43 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3xdm.dtsi b/arch/arm/boot/dts/sama5d3xdm.dtsi
index 035ab72..690055e 100644
--- a/arch/arm/boot/dts/sama5d3xdm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xdm.dtsi
@@ -36,6 +36,49 @@
 					};
 				};
 			};
+
+			hlcdc: hlcdc@f0030000 {
+				hlcdc-display-controller {
+					pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+					pinctrl-0 = <&pinctrl_lcd_base>;
+					pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+					pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+					pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666_alt>;
+					pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>;
+				};
+			};
 		};
 	};
+
+	bl_reg: backlight_regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "backlight-power-supply";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		status = "disabled";
+	};
+
+	panel_reg: panel_regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "panel-power-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		status = "disabled";
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&hlcdc_pwm 0 50000 0>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+		power-supply = <&bl_reg>;
+		status = "disabled";
+	};
+
+	panel: panel {
+		compatible = "foxlink,fl500wvr00-a0t", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&panel_reg>;
+		status = "disabled";
+	};
 };
-- 
1.8.3.2


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

* [RESEND PATCH v3 10/11] ARM: at91/dt: add LCD panel description to sama5d3xdm.dtsi
@ 2014-07-07 16:43   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add LCD panel related nodes (backlight, regulators and panel) to sama5d3
Display Module dtsi.

Reference LCD pin muxing used by sama5d3xek boards.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d3xdm.dtsi | 43 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d3xdm.dtsi b/arch/arm/boot/dts/sama5d3xdm.dtsi
index 035ab72..690055e 100644
--- a/arch/arm/boot/dts/sama5d3xdm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xdm.dtsi
@@ -36,6 +36,49 @@
 					};
 				};
 			};
+
+			hlcdc: hlcdc at f0030000 {
+				hlcdc-display-controller {
+					pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", "rgb-888";
+					pinctrl-0 = <&pinctrl_lcd_base>;
+					pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
+					pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+					pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666_alt>;
+					pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>;
+				};
+			};
 		};
 	};
+
+	bl_reg: backlight_regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "backlight-power-supply";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		status = "disabled";
+	};
+
+	panel_reg: panel_regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "panel-power-supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		status = "disabled";
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&hlcdc_pwm 0 50000 0>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+		power-supply = <&bl_reg>;
+		status = "disabled";
+	};
+
+	panel: panel {
+		compatible = "foxlink,fl500wvr00-a0t", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&panel_reg>;
+		status = "disabled";
+	};
 };
-- 
1.8.3.2

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

* [RESEND PATCH v3 11/11] ARM: at91/dt: enable the LCD panel on sama5d3xek boards
  2014-07-07 16:42 ` Boris BREZILLON
@ 2014-07-07 16:43   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor
  Cc: Jean-Jacques Hiblot, Laurent Pinchart, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer,
	Boris BREZILLON

Enable LCD related nodes and reference panel node in the hlcdc (HLCD
Controller) node.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d31ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d33ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d34ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d36ek.dts | 24 ++++++++++++++++++++++++
 4 files changed, 96 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d31ek.dts b/arch/arm/boot/dts/sama5d31ek.dts
index 04eec0d..338f4c3 100644
--- a/arch/arm/boot/dts/sama5d31ek.dts
+++ b/arch/arm/boot/dts/sama5d31ek.dts
@@ -33,6 +33,14 @@
 				status = "okay";
 			};
 
+			hlcdc: hlcdc@f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
+
 			macb1: ethernet@f802c000 {
 				status = "okay";
 			};
@@ -46,6 +54,22 @@
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d33ek.dts b/arch/arm/boot/dts/sama5d33ek.dts
index cbd6a3f..f2ab41d 100644
--- a/arch/arm/boot/dts/sama5d33ek.dts
+++ b/arch/arm/boot/dts/sama5d33ek.dts
@@ -36,9 +36,33 @@
 			macb0: ethernet@f0028000 {
 				status = "okay";
 			};
+
+			hlcdc: hlcdc@f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d34ek.dts b/arch/arm/boot/dts/sama5d34ek.dts
index 878aa16..0d0049c 100644
--- a/arch/arm/boot/dts/sama5d34ek.dts
+++ b/arch/arm/boot/dts/sama5d34ek.dts
@@ -46,6 +46,14 @@
 			macb0: ethernet@f0028000 {
 				status = "okay";
 			};
+
+			hlcdc: hlcdc@f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
 		};
 	};
 
@@ -56,6 +64,22 @@
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d36ek.dts b/arch/arm/boot/dts/sama5d36ek.dts
index 59576c6..8350358 100644
--- a/arch/arm/boot/dts/sama5d36ek.dts
+++ b/arch/arm/boot/dts/sama5d36ek.dts
@@ -41,12 +41,36 @@
 				status = "okay";
 			};
 
+			hlcdc: hlcdc@f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
+
 			macb1: ethernet@f802c000 {
 				status = "okay";
 			};
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
-- 
1.8.3.2


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

* [RESEND PATCH v3 11/11] ARM: at91/dt: enable the LCD panel on sama5d3xek boards
@ 2014-07-07 16:43   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-07 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

Enable LCD related nodes and reference panel node in the hlcdc (HLCD
Controller) node.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/sama5d31ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d33ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d34ek.dts | 24 ++++++++++++++++++++++++
 arch/arm/boot/dts/sama5d36ek.dts | 24 ++++++++++++++++++++++++
 4 files changed, 96 insertions(+)

diff --git a/arch/arm/boot/dts/sama5d31ek.dts b/arch/arm/boot/dts/sama5d31ek.dts
index 04eec0d..338f4c3 100644
--- a/arch/arm/boot/dts/sama5d31ek.dts
+++ b/arch/arm/boot/dts/sama5d31ek.dts
@@ -33,6 +33,14 @@
 				status = "okay";
 			};
 
+			hlcdc: hlcdc at f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
+
 			macb1: ethernet at f802c000 {
 				status = "okay";
 			};
@@ -46,6 +54,22 @@
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d33ek.dts b/arch/arm/boot/dts/sama5d33ek.dts
index cbd6a3f..f2ab41d 100644
--- a/arch/arm/boot/dts/sama5d33ek.dts
+++ b/arch/arm/boot/dts/sama5d33ek.dts
@@ -36,9 +36,33 @@
 			macb0: ethernet at f0028000 {
 				status = "okay";
 			};
+
+			hlcdc: hlcdc at f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d34ek.dts b/arch/arm/boot/dts/sama5d34ek.dts
index 878aa16..0d0049c 100644
--- a/arch/arm/boot/dts/sama5d34ek.dts
+++ b/arch/arm/boot/dts/sama5d34ek.dts
@@ -46,6 +46,14 @@
 			macb0: ethernet at f0028000 {
 				status = "okay";
 			};
+
+			hlcdc: hlcdc at f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
 		};
 	};
 
@@ -56,6 +64,22 @@
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sama5d36ek.dts b/arch/arm/boot/dts/sama5d36ek.dts
index 59576c6..8350358 100644
--- a/arch/arm/boot/dts/sama5d36ek.dts
+++ b/arch/arm/boot/dts/sama5d36ek.dts
@@ -41,12 +41,36 @@
 				status = "okay";
 			};
 
+			hlcdc: hlcdc at f0030000 {
+				status = "okay";
+
+				hlcdc-display-controller {
+					atmel,panel = <&panel 3 0>;
+				};
+			};
+
 			macb1: ethernet at f802c000 {
 				status = "okay";
 			};
 		};
 	};
 
+	bl_reg: backlight_regulator {
+		status = "okay";
+	};
+
+	panel_reg: panel_regulator {
+		status = "okay";
+	};
+
+	backlight: backlight {
+		status = "okay";
+	};
+
+	panel: panel {
+		status = "okay";
+	};
+
 	sound {
 		status = "okay";
 	};
-- 
1.8.3.2

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-07 16:42   ` Boris BREZILLON
  (?)
@ 2014-07-08  3:45   ` Rob Clark
  2014-07-08  7:23       ` Boris BREZILLON
  2014-07-09  8:18       ` Boris BREZILLON
  -1 siblings, 2 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-08  3:45 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> controller device.
>
> This display controller supports at least one primary plane and might
> provide several overlays and an hardware cursor depending on the IP
> version.
>
> At the moment, this driver only implements an RGB connector to interface
> with LCD panels, but support for other kind of external devices (like DRM
> bridges) might be added later.
>
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
>  drivers/gpu/drm/Kconfig                         |   2 +
>  drivers/gpu/drm/Makefile                        |   1 +
>  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>  11 files changed, 3382 insertions(+)
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index d1cc2f6..df6f0c1 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>
>  source "drivers/gpu/drm/armada/Kconfig"
>
> +source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
> +
>  source "drivers/gpu/drm/rcar-du/Kconfig"
>
>  source "drivers/gpu/drm/shmobile/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 48e38ba..28c8a61 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
>  obj-$(CONFIG_DRM_UDL) += udl/
>  obj-$(CONFIG_DRM_AST) += ast/
>  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_OMAP) += omapdrm/
> diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig
> new file mode 100644
> index 0000000..bc07315
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig
> @@ -0,0 +1,11 @@
> +config DRM_ATMEL_HLCDC
> +       tristate "DRM Support for ATMEL HLCDC Display Controller"
> +       depends on DRM && OF && MFD_ATMEL_HLCDC && COMMON_CLK
> +       select DRM_GEM_CMA_HELPER
> +       select DRM_KMS_HELPER
> +       select DRM_KMS_FB_HELPER
> +       select DRM_KMS_CMA_HELPER
> +       select DRM_PANEL
> +       help
> +         Choose this option if you have an ATMEL SoC with an HLCDC display
> +         controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
> diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile
> new file mode 100644
> index 0000000..bf9fe0b
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
> @@ -0,0 +1,7 @@
> +atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
> +               atmel_hlcdc_dc.o \
> +               atmel_hlcdc_layer.o \
> +               atmel_hlcdc_panel.o \
> +               atmel_hlcdc_plane.o
> +
> +obj-$(CONFIG_DRM_ATMEL_HLCDC)  += atmel-hlcdc-dc.o
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> new file mode 100644
> index 0000000..8b11af8
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> @@ -0,0 +1,469 @@
> +/*
> + * Copyright (C) 2014 Traphandler
> + * Copyright (C) 2014 Free Electrons
> + *
> + * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/pm.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drmP.h>
> +
> +#include <video/videomode.h>
> +
> +#include "atmel_hlcdc_dc.h"
> +
> +/**
> + * Structure storing HW cursor status.
> + *
> + * @status: the current cursor status
> + * @req: the requested cursor changes
> + * @plane: the hardware cursor plane
> + * @lock: cursor lock held when modifying cursor req or status
> + */
> +struct atmel_hlcdc_crtc_cursor {
> +       struct atmel_hlcdc_plane *plane;
> +       struct drm_gem_cma_object *gem;
> +       u32 height;
> +       u32 width;
> +       int x;
> +       int y;
> +       struct mutex lock;
> +};
> +
> +/**
> + * Atmel HLCDC CRTC structure
> + *
> + * @base: base DRM CRTC structure
> + * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
> + * @event: pointer to the current page flip event
> + * @id: CRTC id (returned by drm_crtc_index)
> + * @dpms: DPMS mode
> + * @cursor: hardware cursor status
> + */
> +struct atmel_hlcdc_crtc {
> +       struct drm_crtc base;
> +       struct atmel_hlcdc *hlcdc;
> +       struct drm_pending_vblank_event *event;
> +       int id;
> +       int dpms;
> +       struct atmel_hlcdc_crtc_cursor cursor;
> +};
> +
> +static inline struct atmel_hlcdc_crtc *
> +drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
> +{
> +       return container_of(crtc, struct atmel_hlcdc_crtc, base);
> +}
> +
> +
> +static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
> +{
> +       struct drm_device *dev = c->dev;
> +
> +       if (mode != DRM_MODE_DPMS_ON)
> +               mode = DRM_MODE_DPMS_OFF;
> +
> +       pm_runtime_get_sync(dev->dev);
> +
> +       if (mode == DRM_MODE_DPMS_ON)
> +               pm_runtime_forbid(dev->dev);
> +       else
> +               pm_runtime_allow(dev->dev);
> +
> +       pm_runtime_put_sync(dev->dev);
> +}
> +
> +static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
> +                                    struct drm_display_mode *mode,
> +                                    struct drm_display_mode *adjusted,
> +                                    int x, int y,
> +                                    struct drm_framebuffer *old_fb)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +       struct regmap *regmap = crtc->hlcdc->regmap;
> +       struct drm_plane *plane = c->primary;
> +       struct drm_framebuffer *fb;
> +       struct videomode vm;
> +
> +       vm.vfront_porch = mode->vsync_start - mode->vdisplay;
> +       vm.vback_porch = mode->vtotal - mode->vsync_end;
> +       vm.vsync_len = mode->vsync_end - mode->vsync_start;
> +       vm.hfront_porch = mode->hsync_start - mode->hdisplay;
> +       vm.hback_porch = mode->htotal - mode->hsync_end;
> +       vm.hsync_len = mode->hsync_end - mode->hsync_start;
> +
> +       if (vm.hsync_len > 0x40 || vm.hsync_len < 1 ||
> +           vm.vsync_len > 0x40 || vm.vsync_len < 1 ||
> +           vm.vfront_porch > 0x40 || vm.vfront_porch < 1 ||
> +           vm.vback_porch > 0x40 || vm.vback_porch < 0 ||
> +           vm.hfront_porch > 0x200 || vm.hfront_porch < 1 ||
> +           vm.hback_porch > 0x200 || vm.hback_porch < 1 ||
> +           mode->hdisplay > 2048 || mode->hdisplay < 1 ||
> +           mode->vdisplay > 2048 || mode->vdisplay < 1)
> +               return -EINVAL;
> +
> +       regmap_write(regmap, ATMEL_HLCDC_CFG(1),
> +                    (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
> +
> +       regmap_write(regmap, ATMEL_HLCDC_CFG(2),
> +                    (vm.vfront_porch - 1) | (vm.vback_porch << 16));
> +
> +       regmap_write(regmap, ATMEL_HLCDC_CFG(3),
> +                    (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
> +
> +       regmap_write(regmap, ATMEL_HLCDC_CFG(4),
> +                    (mode->hdisplay - 1) | ((mode->vdisplay - 1) << 16));
> +
> +       fb = plane->fb;
> +       plane->fb = old_fb;
> +
> +       return plane->funcs->update_plane(plane, c, fb,
> +                                         0, 0,
> +                                         mode->hdisplay, mode->vdisplay,
> +                                         c->x << 16, c->y << 16,
> +                                         mode->hdisplay << 16,
> +                                         mode->vdisplay << 16);
> +}
> +
> +static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
> +{
> +       atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
> +}
> +
> +static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
> +{
> +       atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
> +}
> +
> +static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
> +                                       const struct drm_display_mode *mode,
> +                                       struct drm_display_mode *adjusted_mode)
> +{
> +       return true;
> +}
> +
> +
> +static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
> +
> +       .mode_fixup = atmel_hlcdc_crtc_mode_fixup,
> +       .dpms = atmel_hlcdc_crtc_dpms,
> +       .mode_set = atmel_hlcdc_crtc_mode_set,
> +       .prepare = atmel_hlcdc_crtc_prepare,
> +       .commit = atmel_hlcdc_crtc_commit,
> +};
> +
> +static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +
> +       drm_crtc_cleanup(c);
> +       kfree(crtc);
> +}
> +
> +void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
> +                                      struct drm_file *file)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +       struct drm_pending_vblank_event *event;
> +       struct drm_device *dev = c->dev;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&dev->event_lock, flags);
> +       event = crtc->event;
> +       if (event && event->base.file_priv == file) {
> +               event->base.destroy(&event->base);
> +               drm_vblank_put(dev, crtc->id);
> +               crtc->event = NULL;
> +       }
> +       spin_unlock_irqrestore(&dev->event_lock, flags);
> +}
> +
> +static void atmel_hlcdc_crtc_finish_page_flip(void *data)
> +{
> +       struct atmel_hlcdc_crtc *crtc = data;
> +       struct drm_device *dev = crtc->base.dev;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&dev->event_lock, flags);
> +       if (crtc->event) {
> +               drm_send_vblank_event(dev, crtc->id, crtc->event);
> +               drm_vblank_put(dev, crtc->id);
> +               crtc->event = NULL;
> +       }
> +       spin_unlock_irqrestore(&dev->event_lock, flags);
> +}
> +
> +static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
> +                                     struct drm_framebuffer *fb,
> +                                     struct drm_pending_vblank_event *event,
> +                                     uint32_t page_flip_flags)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +       struct atmel_hlcdc_plane_update_req req;
> +       struct drm_plane *plane = c->primary;
> +       int ret;
> +       int i;
> +
> +       if (crtc->event)
> +               return -EBUSY;
> +
> +       memset(&req, 0, sizeof(req));
> +       req.crtc_x = 0;
> +       req.crtc_y = 0;
> +       req.crtc_h = c->mode.crtc_vdisplay;
> +       req.crtc_w = c->mode.crtc_hdisplay;
> +       req.src_x = c->x << 16;
> +       req.src_y = c->y << 16;
> +       req.src_w = req.crtc_w << 16;
> +       req.src_h = req.crtc_h << 16;
> +       req.pixel_format = fb->pixel_format;
> +
> +       for (i = 0; i < ATMEL_HLCDC_MAX_PLANES; i++) {
> +               req.offsets[i] = fb->offsets[i];
> +               req.pitches[i] = fb->pitches[i];
> +               req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
> +       }
> +
> +       req.crtc = c;
> +       req.finished = atmel_hlcdc_crtc_finish_page_flip;
> +       req.finished_data = crtc;
> +
> +       ret = atmel_hlcdc_plane_prepare_update_req(plane, &req);
> +       if (ret)
> +               return ret;
> +
> +       if (event) {
> +               crtc->event = event;
> +               drm_vblank_get(c->dev, crtc->id);
> +       }
> +
> +       ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
> +
> +       if (ret) {
> +               crtc->event = NULL;
> +               drm_vblank_put(c->dev, crtc->id);
> +       } else {
> +               drm_framebuffer_reference(fb);
> +               if (plane->fb)
> +                       drm_framebuffer_unreference(plane->fb);
> +               plane->fb = fb;
> +       }
> +
> +       return ret;
> +}
> +
> +static int atmel_hlcdc_crtc_cursor_set(struct drm_crtc *c,
> +                                      struct drm_file *file_priv,
> +                                      uint32_t handle,
> +                                      uint32_t width, uint32_t height)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +       struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
> +       struct drm_gem_cma_object *cma_gem = NULL;
> +       struct atmel_hlcdc_plane_update_req req;
> +       int ret;
> +
> +       if (unlikely(!plane))
> +               return -ENOTSUPP;
> +
> +       mutex_lock(&crtc->cursor.lock);
> +
> +       if (handle) {
> +               struct drm_gem_object *gem;
> +
> +               gem = drm_gem_object_lookup(c->dev, file_priv, handle);
> +               if (unlikely(!gem)) {
> +                       ret = -ENOENT;
> +                       goto out;
> +               }
> +
> +               cma_gem = to_drm_gem_cma_obj(gem);
> +       }
> +
> +       memset(&req, 0, sizeof(req));
> +       req.crtc_x = crtc->cursor.x;
> +       req.crtc_y = crtc->cursor.y;
> +       req.crtc_h = height;
> +       req.crtc_w = width;
> +       req.src_x = 0;
> +       req.src_y = 0;
> +       req.src_w = req.crtc_w << 16;
> +       req.src_h = req.crtc_h << 16;
> +       req.pixel_format = DRM_FORMAT_ARGB8888;
> +       req.gems[0] = cma_gem;
> +       req.offsets[0] = 0;
> +       req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) * width;
> +       req.crtc = c;
> +
> +       if (!req.gems[0] || !req.src_h || !req.src_w) {
> +               cma_gem = crtc->cursor.gem;
> +               ret = plane->base.funcs->disable_plane(&plane->base);
> +               if (!ret && cma_gem) {
> +                       drm_gem_object_unreference_unlocked(&cma_gem->base);
> +                       crtc->cursor.gem = NULL;
> +               }
> +
> +               goto out;
> +       }
> +
> +       ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
> +       if (ret)
> +               goto err_release_gem;
> +
> +       ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
> +       if (ret)
> +               goto err_release_gem;
> +
> +       crtc->cursor.height = width;
> +       crtc->cursor.width = width;
> +       if (crtc->cursor.gem)
> +               drm_gem_object_unreference_unlocked(&crtc->cursor.gem->base);
> +       crtc->cursor.gem = cma_gem;
> +
> +       goto out;
> +
> +err_release_gem:
> +       if (cma_gem)
> +               drm_gem_object_unreference_unlocked(&cma_gem->base);
> +
> +out:
> +       mutex_unlock(&crtc->cursor.lock);
> +       return ret;
> +}
> +
> +static int atmel_hlcdc_crtc_cursor_move(struct drm_crtc *c, int x, int y)
> +{
> +       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
> +       struct atmel_hlcdc_plane *plane = crtc->cursor.plane;
> +       struct atmel_hlcdc_plane_update_req req;
> +       int ret;
> +
> +       if (unlikely(!plane))
> +               return -ENOTSUPP;
> +
> +       mutex_lock(&crtc->cursor.lock);
> +
> +       memset(&req, 0, sizeof(req));
> +       req.crtc_x = x;
> +       req.crtc_y = y;
> +       req.crtc_h = crtc->cursor.height;
> +       req.crtc_w = crtc->cursor.width;
> +       req.src_x = 0;
> +       req.src_y = 0;
> +       req.src_w = req.crtc_w << 16;
> +       req.src_h = req.crtc_h << 16;
> +       req.pixel_format = DRM_FORMAT_ARGB8888;
> +       req.gems[0] = crtc->cursor.gem;
> +       req.offsets[0] = 0;
> +       req.pitches[0] = drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0) *
> +                        crtc->cursor.width;
> +       req.crtc = c;
> +
> +       if (!req.gems[0] || !req.src_h || !req.src_w) {
> +               struct drm_gem_cma_object *cma_gem = crtc->cursor.gem;
> +
> +               ret = plane->base.funcs->disable_plane(&plane->base);
> +               if (!ret && cma_gem) {
> +                       drm_gem_object_unreference_unlocked(&cma_gem->base);
> +                       crtc->cursor.gem = NULL;
> +               }
> +
> +               goto out;
> +       }
> +
> +       ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
> +       if (ret)
> +               goto out;
> +
> +       ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
> +       if (ret)
> +               goto out;
> +
> +       crtc->cursor.x = x;
> +       crtc->cursor.y = y;
> +
> +out:
> +       mutex_unlock(&crtc->cursor.lock);
> +       return ret;
> +}
> +
> +static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
> +       .page_flip = atmel_hlcdc_crtc_page_flip,
> +       .set_config = drm_crtc_helper_set_config,
> +       .destroy = atmel_hlcdc_crtc_destroy,
> +};
> +
> +static const struct drm_crtc_funcs atmel_hlcdc_crtc_with_cursor_funcs = {
> +       .page_flip = atmel_hlcdc_crtc_page_flip,
> +       .set_config = drm_crtc_helper_set_config,
> +       .destroy = atmel_hlcdc_crtc_destroy,
> +       .cursor_set = atmel_hlcdc_crtc_cursor_set,
> +       .cursor_move = atmel_hlcdc_crtc_cursor_move,
> +};
> +
> +int atmel_hlcdc_crtc_create(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       struct atmel_hlcdc_planes *planes = dc->planes;
> +       const struct drm_crtc_funcs *funcs;
> +       struct atmel_hlcdc_crtc *crtc;
> +       int ret;
> +       int i;
> +
> +       crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc) {
> +               dev_err(dev->dev, "allocation failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       mutex_init(&crtc->cursor.lock);
> +       crtc->hlcdc = dc->hlcdc;
> +       crtc->cursor.plane = planes->cursor;
> +
> +       if (planes->cursor)
> +               funcs = &atmel_hlcdc_crtc_with_cursor_funcs;
> +       else
> +               funcs = &atmel_hlcdc_crtc_funcs;
> +
> +       ret = drm_crtc_init_with_planes(dev, &crtc->base,
> +                               &planes->primary->base,
> +                               planes->cursor ? &planes->cursor->base : NULL,
> +                               funcs);
> +       if (ret < 0)
> +               goto fail;
> +
> +       crtc->id = drm_crtc_index(&crtc->base);
> +
> +       if (planes->cursor)
> +               planes->cursor->base.possible_crtcs = 1 << crtc->id;
> +
> +       for (i = 0; i < planes->noverlays; i++)
> +               planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
> +
> +       drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
> +
> +       return 0;
> +
> +fail:
> +       atmel_hlcdc_crtc_destroy(&crtc->base);
> +       return ret;
> +}
> +
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> new file mode 100644
> index 0000000..bfecd0d
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> @@ -0,0 +1,474 @@
> +/*
> + * Copyright (C) 2014 Traphandler
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "atmel_hlcdc_dc.h"
> +
> +#define ATMEL_HLCDC_LAYER_IRQS_OFFSET          8
> +
> +static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
> +       {
> +               .name = "base",
> +               .formats = &atmel_hlcdc_plane_rgb_formats,
> +               .regs_offset = 0x40,
> +               .id = 0,
> +               .type = ATMEL_HLCDC_BASE_LAYER,
> +               .nconfigs = 7,
> +               .layout = {
> +                       .xstride = { 2 },
> +                       .default_color = 3,
> +                       .general_config = 4,
> +                       .disc_pos = 5,
> +                       .disc_size = 6,
> +               },
> +       },
> +       {
> +               .name = "overlay1",
> +               .formats = &atmel_hlcdc_plane_rgb_formats,
> +               .regs_offset = 0x140,
> +               .id = 1,
> +               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> +               .nconfigs = 10,
> +               .layout = {
> +                       .pos = 2,
> +                       .size = 3,
> +                       .xstride = { 4 },
> +                       .pstride = { 5 },
> +                       .default_color = 6,
> +                       .chroma_key = 7,
> +                       .chroma_key_mask = 8,
> +                       .general_config = 9,
> +               },
> +       },
> +       {
> +               .name = "overlay2",
> +               .formats = &atmel_hlcdc_plane_rgb_formats,
> +               .regs_offset = 0x240,
> +               .id = 2,
> +               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> +               .nconfigs = 10,
> +               .layout = {
> +                       .pos = 2,
> +                       .size = 3,
> +                       .xstride = { 4 },
> +                       .pstride = { 5 },
> +                       .default_color = 6,
> +                       .chroma_key = 7,
> +                       .chroma_key_mask = 8,
> +                       .general_config = 9,
> +               },
> +       },
> +       {
> +               .name = "high-end-overlay",
> +               .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
> +               .regs_offset = 0x340,
> +               .id = 3,
> +               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> +               .nconfigs = 42,
> +               .layout = {
> +                       .pos = 2,
> +                       .size = 3,
> +                       .memsize = 4,
> +                       .xstride = { 5, 7 },
> +                       .pstride = { 6, 8 },
> +                       .default_color = 9,
> +                       .chroma_key = 10,
> +                       .chroma_key_mask = 11,
> +                       .general_config = 12,
> +                       .csc = 14,
> +               },
> +       },
> +       {
> +               .name = "cursor",
> +               .formats = &atmel_hlcdc_plane_rgb_formats,
> +               .regs_offset = 0x440,
> +               .id = 4,
> +               .type = ATMEL_HLCDC_CURSOR_LAYER,
> +               .nconfigs = 10,
> +               .max_width = 128,
> +               .max_height = 128,
> +               .layout = {
> +                       .pos = 2,
> +                       .size = 3,
> +                       .xstride = { 4 },
> +                       .pstride = { 5 },
> +                       .default_color = 6,
> +                       .chroma_key = 7,
> +                       .chroma_key_mask = 8,
> +                       .general_config = 9,
> +               },
> +       },
> +};
> +
> +static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
> +       .min_width = 0,
> +       .min_height = 0,
> +       .max_width = 2048,
> +       .max_height = 2048,
> +       .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
> +       .layers = atmel_hlcdc_sama5d3_layers,
> +};
> +
> +static const struct of_device_id atmel_hlcdc_of_match[] = {
> +       {
> +               .compatible = "atmel,sama5d3-hlcdc",
> +               .data = &atmel_hlcdc_dc_sama5d3,
> +       },
> +       { /* sentinel */ },
> +};
> +
> +static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
> +{
> +       struct drm_device *dev = data;
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       unsigned long status;
> +       unsigned int imr, isr;
> +       int bit;
> +
> +       regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
> +       regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
> +       status = imr & isr;
> +       if (!status)
> +               return IRQ_NONE;
> +
> +       bit = ATMEL_HLCDC_LAYER_IRQS_OFFSET;
> +       for_each_set_bit_from(bit, &status, ATMEL_HLCDC_LAYER_IRQS_OFFSET +
> +                                           ATMEL_HLCDC_MAX_LAYERS) {
> +               int layerid = bit - ATMEL_HLCDC_LAYER_IRQS_OFFSET;
> +               struct atmel_hlcdc_layer *layer = dc->layers[layerid];
> +
> +               if (layer)
> +                       atmel_hlcdc_layer_irq(layer);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
> +               struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +       return drm_fb_cma_create(dev, file_priv, mode_cmd);
> +}
> +
> +static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +
> +       if (dc->fbdev) {
> +               drm_fbdev_cma_hotplug_event(dc->fbdev);
> +       } else {
> +               dc->fbdev = drm_fbdev_cma_init(dev, 24,
> +                               dev->mode_config.num_crtc,
> +                               dev->mode_config.num_connector);
> +               if (IS_ERR(dc->fbdev))
> +                       dc->fbdev = NULL;
> +       }
> +}
> +
> +static const struct drm_mode_config_funcs mode_config_funcs = {
> +       .fb_create = atmel_hlcdc_fb_create,
> +       .output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
> +};
> +
> +static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       struct atmel_hlcdc_planes *planes;
> +       int ret;
> +       int i;
> +
> +       drm_mode_config_init(dev);
> +
> +       ret = atmel_hlcdc_panel_create(dev);
> +       if (ret) {
> +               dev_err(dev->dev, "failed to create panel: %d\n", ret);
> +               return ret;
> +       }
> +
> +       planes = atmel_hlcdc_create_planes(dev);
> +       if (IS_ERR(planes)) {
> +               dev_err(dev->dev, "failed to create planes\n");
> +               return PTR_ERR(planes);
> +       }
> +
> +       dc->planes = planes;
> +
> +       dc->layers[planes->primary->layer.desc->id] =
> +                                               &planes->primary->layer;
> +
> +       if (planes->cursor)
> +               dc->layers[planes->cursor->layer.desc->id] =
> +                                                       &planes->cursor->layer;
> +
> +       for (i = 0; i < planes->noverlays; i++)
> +               dc->layers[planes->overlays[i]->layer.desc->id] =
> +                                               &planes->overlays[i]->layer;
> +
> +       ret = atmel_hlcdc_crtc_create(dev);
> +       if (ret) {
> +               dev_err(dev->dev, "failed to create crtc\n");
> +               return ret;
> +       }
> +
> +       dev->mode_config.min_width = dc->desc->min_width;
> +       dev->mode_config.min_height = dc->desc->min_height;
> +       dev->mode_config.max_width = dc->desc->max_width;
> +       dev->mode_config.max_height = dc->desc->max_height;
> +       dev->mode_config.funcs = &mode_config_funcs;
> +
> +       return 0;
> +}
> +
> +static int atmel_hlcdc_dc_load(struct drm_device *dev, unsigned long flags)
> +{
> +       struct platform_device *pdev = dev->platformdev;
> +       const struct of_device_id *match;
> +       struct atmel_hlcdc_dc *dc;
> +       int ret;
> +
> +       match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
> +       if (!match) {
> +               dev_err(&pdev->dev, "invalid compatible string\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!match->data) {
> +               dev_err(&pdev->dev, "invalid hlcdc description\n");
> +               return -EINVAL;
> +       }
> +
> +       dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
> +       if (!dc) {
> +               dev_err(dev->dev, "failed to allocate private data\n");
> +               return -ENOMEM;
> +       }
> +
> +       dc->desc = match->data;
> +       dc->hlcdc = dev_get_drvdata(dev->dev->parent);
> +       dev->dev_private = dc;
> +
> +       ret = clk_prepare_enable(dc->hlcdc->periph_clk);
> +       if (ret) {
> +               dev_err(dev->dev, "failed to enable periph_clk\n");
> +               return ret;
> +       }
> +
> +       pm_runtime_enable(dev->dev);
> +
> +       pm_runtime_put_sync(dev->dev);
> +
> +       ret = atmel_hlcdc_dc_modeset_init(dev);
> +       if (ret < 0) {
> +               dev_err(dev->dev, "failed to initialize mode setting\n");
> +               goto err_periph_clk_disable;
> +       }
> +
> +       ret = drm_vblank_init(dev, 1);
> +       if (ret < 0) {
> +               dev_err(dev->dev, "failed to initialize vblank\n");
> +               goto err_periph_clk_disable;
> +       }
> +
> +       pm_runtime_get_sync(dev->dev);
> +       ret = drm_irq_install(dev);
> +       pm_runtime_put_sync(dev->dev);
> +       if (ret < 0) {
> +               dev_err(dev->dev, "failed to install IRQ handler\n");
> +               goto err_periph_clk_disable;
> +       }
> +
> +       platform_set_drvdata(pdev, dev);
> +
> +       drm_kms_helper_poll_init(dev);
> +
> +       /* force connectors detection */
> +       drm_helper_hpd_irq_event(dev);
> +
> +       return 0;
> +
> +err_periph_clk_disable:
> +       clk_disable_unprepare(dc->hlcdc->periph_clk);
> +
> +       return ret;
> +}
> +
> +static int atmel_hlcdc_dc_unload(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +
> +       drm_kms_helper_poll_fini(dev);
> +       drm_mode_config_cleanup(dev);
> +       drm_vblank_cleanup(dev);
> +
> +       pm_runtime_get_sync(dev->dev);
> +       drm_irq_uninstall(dev);
> +       pm_runtime_put_sync(dev->dev);
> +
> +       dev->dev_private = NULL;
> +
> +       pm_runtime_disable(dev->dev);
> +       clk_disable_unprepare(dc->hlcdc->periph_clk);
> +
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_dc_preclose(struct drm_device *dev,
> +                                   struct drm_file *file)
> +{
> +       struct drm_crtc *crtc;
> +
> +       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
> +               atmel_hlcdc_crtc_cancel_page_flip(crtc, file);
> +}
> +
> +static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +
> +       drm_fbdev_cma_restore_mode(dc->fbdev);
> +}
> +
> +static void atmel_hlcdc_dc_irq_preinstall(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       unsigned int isr;
> +
> +       regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
> +       regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
> +}
> +
> +static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       int i;
> +
> +       /* Enable interrupts on activated layers */
> +       for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
> +               if (dc->layers[i])
> +                       regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER,
> +                                    BIT(i + 8));
> +       }
> +
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
> +{
> +
> +}
> +
> +static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc)
> +{
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc)
> +{
> +}
> +
> +static const struct file_operations 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 atmel_hlcdc_dc_driver = {
> +       .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
> +       .load = atmel_hlcdc_dc_load,
> +       .unload = atmel_hlcdc_dc_unload,
> +       .preclose = atmel_hlcdc_dc_preclose,
> +       .lastclose = atmel_hlcdc_dc_lastclose,
> +       .irq_handler = atmel_hlcdc_dc_irq_handler,
> +       .irq_preinstall = atmel_hlcdc_dc_irq_preinstall,
> +       .irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
> +       .irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
> +       .get_vblank_counter = drm_vblank_count,
> +       .enable_vblank = atmel_hlcdc_dc_enable_vblank,
> +       .disable_vblank = atmel_hlcdc_dc_disable_vblank,
> +       .gem_free_object = drm_gem_cma_free_object,
> +       .gem_vm_ops = &drm_gem_cma_vm_ops,
> +       .dumb_create = drm_gem_cma_dumb_create,
> +       .dumb_map_offset = drm_gem_cma_dumb_map_offset,
> +       .dumb_destroy = drm_gem_dumb_destroy,
> +       .fops = &fops,
> +       .name = "atmel-hlcdc",
> +       .desc = "Atmel HLCD Controller DRM",
> +       .date = "20141504",
> +       .major = 1,
> +       .minor = 0,
> +};
> +
> +static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +
> +       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
> +       if (ret)
> +               return ret;
> +
> +       ret = drm_platform_init(&atmel_hlcdc_dc_driver, pdev);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
> +{
> +       drm_put_dev(platform_get_drvdata(pdev));
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
> +       { .compatible = "atmel,hlcdc-dc" },
> +       { },
> +};
> +
> +static struct platform_driver atmel_hlcdc_dc_platform_driver = {
> +       .probe  = atmel_hlcdc_dc_drm_probe,
> +       .remove = atmel_hlcdc_dc_drm_remove,
> +       .driver = {
> +               .name   = "atmel-hlcdc-dc",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = atmel_hlcdc_dc_of_match,
> +       },
> +};
> +module_platform_driver(atmel_hlcdc_dc_platform_driver);
> +
> +MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
> +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
> +MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:atmel-hlcdc-dc");
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> new file mode 100644
> index 0000000..1386998
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> @@ -0,0 +1,210 @@
> +/*
> + * Copyright (C) 2014 Traphandler
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef DRM_ATMEL_HLCDC_H
> +#define DRM_ATMEL_HLCDC_H
> +
> +#include <linux/clk.h>
> +#include <linux/irqdomain.h>
> +#include <linux/pwm.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_panel.h>
> +#include <drm/drmP.h>
> +
> +#include "atmel_hlcdc_layer.h"
> +
> +#define ATMEL_HLCDC_MAX_LAYERS         5
> +
> +/**
> + * Atmel HLCDC Display Controller description structure.
> + *
> + * This structure describe the HLCDC IP capabilities and depends on the
> + * HLCDC IP version (or Atmel SoC family).
> + *
> + * @min_width: minimum width supported by the Display Controller
> + * @min_height: minimum height supported by the Display Controller
> + * @max_width: maximum width supported by the Display Controller
> + * @max_height: maximum height supported by the Display Controller
> + * @layer: a layer description table describing available layers
> + * @nlayers: layer description table size
> + */
> +struct atmel_hlcdc_dc_desc {
> +       int min_width;
> +       int min_height;
> +       int max_width;
> +       int max_height;
> +       const struct atmel_hlcdc_layer_desc *layers;
> +       int nlayers;
> +};
> +
> +/**
> + * Atmel HLCDC Plane properties.
> + *
> + * This structure stores plane property definitions.
> + *
> + * @alpha: alpha blending (or transparency) property
> + * @csc: YUV to RGB conversion factors property
> + */
> +struct atmel_hlcdc_plane_properties {
> +       struct drm_property *alpha;
> +       struct drm_property *csc;

appears like csc is not used yet, so I suppose you can drop it for
now..  when you do add it, don't forget to update drm.tmp.  But for
now it at least makes review easier when the driver doesn't add new
userspace interfaces :-)

> +};
> +
> +/**
> + * Atmel HLCDC Plane.
> + *
> + * @base: base DRM plane structure
> + * @layer: HLCDC layer structure
> + * @properties: pointer to the property definitions structure
> + * @alpha: current alpha blending (or transparency) status
> + */
> +struct atmel_hlcdc_plane {
> +       struct drm_plane base;
> +       struct atmel_hlcdc_layer layer;
> +       struct atmel_hlcdc_plane_properties *properties;
> +};
> +
> +static inline struct atmel_hlcdc_plane *
> +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> +{
> +       return container_of(p, struct atmel_hlcdc_plane, base);
> +}
> +
> +static inline struct atmel_hlcdc_plane *
> +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> +{
> +       return container_of(l, struct atmel_hlcdc_plane, layer);
> +}
> +
> +/**
> + * Atmel HLCDC Plane update request structure.
> + *
> + * @crtc_x: x position of the plane relative to the CRTC
> + * @crtc_y: y position of the plane relative to the CRTC
> + * @crtc_w: visible width of the plane
> + * @crtc_h: visible height of the plane
> + * @src_x: x buffer position
> + * @src_y: y buffer position
> + * @src_w: buffer width
> + * @src_h: buffer height
> + * @pixel_format: pixel format
> + * @gems: GEM object object containing image buffers
> + * @offsets: offsets to apply to the GEM buffers
> + * @pitches: line size in bytes
> + * @crtc: crtc to display on
> + * @finished: finished callback
> + * @finished_data: data passed to the finished callback
> + * @bpp: bytes per pixel deduced from pixel_format
> + * @xstride: value to add to the pixel pointer between each line
> + * @pstride: value to add to the pixel pointer between each pixel
> + * @nplanes: number of planes (deduced from pixel_format)
> + */
> +struct atmel_hlcdc_plane_update_req {
> +       int crtc_x;
> +       int crtc_y;
> +       unsigned int crtc_w;
> +       unsigned int crtc_h;
> +       uint32_t src_x;
> +       uint32_t src_y;
> +       uint32_t src_w;
> +       uint32_t src_h;
> +       uint32_t pixel_format;
> +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];

tbh, I've only looked closely, but I don't completely follow all the
layering here..  I wonder if we'd be better off just moving 'struct
drm_fb_cma' to header file so you could get the gem objects / pixel
fmt / width / height directly from the fb object (and then you can
reference count things at the fb level, rather than at the individual
gem obj level, too)

BR,
-R

> +       struct drm_crtc *crtc;
> +       void (*finished)(void *data);
> +       void *finished_data;
> +
> +       /* These fields are private and should not be touched */
> +       int bpp[ATMEL_HLCDC_MAX_PLANES];
> +       int xstride[ATMEL_HLCDC_MAX_PLANES];
> +       int pstride[ATMEL_HLCDC_MAX_PLANES];
> +       int nplanes;
> +};
> +
> +/**
> + * Atmel HLCDC Planes.
> + *
> + * This structure stores the instantiated HLCDC Planes and can be accessed by
> + * the HLCDC Display Controller or the HLCDC CRTC.
> + *
> + * @primary: primary plane
> + * @cursor: hardware cursor plane
> + * @overlays: overlay plane table
> + * @noverlays: number of overlay planes
> + */
> +struct atmel_hlcdc_planes {
> +       struct atmel_hlcdc_plane *primary;
> +       struct atmel_hlcdc_plane *cursor;
> +       struct atmel_hlcdc_plane **overlays;
> +       int noverlays;
> +};
> +
> +/**
> + * Atmel HLCDC Display Controller.
> + *
> + * @desc: HLCDC Display Controller description
> + * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
> + * @fbdev: framebuffer device attached to the Display Controller
> + * @planes: instantiated planes
> + * @layers: active HLCDC layer
> + */
> +struct atmel_hlcdc_dc {
> +       const struct atmel_hlcdc_dc_desc *desc;
> +       struct atmel_hlcdc *hlcdc;
> +       struct drm_fbdev_cma *fbdev;
> +       struct atmel_hlcdc_planes *planes;
> +       struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
> +};
> +
> +extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
> +extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
> +
> +struct atmel_hlcdc_planes *
> +atmel_hlcdc_create_planes(struct drm_device *dev);
> +
> +int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
> +                               struct atmel_hlcdc_plane_update_req *req);
> +
> +int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
> +                               struct atmel_hlcdc_plane_update_req *req);
> +
> +void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
> +                                      struct drm_file *file);
> +
> +int atmel_hlcdc_crtc_create(struct drm_device *dev);
> +
> +int atmel_hlcdc_panel_create(struct drm_device *dev);
> +
> +struct atmel_hlcdc_pwm_chip *atmel_hlcdc_pwm_create(struct drm_device *dev,
> +                                                   struct clk *slow_clk,
> +                                                   struct clk *sys_clk,
> +                                                   void __iomem *regs);
> +
> +int atmel_hlcdc_pwm_destroy(struct drm_device *dev,
> +                           struct atmel_hlcdc_pwm_chip *chip);
> +
> +#endif /* DRM_ATMEL_HLCDC_H */
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> new file mode 100644
> index 0000000..57c50ec
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> @@ -0,0 +1,706 @@
> +/*
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +
> +#include "atmel_hlcdc_dc.h"
> +
> +static void
> +atmel_hlcdc_layer_gem_flip_release(struct atmel_hlcdc_layer *layer,
> +                                  struct atmel_hlcdc_layer_gem_flip *flip)
> +{
> +       int i;
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (!flip->gems[i])
> +                       break;
> +
> +               drm_gem_object_unreference_unlocked(flip->gems[i]);
> +       }
> +
> +       kfree(flip);
> +}
> +
> +static void atmel_hlcdc_layer_gc_work(struct work_struct *work)
> +{
> +       struct atmel_hlcdc_layer_gem_flip_gc *gc =
> +                       container_of(work,
> +                                    struct atmel_hlcdc_layer_gem_flip_gc,
> +                                    work);
> +       struct atmel_hlcdc_layer *layer =
> +                       container_of(gc , struct atmel_hlcdc_layer, gc);
> +
> +       while (true) {
> +               struct atmel_hlcdc_layer_gem_flip *flip;
> +               unsigned long flags;
> +
> +               spin_lock_irqsave(&gc->list_lock, flags);
> +               flip = list_first_entry_or_null(&gc->list,
> +                                       struct atmel_hlcdc_layer_gem_flip,
> +                                       node);
> +               if (flip)
> +                       list_del(&flip->node);
> +               spin_unlock_irqrestore(&gc->list_lock, flags);
> +
> +               if (!flip)
> +                       break;
> +
> +               atmel_hlcdc_layer_gem_flip_release(layer, flip);
> +       }
> +}
> +
> +static void
> +atmel_hlcdc_layer_gem_flip_put(struct atmel_hlcdc_layer *layer,
> +                              struct atmel_hlcdc_layer_gem_flip *flip)
> +{
> +       struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
> +       unsigned long flags;
> +
> +       if (--flip->remaining_gems <= 0) {
> +               spin_lock_irqsave(&gc->list_lock, flags);
> +               list_add_tail(&flip->node,
> +                             &gc->list);
> +               spin_unlock_irqrestore(&gc->list_lock, flags);
> +               schedule_work(&gc->work);
> +       }
> +}
> +
> +static void atmel_hlcdc_layer_start_queue(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> +       struct regmap *regmap = layer->hlcdc->regmap;
> +       int i;
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               dma->cur[i] = dma->queue[i];
> +               if (!dma->queue[i])
> +                       continue;
> +               dma->queue[i] = NULL;
> +
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
> +                            dma->cur[i]->addr);
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
> +                            dma->cur[i]->ctrl);
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
> +                            dma->cur[i]->next);
> +       }
> +}
> +
> +static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
> +{
> +       const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct regmap *regmap = layer->hlcdc->regmap;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +       unsigned int cfg;
> +       u32 action = 0;
> +       int i;
> +
> +       if (upd->pending < 0 || upd->pending > 1)
> +               return;
> +
> +       slot = &upd->slots[upd->pending];
> +
> +       for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_CFG(layer, cfg),
> +                            slot->configs[cfg]);
> +               action |= ATMEL_HLCDC_LAYER_UPDATE;
> +       }
> +
> +       if (slot->gem_flip && slot->gem_flip->remaining_gems) {
> +               struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +
> +               for (i = 0; i < layer->max_planes; i++) {
> +                       struct atmel_hlcdc_dma_channel_dscr *dscr;
> +
> +                       if (!slot->gem_flip->gems[i])
> +                               break;
> +
> +                       dscr =  slot->dscrs[i];
> +                       slot->dscrs[i] = NULL;
> +
> +                       if (!dma->enabled) {
> +                               action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
> +                               regmap_write(regmap,
> +                                            desc->regs_offset +
> +                                            ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
> +                                            dscr->addr);
> +                               regmap_write(regmap,
> +                                            desc->regs_offset +
> +                                            ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
> +                                            dscr->ctrl);
> +                               regmap_write(regmap,
> +                                            desc->regs_offset +
> +                                            ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
> +                                            dscr->next);
> +                               dma->cur[i] = dscr;
> +                       } else {
> +                               action |= ATMEL_HLCDC_LAYER_A2Q;
> +                               regmap_write(regmap,
> +                                            desc->regs_offset +
> +                                            ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
> +                                            dscr->next);
> +                               dma->queue[i] = dscr;
> +                       }
> +               }
> +
> +               dma->enabled = true;
> +               slot->gem_flip = NULL;
> +       }
> +
> +       if (action)
> +               regmap_write(regmap,
> +                            desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
> +                            action);
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (!slot->dscrs[i])
> +                       continue;
> +
> +               slot->dscrs[i]->gem_flip = NULL;
> +               slot->dscrs[i] = NULL;
> +       }
> +
> +       if (slot->gem_flip) {
> +               atmel_hlcdc_layer_gem_flip_put(layer, slot->gem_flip);
> +               slot->gem_flip = NULL;
> +       }
> +
> +       bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
> +       memset(slot->configs, 0,
> +              sizeof(*slot->configs) * layer->desc->nconfigs);
> +
> +       upd->pending = -1;
> +}
> +
> +static bool
> +atmel_hlcdc_layer_dma_channel_active(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       int i;
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (dma->cur[i])
> +                       return true;
> +       }
> +
> +       return false;
> +}
> +
> +void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_gem_flip *flip_gc[ATMEL_HLCDC_MAX_PLANES];
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> +       struct atmel_hlcdc_layer_gem_flip *flip = NULL;
> +       struct regmap *regmap = layer->hlcdc->regmap;
> +       struct atmel_hlcdc_dma_channel_dscr *dscr;
> +       unsigned long flags;
> +       unsigned int isr, imr;
> +       unsigned int status;
> +
> +       int i;
> +
> +       regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
> +       regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
> +       status = imr & isr;
> +       if (!status)
> +               return;
> +
> +       memset(flip_gc, 0, sizeof(flip_gc));
> +
> +       spin_lock_irqsave(&dma->lock, flags);
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if ((status & ATMEL_HLCDC_LAYER_DONE_IRQ(i)) ||
> +                   (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i))) {
> +                       dscr = dma->cur[i];
> +                       dma->cur[i] = NULL;
> +                       flip_gc[i] = dscr->gem_flip;
> +                       dscr->gem_flip = NULL;
> +               }
> +
> +               if (status & ATMEL_HLCDC_LAYER_ADD_IRQ(i)) {
> +                       dma->cur[i] = dma->queue[i];
> +                       flip = dma->queue[i]->gem_flip;
> +                       dma->queue[i] = NULL;
> +               }
> +       }
> +
> +       if (flip && flip->finished &&
> +           !atmel_hlcdc_layer_dma_channel_busy(layer))
> +               flip->finished(flip->finished_data);
> +
> +       /*
> +        * The DMA channel might have been disabled before we were able to
> +        * add the new frame to the DMA transfer queue.
> +        * Try to re-enable the channel in this case.
> +        */
> +       if (!atmel_hlcdc_layer_dma_channel_active(layer)) {
> +               if (atmel_hlcdc_layer_dma_channel_busy(layer)) {
> +                       atmel_hlcdc_layer_start_queue(layer);
> +
> +                       regmap_write(regmap,
> +                                    desc->regs_offset +
> +                                    ATMEL_HLCDC_LAYER_CHDR,
> +                                    ATMEL_HLCDC_LAYER_A2Q);
> +                       regmap_write(regmap,
> +                                    desc->regs_offset +
> +                                    ATMEL_HLCDC_LAYER_CHER,
> +                                    ATMEL_HLCDC_LAYER_DMA_CHAN);
> +               } else {
> +                       dma->enabled = false;
> +               }
> +       }
> +
> +       if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
> +               struct atmel_hlcdc_layer_update *upd = &layer->update;
> +
> +               spin_lock(&upd->pending_lock);
> +               atmel_hlcdc_layer_update_apply(layer);
> +               spin_unlock(&upd->pending_lock);
> +       }
> +       spin_unlock_irqrestore(&dma->lock, flags);
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (!flip_gc[i])
> +                       break;
> +
> +               atmel_hlcdc_layer_gem_flip_put(layer, flip_gc[i]);
> +       }
> +}
> +
> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       unsigned long flags;
> +       int i;
> +
> +       spin_lock_irqsave(&dma->lock, flags);
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (!dma->cur[i])
> +                       break;
> +
> +               dma->cur[i]->ctrl = 0;
> +       }
> +       spin_unlock_irqrestore(&dma->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +       unsigned long flags;
> +       int i;
> +
> +       if (upd->next < 0 || upd->next > 1)
> +               return;
> +
> +       slot = &upd->slots[upd->next];
> +       bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
> +       memset(slot->configs, 0,
> +              sizeof(*slot->configs) * layer->desc->nconfigs);
> +
> +       spin_lock_irqsave(&dma->lock, flags);
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (!slot->dscrs[i])
> +                       break;
> +               slot->dscrs[i]->gem_flip = NULL;
> +               slot->dscrs[i] = NULL;
> +       }
> +       spin_unlock_irqrestore(&layer->dma.lock, flags);
> +
> +       if (slot->gem_flip) {
> +               atmel_hlcdc_layer_gem_flip_release(layer, slot->gem_flip);
> +               slot->gem_flip = NULL;
> +       }
> +
> +       upd->next = -1;
> +}
> +
> +int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct regmap *regmap = layer->hlcdc->regmap;
> +       struct atmel_hlcdc_layer_gem_flip *gem_flip;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +       unsigned long flags;
> +       int i, j = 0;
> +       int pending;
> +
> +       gem_flip = kzalloc(sizeof(*gem_flip), GFP_KERNEL);
> +       if (!gem_flip)
> +               return -ENOMEM;
> +
> +       mutex_lock(&upd->lock);
> +
> +       spin_lock_irqsave(&upd->pending_lock, flags);
> +       pending = upd->pending;
> +       spin_unlock_irqrestore(&upd->pending_lock, flags);
> +
> +       upd->next = pending ? 0 : 1;
> +
> +       slot = &upd->slots[upd->next];
> +
> +       spin_lock_irqsave(&dma->lock, flags);
> +       for (i = 0; i < layer->max_planes * 4; i++) {
> +               if (!dma->dscrs[i].gem_flip) {
> +                       slot->dscrs[j++] = &dma->dscrs[i];
> +                       dma->dscrs[i].gem_flip = gem_flip;
> +                       if (j == layer->max_planes)
> +                               break;
> +               }
> +       }
> +
> +       if (j < layer->max_planes) {
> +               for (i = 0; i < j; i++)
> +                       slot->dscrs[i]->gem_flip = NULL;
> +       }
> +       spin_unlock_irqrestore(&layer->dma.lock, flags);
> +
> +       if (j < layer->max_planes) {
> +               mutex_unlock(&upd->lock);
> +               kfree(gem_flip);
> +               return -EBUSY;
> +       }
> +
> +       slot->gem_flip = gem_flip;
> +
> +       spin_lock_irqsave(&upd->pending_lock, flags);
> +       pending = upd->pending;
> +       if (pending >= 0) {
> +               memcpy(upd->slots[upd->next].configs,
> +                      upd->slots[upd->pending].configs,
> +                      layer->desc->nconfigs * sizeof(u32));
> +               memcpy(upd->slots[upd->next].updated_configs,
> +                      upd->slots[upd->pending].updated_configs,
> +                      DIV_ROUND_UP(layer->desc->nconfigs,
> +                                   BITS_PER_BYTE * sizeof(unsigned long)) *
> +                      sizeof(unsigned long));
> +       }
> +       spin_unlock_irqrestore(&upd->pending_lock, flags);
> +
> +       if (pending < 0) {
> +               regmap_bulk_read(regmap,
> +                                layer->desc->regs_offset +
> +                                ATMEL_HLCDC_LAYER_CFG(layer, 0),
> +                                upd->slots[upd->next].configs,
> +                                layer->desc->nconfigs);
> +       }
> +
> +       return 0;
> +}
> +
> +void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +
> +       atmel_hlcdc_layer_update_reset(layer);
> +       mutex_unlock(&upd->lock);
> +}
> +
> +void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
> +                                     int plane_id,
> +                                     struct drm_gem_cma_object *gem,
> +                                     unsigned int offset)
> +{
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct atmel_hlcdc_layer_gem_flip *gem_flip;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +       struct atmel_hlcdc_dma_channel_dscr *dscr;
> +       struct drm_gem_object *old_gem;
> +
> +       if (upd->next < 0 || upd->next > 1)
> +               return;
> +
> +       if (plane_id >= layer->max_planes || plane_id < 0)
> +               return;
> +
> +       slot = &upd->slots[upd->next];
> +       dscr = slot->dscrs[plane_id];
> +       dscr->addr = gem->paddr + offset;
> +       dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
> +       gem_flip = dscr->gem_flip;
> +
> +       old_gem = gem_flip->gems[plane_id];
> +
> +       if (gem) {
> +               drm_gem_object_reference(&gem->base);
> +               gem_flip->gems[plane_id] = &gem->base;
> +               gem_flip->remaining_gems++;
> +       } else {
> +               gem_flip->gems[plane_id] = NULL;
> +       }
> +
> +       if (old_gem) {
> +               drm_gem_object_unreference_unlocked(old_gem);
> +               gem_flip->remaining_gems--;
> +       }
> +}
> +
> +void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
> +                                          void (*finished)(void *data),
> +                                          void *finished_data)
> +{
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +
> +       if (upd->next < 0 || upd->next > 1)
> +               return;
> +
> +       slot = &upd->slots[upd->next];
> +
> +       slot->gem_flip->finished = finished;
> +       slot->gem_flip->finished_data = finished_data;
> +}
> +
> +void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
> +                                 u32 mask, u32 val)
> +{
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +
> +       if (upd->next < 0 || upd->next > 1)
> +               return;
> +
> +       if (cfg >= layer->desc->nconfigs)
> +               return;
> +
> +       slot = &upd->slots[upd->next];
> +       slot->configs[cfg] &= ~mask;
> +       slot->configs[cfg] |= (val & mask);
> +       set_bit(cfg, slot->updated_configs);
> +}
> +
> +void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       struct atmel_hlcdc_layer_update_slot *slot;
> +       unsigned long flags;
> +       int pending;
> +
> +       if (upd->next < 0  || upd->next > 1)
> +               return;
> +
> +       slot = &upd->slots[upd->next];
> +
> +       spin_lock_irqsave(&upd->pending_lock, flags);
> +       pending = upd->pending;
> +       upd->pending = upd->next;
> +       upd->next = pending;
> +       if (pending >= 0 && !slot->gem_flip->remaining_gems) {
> +               struct atmel_hlcdc_layer_gem_flip *gem_flip = slot->gem_flip;
> +               struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
> +
> +               memcpy(dscrs, slot->dscrs, sizeof(dscrs));
> +               slot->gem_flip = upd->slots[pending].gem_flip;
> +               memcpy(slot->dscrs, upd->slots[pending].dscrs,
> +                      sizeof(slot->dscrs));
> +               upd->slots[pending].gem_flip = gem_flip;
> +               memcpy(upd->slots[pending].dscrs, dscrs, sizeof(dscrs));
> +       }
> +       spin_unlock_irqrestore(&upd->pending_lock, flags);
> +
> +       if (pending >= 0) {
> +               atmel_hlcdc_layer_update_reset(layer);
> +               mutex_unlock(&upd->lock);
> +               return;
> +       }
> +
> +       spin_lock_irqsave(&dma->lock, flags);
> +       if (!atmel_hlcdc_layer_dma_channel_busy(layer)) {
> +               spin_lock(&upd->pending_lock);
> +               atmel_hlcdc_layer_update_apply(layer);
> +               spin_unlock(&upd->pending_lock);
> +       }
> +       spin_unlock_irqrestore(&dma->lock, flags);
> +
> +       atmel_hlcdc_layer_update_reset(layer);
> +       mutex_unlock(&upd->lock);
> +}
> +
> +static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
> +                                     struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       dma_addr_t dma_addr;
> +       int i;
> +
> +       dma->dscrs = dma_alloc_coherent(dev->dev,
> +                                       layer->max_planes * 4 *
> +                                       sizeof(*dma->dscrs),
> +                                       &dma_addr, GFP_KERNEL);
> +       if (!dma->dscrs)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < layer->max_planes * 4; i++) {
> +               struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
> +
> +               dscr->next = dma_addr + (i * sizeof(*dscr));
> +       }
> +
> +       spin_lock_init(&dma->lock);
> +
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
> +                                         struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       int i;
> +
> +       for (i = 0; i < layer->max_planes * 4; i++) {
> +               struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
> +
> +               if (!dscr->gem_flip)
> +                       continue;
> +
> +               atmel_hlcdc_layer_gem_flip_put(layer, dscr->gem_flip);
> +       }
> +
> +       dma_free_coherent(dev->dev, layer->max_planes * 4 *
> +                         sizeof(*dma->dscrs), dma->dscrs,
> +                         dma->dscrs[0].next);
> +}
> +
> +static void atmel_hlcdc_layer_gc_init(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
> +
> +       INIT_LIST_HEAD(&gc->list);
> +       spin_lock_init(&gc->list_lock);
> +       INIT_WORK(&gc->work, atmel_hlcdc_layer_gc_work);
> +}
> +
> +static void atmel_hlcdc_layer_gc_cleanup(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_gem_flip_gc *gc = &layer->gc;
> +
> +       flush_work(&gc->work);
> +}
> +
> +static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
> +                               struct atmel_hlcdc_layer *layer,
> +                               const struct atmel_hlcdc_layer_desc *desc)
> +{
> +       struct atmel_hlcdc_layer_update *upd = &layer->update;
> +       int updated_size;
> +       void *buffer;
> +       int i;
> +
> +       updated_size = DIV_ROUND_UP(desc->nconfigs,
> +                                   BITS_PER_BYTE *
> +                                   sizeof(unsigned long));
> +
> +       buffer = devm_kzalloc(dev->dev,
> +                             ((desc->nconfigs * sizeof(u32)) +
> +                               (updated_size * sizeof(unsigned long))) * 2,
> +                             GFP_KERNEL);
> +       if (!buffer)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < 2; i++) {
> +               upd->slots[i].updated_configs = buffer;
> +               buffer += updated_size * sizeof(unsigned long);
> +               upd->slots[i].configs = buffer;
> +               buffer += desc->nconfigs * sizeof(u32);
> +       }
> +
> +       upd->pending = -1;
> +       upd->next = -1;
> +       spin_lock_init(&upd->pending_lock);
> +       mutex_init(&upd->lock);
> +
> +       return 0;
> +}
> +
> +int atmel_hlcdc_layer_init(struct drm_device *dev,
> +                          struct atmel_hlcdc_layer *layer,
> +                          const struct atmel_hlcdc_layer_desc *desc)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       struct regmap *regmap = dc->hlcdc->regmap;
> +       unsigned int tmp;
> +       int ret;
> +       int i;
> +
> +       layer->hlcdc = dc->hlcdc;
> +       layer->desc = desc;
> +
> +       regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> +                    ATMEL_HLCDC_LAYER_RST);
> +       for (i = 0; i < desc->formats->nformats; i++) {
> +               int nplanes = drm_format_num_planes(desc->formats->formats[i]);
> +
> +               if (nplanes > layer->max_planes)
> +                       layer->max_planes = nplanes;
> +       }
> +
> +       atmel_hlcdc_layer_gc_init(layer);
> +       ret = atmel_hlcdc_layer_dma_init(dev, layer);
> +       if (ret)
> +               return ret;
> +
> +       ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
> +       if (ret)
> +               return ret;
> +
> +       /* Flush Status Register */
> +       regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
> +                    0xffffffff);
> +       regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
> +                   &tmp);
> +
> +       for (i = 0; i < layer->max_planes; i++)
> +               regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER,
> +                            ATMEL_HLCDC_LAYER_ADD_IRQ(i) |
> +                            ATMEL_HLCDC_LAYER_DONE_IRQ(i));
> +
> +       return 0;
> +}
> +
> +void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
> +                              struct atmel_hlcdc_layer *layer)
> +{
> +       const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> +       struct regmap *regmap = layer->hlcdc->regmap;
> +
> +       regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
> +                    0xffffffff);
> +       regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> +                    ATMEL_HLCDC_LAYER_RST);
> +
> +       atmel_hlcdc_layer_dma_cleanup(dev, layer);
> +       atmel_hlcdc_layer_gc_cleanup(layer);
> +}
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> new file mode 100644
> index 0000000..006d479
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> @@ -0,0 +1,422 @@
> +/*
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef DRM_ATMEL_HLCDC_LAYER_H
> +#define DRM_ATMEL_HLCDC_LAYER_H
> +
> +#include <linux/mfd/atmel-hlcdc.h>
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drmP.h>
> +
> +#define ATMEL_HLCDC_LAYER_CHER                 0x0
> +#define ATMEL_HLCDC_LAYER_CHDR                 0x4
> +#define ATMEL_HLCDC_LAYER_CHSR                 0x8
> +#define ATMEL_HLCDC_LAYER_DMA_CHAN             BIT(0)
> +#define ATMEL_HLCDC_LAYER_UPDATE               BIT(1)
> +#define ATMEL_HLCDC_LAYER_A2Q                  BIT(2)
> +#define ATMEL_HLCDC_LAYER_RST                  BIT(8)
> +
> +#define ATMEL_HLCDC_LAYER_IER                  0xc
> +#define ATMEL_HLCDC_LAYER_IDR                  0x10
> +#define ATMEL_HLCDC_LAYER_IMR                  0x14
> +#define ATMEL_HLCDC_LAYER_ISR                  0x18
> +#define ATMEL_HLCDC_LAYER_DFETCH               BIT(0)
> +#define ATMEL_HLCDC_LAYER_LFETCH               BIT(1)
> +#define ATMEL_HLCDC_LAYER_DMA_IRQ(n)           BIT(2 + ((n) * 8))
> +#define ATMEL_HLCDC_LAYER_DSCR_IRQ(n)          BIT(3 + ((n) * 8))
> +#define ATMEL_HLCDC_LAYER_ADD_IRQ(n)           BIT(4 + ((n) * 8))
> +#define ATMEL_HLCDC_LAYER_DONE_IRQ(n)          BIT(5 + ((n) * 8))
> +#define ATMEL_HLCDC_LAYER_OVR_IRQ(n)           BIT(6 + ((n) * 8))
> +
> +#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n)                (((n) * 0x10) + 0x1c)
> +#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n)                (((n) * 0x10) + 0x20)
> +#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n)                (((n) * 0x10) + 0x24)
> +#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n)                (((n) * 0x10) + 0x28)
> +#define ATMEL_HLCDC_LAYER_CFG(p, c)            (((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
> +
> +#define ATMEL_HLCDC_LAYER_DMA_CFG_ID           0
> +#define ATMEL_HLCDC_LAYER_DMA_CFG(p)           ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
> +
> +#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID                1
> +#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p)                ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
> +#define ATMEL_HLCDC_LAYER_RGB                  (0 << 0)
> +#define ATMEL_HLCDC_LAYER_CLUT                 (1 << 0)
> +#define ATMEL_HLCDC_LAYER_YUV                  (2 << 0)
> +#define ATMEL_HLCDC_RGB_MODE(m)                        (((m) & 0xf) << 4)
> +#define ATMEL_HLCDC_CLUT_MODE(m)               (((m) & 0x3) << 8)
> +#define ATMEL_HLCDC_YUV_MODE(m)                        (((m) & 0xf) << 12)
> +#define ATMEL_HLCDC_YUV422ROT                  (1 << 16)
> +#define ATMEL_HLCDC_YUV422SWP                  (1 << 17)
> +#define ATMEL_HLCDC_DSCALEOPT                  (1 << 20)
> +
> +#define ATMEL_HLCDC_XRGB4444_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
> +#define ATMEL_HLCDC_ARGB4444_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
> +#define ATMEL_HLCDC_RGBA4444_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
> +#define ATMEL_HLCDC_RGB565_MODE                        (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
> +#define ATMEL_HLCDC_ARGB1555_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
> +#define ATMEL_HLCDC_XRGB8888_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
> +#define ATMEL_HLCDC_RGB888_MODE                        (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
> +#define ATMEL_HLCDC_ARGB8888_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
> +#define ATMEL_HLCDC_RGBA8888_MODE              (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
> +
> +#define ATMEL_HLCDC_AYUV_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
> +#define ATMEL_HLCDC_YUYV_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
> +#define ATMEL_HLCDC_UYVY_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
> +#define ATMEL_HLCDC_YVYU_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
> +#define ATMEL_HLCDC_VYUY_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
> +#define ATMEL_HLCDC_NV61_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
> +#define ATMEL_HLCDC_YUV422_MODE                        (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
> +#define ATMEL_HLCDC_NV21_MODE                  (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
> +#define ATMEL_HLCDC_YUV420_MODE                        (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
> +
> +#define ATMEL_HLCDC_LAYER_POS_CFG(p)           ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
> +#define ATMEL_HLCDC_LAYER_SIZE_CFG(p)          ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
> +#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p)       ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
> +#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p)       ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
> +#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p)       ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
> +#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
> +#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p)         ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
> +#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p)    ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
> +
> +#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p)       ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
> +#define ATMEL_HLCDC_LAYER_CRKEY                        BIT(0)
> +#define ATMEL_HLCDC_LAYER_INV                  BIT(1)
> +#define ATMEL_HLCDC_LAYER_ITER2BL              BIT(2)
> +#define ATMEL_HLCDC_LAYER_ITER                 BIT(3)
> +#define ATMEL_HLCDC_LAYER_REVALPHA             BIT(4)
> +#define ATMEL_HLCDC_LAYER_GAEN                 BIT(5)
> +#define ATMEL_HLCDC_LAYER_LAEN                 BIT(6)
> +#define ATMEL_HLCDC_LAYER_OVR                  BIT(7)
> +#define ATMEL_HLCDC_LAYER_DMA                  BIT(8)
> +#define ATMEL_HLCDC_LAYER_REP                  BIT(9)
> +#define ATMEL_HLCDC_LAYER_DSTKEY               BIT(10)
> +#define ATMEL_HLCDC_LAYER_GA_MASK              GENMASK(23, 16)
> +#define ATMEL_HLCDC_LAYER_GA_SHIFT             16
> +
> +#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)                ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
> +
> +#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p)      ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
> +
> +#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
> +
> +#define ATMEL_HLCDC_MAX_PLANES                 3
> +
> +/**
> + * Atmel HLCDC Layer registers layout structure
> + *
> + * Each HLCDC layer has its own register organization and a given register
> + * by be placed differently on 2 different layers depending on its
> + * capabilities.
> + * This structure stores common registers layout for a given layer and is
> + * used by HLCDC layer code to chose the appropriate register to write to
> + * or to read from.
> + *
> + * For all fields, a value of zero means "unsupported".
> + *
> + * See Atmel's datasheet for a detailled description of these registers.
> + *
> + * @xstride: xstride registers
> + * @pstride: pstride registers
> + * @pos: position register
> + * @size: displayed size register
> + * @memsize: memory size register
> + * @default_color: default color register
> + * @chroma_key: chroma key register
> + * @chroma_key_mask: chroma key mask register
> + * @general_config: general layer config register
> + * @disc_pos: discard area position register
> + * @disc_size: discard area size register
> + * @csc: color space conversion register
> + */
> +struct atmel_hlcdc_layer_cfg_layout {
> +       int xstride[ATMEL_HLCDC_MAX_PLANES];
> +       int pstride[ATMEL_HLCDC_MAX_PLANES];
> +       int pos;
> +       int size;
> +       int memsize;
> +       int default_color;
> +       int chroma_key;
> +       int chroma_key_mask;
> +       int general_config;
> +       int disc_pos;
> +       int disc_size;
> +       int csc;
> +};
> +
> +/**
> + * Atmel HLCDC GEM flip structure
> + *
> + * This structure is allocated when someone asked for a layer update (most
> + * likely a DRM plane update, either primary, overlay or cursor plane) and
> + * released when the layer do not need the reference GEM objects anymore
> + * (i.e. the layer was disabled or updated).
> + *
> + * @node: list element structure. Used to attach the GEM flip structure to
> + *       the garbage collector when the layer no longer need the referenced
> + *       GEM objects.
> + * @gems: the referenced GEM objects. The number of GEM object referenced
> + *       depends on the chosen format.
> + * @remaining_gems: the number of GEM object still referenced by the layer.
> + *                 When no more objects are referenced the GEM flip structure
> + *                 is added to the garbage collector.
> + */
> +struct atmel_hlcdc_layer_gem_flip {
> +       struct list_head node;
> +       struct drm_gem_object *gems[ATMEL_HLCDC_MAX_PLANES];
> +       int remaining_gems;
> +       void (*finished)(void *data);
> +       void *finished_data;
> +};
> +
> +/**
> + * Atmel HLCDC DMA descriptor structure
> + *
> + * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
> + *
> + * The structure fields must remain in this specific order, because they're
> + * used by the HLCDC DMA engine, which expect them in this order.
> + *
> + * @addr: buffer DMA address
> + * @ctrl: DMA transfer options
> + * @next: next DMA descriptor to fetch
> + * @gem_flip: the attached gem_flip operation
> + */
> +struct atmel_hlcdc_dma_channel_dscr {
> +       dma_addr_t addr;
> +       u32 ctrl;
> +       dma_addr_t next;
> +       struct atmel_hlcdc_layer_gem_flip *gem_flip;
> +} __aligned(sizeof(u64));
> +
> +/**
> + * Atmel HLCDC layer types
> + */
> +enum atmel_hlcdc_layer_type {
> +       ATMEL_HLCDC_BASE_LAYER,
> +       ATMEL_HLCDC_OVERLAY_LAYER,
> +       ATMEL_HLCDC_CURSOR_LAYER,
> +       ATMEL_HLCDC_PP_LAYER,
> +};
> +
> +/**
> + * Atmel HLCDC Supported formats structure
> + *
> + * This structure list all the formats supported by a given layer.
> + *
> + * @nformats: number of supported formats
> + * @formats: supported formats
> + */
> +struct atmel_hlcdc_formats {
> +       int nformats;
> +       uint32_t *formats;
> +};
> +
> +/**
> + * Atmel HLCDC Layer description structure
> + *
> + * This structure describe the capabilities provided by a given layer.
> + *
> + * @name: layer name
> + * @type: layer type
> + * @id: layer id
> + * @regs_offset: offset of the layer registers from the HLCDC registers base
> + * @nconfigs: number of config registers provided by this layer
> + * @layout: config registers layout
> + * @max_width: maximum width supported by this layer (0 means unlimited)
> + * @max_height: maximum height supported by this layer (0 means unlimited)
> + */
> +struct atmel_hlcdc_layer_desc {
> +       const char *name;
> +       enum atmel_hlcdc_layer_type type;
> +       int id;
> +       int regs_offset;
> +       int nconfigs;
> +       struct atmel_hlcdc_formats *formats;
> +       struct atmel_hlcdc_layer_cfg_layout layout;
> +       int max_width;
> +       int max_height;
> +};
> +
> +/**
> + * Atmel HLCDC Layer Update Slot structure
> + *
> + * This structure stores layer update requests to be applied on next frame.
> + * This is the base structure behind the atomic layer update infrastructure.
> + *
> + * Atomic layer update provides a way to update all layer's parameters
> + * simultaneously. This is needed to avoid incompatible sequential updates
> + * like this one:
> + * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
> + *    (2 planes/buffers)
> + * 2) the format update is applied but the DMA channel for the second
> + *    plane/buffer is not enabled
> + * 3) enable the DMA channel for the second plane
> + *
> + *@dscrs: DMA channel descriptors
> + *@gem_flip: gem_flip object
> + *@updated_configs: bitmask used to record modified configs
> + *@configs: new config values
> + */
> +struct atmel_hlcdc_layer_update_slot {
> +       struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
> +       struct atmel_hlcdc_layer_gem_flip *gem_flip;
> +       unsigned long *updated_configs;
> +       u32 *configs;
> +};
> +
> +/**
> + * Atmel HLCDC Layer Update structure
> + *
> + * This structure provides a way to queue layer update requests.
> + *
> + * At a given time there is at most:
> + *  - one pending update request, which means the update request has been
> + *    commited (or validated) and is waiting for the DMA channel(s) to be
> + *    available
> + *  - one request being prepared, which means someone started a layer update
> + *    but has not commited it yet. There cannot be more than one started
> + *    request, because the update lock is taken when starting a layer update
> + *    and release when commiting or rolling back the request.
> + *
> + *@slots: update slots. One is used for pending request and the other one
> + *       for started update request
> + *@pending: the pending slot index or -1 if no request is pending
> + *@next: the started update slot index or -1 no update has been started
> + *@pending_lock: lock to access the pending field
> + *@lock: layer update lock
> + */
> +struct atmel_hlcdc_layer_update {
> +       struct atmel_hlcdc_layer_update_slot slots[2];
> +       int pending;
> +       int next;
> +       spinlock_t pending_lock;
> +       struct mutex lock;
> +};
> +
> +/**
> + * Atmel HLCDC Layer GEM flip garbage collector structure
> + *
> + * This structure is used to schedule GEM object release when we are in
> + * interrupt context (within atmel_hlcdc_layer_irq function).
> + *
> + *@list: GEM flip objects to release
> + *@list_lock: lock to access the GEM flip list
> + *@work: work queue scheduled when there are GEM flip to collect
> + *@finished: action to execute the GEM flip and all attached objects have been
> + *          released
> + *@finished_data: data passed to the finished callback
> + *@finished_lock: lock to access finished related fields
> + */
> +struct atmel_hlcdc_layer_gem_flip_gc {
> +       struct list_head list;
> +       spinlock_t list_lock;
> +       struct work_struct work;
> +};


Please have a look at drm_flip_work.. I think that should simplify
post-flip cleanup for you..

> +
> +/**
> + * Atmel HLCDC Layer DMA channel structure
> + *
> + * This structure stores informations on the DMA channel associated to a
> + * given layer.
> + *
> + *@enabled: DMA channel status
> + *@lock: lock to access the DMA channel fields
> + *@cur: current DMA transfers (one for each plane/buffer)
> + *@queue: next DMA transfers, to be launch on next frame update
> + *@dscrs: allocated DMA descriptors
> + */
> +struct atmel_hlcdc_layer_dma_channel {
> +       bool enabled;
> +       spinlock_t lock;
> +       struct atmel_hlcdc_dma_channel_dscr *cur[ATMEL_HLCDC_MAX_PLANES];
> +       struct atmel_hlcdc_dma_channel_dscr *queue[ATMEL_HLCDC_MAX_PLANES];
> +       struct atmel_hlcdc_dma_channel_dscr *dscrs;
> +};
> +
> +/**
> + * Atmel HLCDC Layer structure
> + *
> + * This structure stores information on the layer instance.
> + *
> + *@desc: layer description
> + *@max_planes: maximum planes/buffers that can be associated with this layer.
> + *            This depends on the supported formats.
> + *@hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
> + *@dma: dma channel
> + *@gc: GEM flip garbage collector
> + *@update: update handler
> + */
> +struct atmel_hlcdc_layer {
> +       const struct atmel_hlcdc_layer_desc *desc;
> +       int max_planes;
> +       struct atmel_hlcdc *hlcdc;
> +       struct atmel_hlcdc_layer_dma_channel dma;
> +       struct atmel_hlcdc_layer_gem_flip_gc gc;
> +       struct atmel_hlcdc_layer_update update;
> +};
> +
> +void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
> +
> +int atmel_hlcdc_layer_init(struct drm_device *dev,
> +                          struct atmel_hlcdc_layer *layer,
> +                          const struct atmel_hlcdc_layer_desc *desc);
> +
> +void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
> +                              struct atmel_hlcdc_layer *layer);
> +
> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
> +
> +void atmel_hlcdc_layer_set_finished(struct atmel_hlcdc_layer *layer,
> +                                   void (*finished)(void *data),
> +                                   void *data);
> +
> +int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
> +
> +void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
> +                                 u32 mask, u32 val);
> +
> +void atmel_hlcdc_layer_update_set_gem(struct atmel_hlcdc_layer *layer,
> +                                     int plane_id,
> +                                     struct drm_gem_cma_object *gem,
> +                                     unsigned int offset);
> +
> +void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
> +                                          void (*finished)(void *data),
> +                                          void *finished_data);
> +
> +void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
> +
> +void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
> +
> +static inline bool
> +atmel_hlcdc_layer_dma_channel_busy(struct atmel_hlcdc_layer *layer)
> +{
> +       struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +       int i;
> +
> +       for (i = 0; i < layer->max_planes; i++) {
> +               if (dma->queue[i])
> +                       return true;
> +       }
> +
> +       return false;
> +}
> +
> +#endif /* DRM_ATMEL_HLCDC_LAYER_H */
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> new file mode 100644
> index 0000000..3295021
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> @@ -0,0 +1,351 @@
> +/*
> + * Copyright (C) 2014 Traphandler
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_panel.h>
> +
> +#include "atmel_hlcdc_dc.h"
> +
> +/**
> + * Atmel HLCDC RGB output mode
> + */
> +enum atmel_hlcdc_connector_rgb_mode {
> +       ATMEL_HLCDC_CONNECTOR_RGB444,
> +       ATMEL_HLCDC_CONNECTOR_RGB565,
> +       ATMEL_HLCDC_CONNECTOR_RGB666,
> +       ATMEL_HLCDC_CONNECTOR_RGB888,
> +};
> +
> +/**
> + * Atmel HLCDC Panel structure
> + *
> + * This structure stores informations about an DRM panel connected through
> + * the RGB connector.
> + *
> + * @mode: RGB output mode
> + * @connector: DRM connector
> + * @encoder: DRM encoder
> + * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
> + * @panel: pointer to the attached DRM panel
> + * @pinctrl: pinctrl state used by the current RGB output mode
> + * @np: DRM panel DT node
> + * @dpms: current DPMS mode
> + */
> +struct atmel_hlcdc_panel {
> +       enum atmel_hlcdc_connector_rgb_mode mode;
> +       struct drm_connector connector;
> +       struct drm_encoder encoder;
> +       struct atmel_hlcdc *hlcdc;
> +       struct drm_panel *panel;
> +       struct pinctrl *pinctrl;
> +       struct device_node *np;
> +       int dpms;
> +};
> +
> +static const char * const pin_state_names[] = {
> +       [ATMEL_HLCDC_CONNECTOR_RGB444] = "rgb-444",
> +       [ATMEL_HLCDC_CONNECTOR_RGB565] = "rgb-565",
> +       [ATMEL_HLCDC_CONNECTOR_RGB666] = "rgb-666",
> +       [ATMEL_HLCDC_CONNECTOR_RGB888] = "rgb-888",
> +};
> +
> +static inline struct atmel_hlcdc_panel *
> +drm_connector_to_atmel_hlcdc_panel(struct drm_connector *connector)
> +{
> +       return container_of(connector, struct atmel_hlcdc_panel, connector);
> +}
> +
> +static inline struct atmel_hlcdc_panel *
> +drm_encoder_to_atmel_hlcdc_panel(struct drm_encoder *encoder)
> +{
> +       return container_of(encoder, struct atmel_hlcdc_panel, encoder);
> +}
> +
> +static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
> +                                          int mode)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_encoder_to_atmel_hlcdc_panel(encoder);
> +       struct regmap *regmap = panel->hlcdc->regmap;
> +       unsigned int status;
> +
> +       if (mode != DRM_MODE_DPMS_ON)
> +               mode = DRM_MODE_DPMS_OFF;
> +
> +       if (mode == panel->dpms)
> +               return;
> +
> +       if (mode != DRM_MODE_DPMS_ON) {
> +               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      (status & ATMEL_HLCDC_DISP))
> +                       cpu_relax();
> +
> +               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      (status & ATMEL_HLCDC_SYNC))
> +                       cpu_relax();
> +
> +               regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      (status & ATMEL_HLCDC_PIXEL_CLK))
> +                       cpu_relax();
> +
> +               clk_disable_unprepare(panel->hlcdc->sys_clk);
> +               if (panel->panel)
> +                       drm_panel_disable(panel->panel);
> +       } else {
> +               if (panel->panel)
> +                       drm_panel_enable(panel->panel);
> +               clk_prepare_enable(panel->hlcdc->sys_clk);
> +
> +               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      !(status & ATMEL_HLCDC_PIXEL_CLK))
> +                       cpu_relax();
> +
> +
> +               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      !(status & ATMEL_HLCDC_SYNC))
> +                       cpu_relax();
> +
> +               regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
> +               while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
> +                      !(status & ATMEL_HLCDC_DISP))
> +                       cpu_relax();
> +       }
> +
> +       panel->dpms = mode;
> +}
> +
> +static bool
> +atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
> +                                    const struct drm_display_mode *mode,
> +                                    struct drm_display_mode *adjusted)
> +{
> +       return true;
> +}
> +
> +static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
> +{
> +       atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
> +}
> +
> +static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
> +{
> +       atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
> +}
> +
> +static void
> +atmel_hlcdc_panel_encoder_mode_set(struct drm_encoder *encoder,
> +                                  struct drm_display_mode *mode,
> +                                  struct drm_display_mode *adjusted)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_encoder_to_atmel_hlcdc_panel(encoder);
> +       unsigned long prate = clk_get_rate(panel->hlcdc->sys_clk);
> +       unsigned long mode_rate = mode->clock * 1000;
> +       int div;
> +       u32 cfg0 = 0;
> +
> +       if ((prate / 2) < mode_rate) {
> +               prate *= 2;
> +               cfg0 |= ATMEL_HLCDC_CLKSEL;
> +       }
> +
> +       div = DIV_ROUND_UP(prate, mode_rate);
> +       if (div < 2)
> +               div = 2;
> +
> +       cfg0 |= ATMEL_HLCDC_CLKDIV(div);
> +
> +       regmap_update_bits(panel->hlcdc->regmap, ATMEL_HLCDC_CFG(0),
> +                          ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK, cfg0);
> +}
> +
> +static struct drm_encoder_helper_funcs encoder_helper_funcs = {
> +       .dpms = atmel_hlcdc_panel_encoder_dpms,
> +       .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
> +       .prepare = atmel_hlcdc_panel_encoder_prepare,
> +       .commit = atmel_hlcdc_panel_encoder_commit,
> +       .mode_set = atmel_hlcdc_panel_encoder_mode_set,
> +};
> +
> +static void atmel_hlcdc_panel_encoder_destroy(struct drm_encoder *encoder)
> +{
> +       drm_encoder_cleanup(encoder);
> +       memset(encoder, 0, sizeof(*encoder));
> +}
> +
> +static const struct drm_encoder_funcs encoder_funcs = {
> +       .destroy = atmel_hlcdc_panel_encoder_destroy,
> +};
> +
> +static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_connector_to_atmel_hlcdc_panel(connector);
> +       int ret;
> +
> +       if (!panel->panel)
> +               return -ENOENT;
> +
> +       ret = panel->panel->funcs->get_modes(panel->panel);
> +       return ret;
> +}
> +
> +static int atmel_hlcdc_panel_mode_valid(struct drm_connector *connector,
> +                                       struct drm_display_mode *mode)
> +{
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +atmel_hlcdc_panel_best_encoder(struct drm_connector *connector)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_connector_to_atmel_hlcdc_panel(connector);
> +
> +       return &panel->encoder;
> +}
> +
> +static struct drm_connector_helper_funcs connector_helper_funcs = {
> +       .get_modes = atmel_hlcdc_panel_get_modes,
> +       .mode_valid = atmel_hlcdc_panel_mode_valid,
> +       .best_encoder = atmel_hlcdc_panel_best_encoder,
> +};
> +
> +static enum drm_connector_status
> +atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_connector_to_atmel_hlcdc_panel(connector);
> +
> +       if (!panel->panel) {
> +               panel->panel = of_drm_find_panel(panel->np);
> +               if (panel->panel)
> +                       drm_panel_attach(panel->panel, &panel->connector);
> +       }
> +
> +       if (panel->panel)
> +               return connector_status_connected;
> +
> +       return connector_status_disconnected;
> +}
> +
> +static void
> +atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
> +{
> +       struct atmel_hlcdc_panel *panel =
> +                       drm_connector_to_atmel_hlcdc_panel(connector);
> +
> +       if (panel->panel)
> +               drm_panel_detach(panel->panel);
> +
> +       drm_sysfs_connector_remove(connector);
> +       drm_connector_cleanup(connector);
> +
> +       pinctrl_put(panel->pinctrl);
> +}
> +
> +static const struct drm_connector_funcs connector_funcs = {
> +       .dpms = drm_helper_connector_dpms,
> +       .detect = atmel_hlcdc_panel_connector_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .destroy = atmel_hlcdc_panel_connector_destroy,
> +};
> +
> +int atmel_hlcdc_panel_create(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       struct atmel_hlcdc_panel *panel;
> +       struct of_phandle_args out_args;
> +       u32 cfg;
> +       int ret;
> +
> +       panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
> +       if (!panel)
> +               return -ENOMEM;
> +
> +       ret = of_parse_phandle_with_fixed_args(dev->dev->of_node,
> +                                              "atmel,panel", 2, 0,
> +                                              &out_args);
> +       if (ret) {
> +               dev_err(dev->dev, "failed to retrieve panel info from DT\n");
> +               return ret;
> +       }
> +
> +       switch (out_args.args[0]) {
> +       case ATMEL_HLCDC_CONNECTOR_RGB444:
> +       case ATMEL_HLCDC_CONNECTOR_RGB565:
> +       case ATMEL_HLCDC_CONNECTOR_RGB666:
> +       case ATMEL_HLCDC_CONNECTOR_RGB888:
> +               break;
> +       default:
> +               dev_err(dev->dev, "unknown RGB mode\n");
> +               return -EINVAL;
> +       }
> +
> +       panel->np = out_args.np;
> +       panel->mode = out_args.args[0];
> +       panel->pinctrl = pinctrl_get_select(dev->dev,
> +                                           pin_state_names[panel->mode]);
> +       if (IS_ERR(panel->pinctrl)) {
> +               dev_err(dev->dev, "could not request pinctrl state\n");
> +               return PTR_ERR(panel->pinctrl);
> +       }
> +
> +       cfg = out_args.args[1] & (ATMEL_HLCDC_HSPOL |
> +                                 ATMEL_HLCDC_VSPOL |
> +                                 ATMEL_HLCDC_VSPDLYS |
> +                                 ATMEL_HLCDC_VSPDLYE |
> +                                 ATMEL_HLCDC_DISPPOL |
> +                                 ATMEL_HLCDC_DISPDLY |
> +                                 ATMEL_HLCDC_VSPSU |
> +                                 ATMEL_HLCDC_VSPHO);
> +       cfg |= panel->mode << 8;
> +
> +       regmap_write(dc->hlcdc->regmap,
> +                    ATMEL_HLCDC_CFG(5),
> +                    cfg);
> +
> +       panel->dpms = DRM_MODE_DPMS_OFF;
> +
> +       panel->hlcdc = dc->hlcdc;
> +
> +       drm_connector_init(dev, &panel->connector, &connector_funcs,
> +                          DRM_MODE_CONNECTOR_LVDS);
> +       drm_connector_helper_add(&panel->connector, &connector_helper_funcs);
> +       panel->connector.dpms = DRM_MODE_DPMS_OFF;
> +       panel->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
> +
> +       drm_encoder_init(dev, &panel->encoder, &encoder_funcs,
> +                        DRM_MODE_ENCODER_LVDS);
> +       drm_encoder_helper_add(&panel->encoder, &encoder_helper_funcs);
> +
> +       drm_mode_connector_attach_encoder(&panel->connector, &panel->encoder);
> +       drm_sysfs_connector_add(&panel->connector);
> +
> +       panel->encoder.possible_crtcs = 0x1;
> +
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> new file mode 100644
> index 0000000..0c7469b
> --- /dev/null
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> @@ -0,0 +1,729 @@
> +/*
> + * Copyright (C) 2014 Free Electrons
> + * Copyright (C) 2014 Atmel
> + *
> + * Author: Boris BREZILLON <boris.brezillon@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 version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "atmel_hlcdc_dc.h"
> +
> +#define SUBPIXEL_MASK                  0xffff
> +
> +static uint32_t rgb_formats[] = {
> +       DRM_FORMAT_XRGB4444,
> +       DRM_FORMAT_ARGB4444,
> +       DRM_FORMAT_RGBA4444,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_RGB888,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_RGBA8888,
> +};
> +
> +struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
> +       .formats = rgb_formats,
> +       .nformats = ARRAY_SIZE(rgb_formats),
> +};
> +
> +static uint32_t rgb_and_yuv_formats[] = {
> +       DRM_FORMAT_XRGB4444,
> +       DRM_FORMAT_ARGB4444,
> +       DRM_FORMAT_RGBA4444,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_RGB888,
> +       DRM_FORMAT_ARGB1555,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_RGBA8888,
> +       DRM_FORMAT_AYUV,
> +       DRM_FORMAT_YUYV,
> +       DRM_FORMAT_UYVY,
> +       DRM_FORMAT_YVYU,
> +       DRM_FORMAT_VYUY,
> +       DRM_FORMAT_NV21,
> +       DRM_FORMAT_NV61,
> +       DRM_FORMAT_YUV422,
> +       DRM_FORMAT_YUV420,
> +};
> +
> +struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
> +       .formats = rgb_and_yuv_formats,
> +       .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
> +};
> +
> +static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
> +{
> +       switch (format) {
> +       case DRM_FORMAT_XRGB4444:
> +               *mode = ATMEL_HLCDC_XRGB4444_MODE;
> +               break;
> +       case DRM_FORMAT_ARGB4444:
> +               *mode = ATMEL_HLCDC_ARGB4444_MODE;
> +               break;
> +       case DRM_FORMAT_RGBA4444:
> +               *mode = ATMEL_HLCDC_RGBA4444_MODE;
> +               break;
> +       case DRM_FORMAT_RGB565:
> +               *mode = ATMEL_HLCDC_RGB565_MODE;
> +               break;
> +       case DRM_FORMAT_RGB888:
> +               *mode = ATMEL_HLCDC_RGB888_MODE;
> +               break;
> +       case DRM_FORMAT_ARGB1555:
> +               *mode = ATMEL_HLCDC_ARGB1555_MODE;
> +               break;
> +       case DRM_FORMAT_XRGB8888:
> +               *mode = ATMEL_HLCDC_XRGB8888_MODE;
> +               break;
> +       case DRM_FORMAT_ARGB8888:
> +               *mode = ATMEL_HLCDC_ARGB8888_MODE;
> +               break;
> +       case DRM_FORMAT_RGBA8888:
> +               *mode = ATMEL_HLCDC_RGBA8888_MODE;
> +               break;
> +       case DRM_FORMAT_AYUV:
> +               *mode = ATMEL_HLCDC_AYUV_MODE;
> +               break;
> +       case DRM_FORMAT_YUYV:
> +               *mode = ATMEL_HLCDC_YUYV_MODE;
> +               break;
> +       case DRM_FORMAT_UYVY:
> +               *mode = ATMEL_HLCDC_UYVY_MODE;
> +               break;
> +       case DRM_FORMAT_YVYU:
> +               *mode = ATMEL_HLCDC_YVYU_MODE;
> +               break;
> +       case DRM_FORMAT_VYUY:
> +               *mode = ATMEL_HLCDC_VYUY_MODE;
> +               break;
> +       case DRM_FORMAT_NV21:
> +               *mode = ATMEL_HLCDC_NV21_MODE;
> +               break;
> +       case DRM_FORMAT_NV61:
> +               *mode = ATMEL_HLCDC_NV61_MODE;
> +               break;
> +       case DRM_FORMAT_YUV420:
> +               *mode = ATMEL_HLCDC_YUV420_MODE;
> +               break;
> +       case DRM_FORMAT_YUV422:
> +               *mode = ATMEL_HLCDC_YUV422_MODE;
> +               break;
> +       default:
> +               return -ENOTSUPP;
> +       }
> +
> +       return 0;
> +}
> +
> +static bool atmel_hlcdc_format_embedds_alpha(u32 format)
> +{
> +       int i;
> +
> +       for (i = 0; i < sizeof(format); i++) {
> +               char tmp = (format >> (8 * i)) & 0xff;
> +
> +               if (tmp == 'A')
> +                       return true;
> +       }
> +
> +       return false;
> +}
> +
> +static u32 heo_downscaling_xcoef[] = {
> +       0x11343311,
> +       0x000000f7,
> +       0x1635300c,
> +       0x000000f9,
> +       0x1b362c08,
> +       0x000000fb,
> +       0x1f372804,
> +       0x000000fe,
> +       0x24382400,
> +       0x00000000,
> +       0x28371ffe,
> +       0x00000004,
> +       0x2c361bfb,
> +       0x00000008,
> +       0x303516f9,
> +       0x0000000c,
> +};
> +
> +static u32 heo_downscaling_ycoef[] = {
> +       0x00123737,
> +       0x00173732,
> +       0x001b382d,
> +       0x001f3928,
> +       0x00243824,
> +       0x0028391f,
> +       0x002d381b,
> +       0x00323717,
> +};
> +
> +static u32 heo_upscaling_xcoef[] = {
> +       0xf74949f7,
> +       0x00000000,
> +       0xf55f33fb,
> +       0x000000fe,
> +       0xf5701efe,
> +       0x000000ff,
> +       0xf87c0dff,
> +       0x00000000,
> +       0x00800000,
> +       0x00000000,
> +       0x0d7cf800,
> +       0x000000ff,
> +       0x1e70f5ff,
> +       0x000000fe,
> +       0x335ff5fe,
> +       0x000000fb,
> +};
> +
> +static u32 heo_upscaling_ycoef[] = {
> +       0x00004040,
> +       0x00075920,
> +       0x00056f0c,
> +       0x00027b03,
> +       0x00008000,
> +       0x00037b02,
> +       0x000c6f05,
> +       0x00205907,
> +};
> +
> +static void
> +atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       const struct atmel_hlcdc_layer_cfg_layout *layout =
> +                                               &plane->layer.desc->layout;
> +
> +       if (layout->size)
> +               atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                            layout->size,
> +                                            0xffffffff,
> +                                            (req->crtc_w - 1) |
> +                                            ((req->crtc_h - 1) << 16));
> +
> +       if (layout->memsize)
> +               atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                            layout->memsize,
> +                                            0xffffffff,
> +                                            (req->src_w - 1) |
> +                                            ((req->src_h - 1) << 16));
> +
> +       if (layout->pos)
> +               atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                            layout->pos,
> +                                            0xffffffff,
> +                                            req->crtc_x |
> +                                            (req->crtc_y  << 16));
> +
> +       /* TODO: rework the rescaling part */
> +       if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
> +               u32 factor_reg = 0;
> +
> +               if (req->crtc_w != req->src_w) {
> +                       int i;
> +                       u32 factor;
> +                       u32 *coeff_tab = heo_upscaling_xcoef;
> +                       u32 max_memsize;
> +
> +                       if (req->crtc_w < req->src_w)
> +                               coeff_tab = heo_downscaling_xcoef;
> +                       for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
> +                               atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                                            17 + i,
> +                                                            0xffffffff,
> +                                                            coeff_tab[i]);
> +                       factor = ((8 * 256 * req->src_w) - (256 * 4)) /
> +                                req->crtc_w;
> +                       factor++;
> +                       max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
> +                                     2048;
> +                       if (max_memsize > req->src_w)
> +                               factor--;
> +                       factor_reg |= factor | 0x80000000;
> +               }
> +
> +               if (req->crtc_h != req->src_h) {
> +                       int i;
> +                       u32 factor;
> +                       u32 *coeff_tab = heo_upscaling_ycoef;
> +                       u32 max_memsize;
> +
> +                       if (req->crtc_w < req->src_w)
> +                               coeff_tab = heo_downscaling_ycoef;
> +                       for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
> +                               atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                                            33 + i,
> +                                                            0xffffffff,
> +                                                            coeff_tab[i]);
> +                       factor = ((8 * 256 * req->src_w) - (256 * 4)) /
> +                                req->crtc_w;
> +                       factor++;
> +                       max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
> +                                     2048;
> +                       if (max_memsize > req->src_w)
> +                               factor--;
> +                       factor_reg |= (factor << 16) | 0x80000000;
> +               }
> +
> +               atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
> +                                            factor_reg);
> +       }
> +}
> +
> +static void
> +atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       const struct atmel_hlcdc_layer_cfg_layout *layout =
> +                                               &plane->layer.desc->layout;
> +       unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
> +
> +       if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
> +               cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
> +                      ATMEL_HLCDC_LAYER_ITER;
> +
> +               if (atmel_hlcdc_format_embedds_alpha(req->pixel_format))
> +                       cfg |= ATMEL_HLCDC_LAYER_LAEN;
> +               else
> +                       cfg |= ATMEL_HLCDC_LAYER_GAEN;
> +       }
> +
> +       atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
> +                                    ATMEL_HLCDC_LAYER_ITER2BL |
> +                                    ATMEL_HLCDC_LAYER_ITER |
> +                                    ATMEL_HLCDC_LAYER_GAEN |
> +                                    ATMEL_HLCDC_LAYER_LAEN |
> +                                    ATMEL_HLCDC_LAYER_OVR |
> +                                    ATMEL_HLCDC_LAYER_DMA, cfg);
> +}
> +
> +static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       u32 mode;
> +       int ret;
> +
> +       ret = atmel_hlcdc_format_to_plane_mode(req->pixel_format, &mode);
> +       if (ret)
> +               return;
> +
> +       atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                    ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
> +                                    0xffffffff,
> +                                    mode);
> +}
> +
> +static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       struct atmel_hlcdc_layer *layer = &plane->layer;
> +       const struct atmel_hlcdc_layer_cfg_layout *layout =
> +                                                       &layer->desc->layout;
> +       int i;
> +
> +       for (i = 0; i < req->nplanes; i++) {
> +               atmel_hlcdc_layer_update_set_gem(&plane->layer, i,
> +                                                req->gems[i],
> +                                                req->offsets[i]);
> +               if (layout->xstride[i])
> +                       atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                               layout->xstride[i],
> +                                               0xffffffff,
> +                                               req->pitches[i] -
> +                                               (req->bpp[i] * req->src_w));
> +       }
> +}
> +
> +static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +       const struct atmel_hlcdc_layer_cfg_layout *layout =
> +                                               &plane->layer.desc->layout;
> +
> +       if (!layout->size &&
> +           (req->crtc->mode.crtc_hdisplay != req->crtc_w ||
> +            req->crtc->mode.crtc_vdisplay != req->crtc_h))
> +               return -EINVAL;
> +
> +       if (plane->layer.desc->max_height &&
> +           req->crtc_h > plane->layer.desc->max_height)
> +               return -EINVAL;
> +
> +       if (plane->layer.desc->max_width &&
> +           req->crtc_w > plane->layer.desc->max_width)
> +               return -EINVAL;
> +
> +       if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
> +           (!layout->memsize ||
> +            atmel_hlcdc_format_embedds_alpha(req->pixel_format)))
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       unsigned int patched_crtc_w;
> +       unsigned int patched_crtc_h;
> +       int x_offset = 0;
> +       int y_offset = 0;
> +       int i;
> +
> +       if ((req->src_x | req->src_y | req->src_w | req->src_h) &
> +           SUBPIXEL_MASK)
> +               return -EINVAL;
> +
> +       req->src_x >>= 16;
> +       req->src_y >>= 16;
> +       req->src_w >>= 16;
> +       req->src_h >>= 16;
> +
> +       req->nplanes = drm_format_num_planes(req->pixel_format);
> +       if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
> +               return -EINVAL;
> +
> +       if (req->crtc_x + req->crtc_w > req->crtc->mode.hdisplay)
> +               patched_crtc_w = req->crtc->mode.hdisplay - req->crtc_x;
> +       else
> +               patched_crtc_w = req->crtc_w;
> +
> +       if (req->crtc_x < 0) {
> +               patched_crtc_w += req->crtc_x;
> +               x_offset = -req->crtc_x;
> +               req->crtc_x = 0;
> +       }
> +
> +       if (req->crtc_y + req->crtc_h > req->crtc->mode.vdisplay)
> +               patched_crtc_h = req->crtc->mode.vdisplay - req->crtc_y;
> +       else
> +               patched_crtc_h = req->crtc_h;
> +
> +       if (req->crtc_y < 0) {
> +               patched_crtc_h += req->crtc_y;
> +               y_offset = -req->crtc_y;
> +               req->crtc_y = 0;
> +       }
> +
> +       req->src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
> +                                      req->crtc_w);
> +       req->src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
> +                                      req->crtc_h);
> +       req->crtc_w = patched_crtc_w;
> +       req->crtc_h = patched_crtc_h;
> +
> +       for (i = 0; i < req->nplanes; i++) {
> +               req->bpp[i] = drm_format_plane_cpp(req->pixel_format, i);
> +               if (!req->bpp[i])
> +                       return -EINVAL;
> +
> +               req->offsets[i] += (x_offset + (y_offset * patched_crtc_w)) *
> +                                  req->bpp[i];
> +       }
> +
> +       return atmel_hlcdc_plane_check_update_req(p, req);
> +}
> +
> +int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
> +                               struct atmel_hlcdc_plane_update_req *req)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +       int ret;
> +
> +       ret = atmel_hlcdc_layer_update_start(&plane->layer);
> +       if (ret)
> +               return ret;
> +
> +       atmel_hlcdc_plane_update_pos_and_size(plane, req);
> +       atmel_hlcdc_plane_update_general_settings(plane, req);
> +       atmel_hlcdc_plane_update_format(plane, req);
> +       atmel_hlcdc_plane_update_buffers(plane, req);
> +       atmel_hlcdc_layer_update_set_finished(&plane->layer, req->finished,
> +                                             req->finished_data);
> +
> +       atmel_hlcdc_layer_update_commit(&plane->layer);
> +
> +       return 0;
> +}
> +
> +static int atmel_hlcdc_plane_update(struct drm_plane *p,
> +                                   struct drm_crtc *crtc,
> +                                   struct drm_framebuffer *fb,
> +                                   int crtc_x, int crtc_y,
> +                                   unsigned int crtc_w, unsigned int crtc_h,
> +                                   uint32_t src_x, uint32_t src_y,
> +                                   uint32_t src_w, uint32_t src_h)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +       struct atmel_hlcdc_plane_update_req req;
> +       int ret = 0;
> +       int i;
> +
> +       memset(&req, 0, sizeof(req));
> +       req.crtc_x = crtc_x;
> +       req.crtc_y = crtc_y;
> +       req.crtc_w = crtc_w;
> +       req.crtc_h = crtc_h;
> +       req.src_x = src_x;
> +       req.src_y = src_y;
> +       req.src_w = src_w;
> +       req.src_h = src_h;
> +       req.pixel_format = fb->pixel_format;
> +       req.crtc = crtc;
> +
> +       for (i = 0; i < plane->layer.max_planes; i++) {
> +               req.offsets[i] = fb->offsets[i];
> +               req.pitches[i] = fb->pitches[i];
> +               req.gems[i] = drm_fb_cma_get_gem_obj(fb, i);
> +       }
> +
> +       ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
> +       if (ret)
> +               return ret;
> +
> +       ret = atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
> +       if (ret)
> +               return ret;
> +
> +       drm_framebuffer_reference(fb);
> +       if (plane->base.fb)
> +               drm_framebuffer_unreference(plane->base.fb);
> +       plane->base.fb = fb;
> +
> +       return 0;
> +}
> +
> +static int atmel_hlcdc_plane_disable(struct drm_plane *p)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +
> +       return atmel_hlcdc_layer_disable(&plane->layer);
> +}
> +
> +static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +
> +       if (plane->base.fb)
> +               drm_framebuffer_unreference(plane->base.fb);
> +
> +       atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
> +
> +       drm_plane_cleanup(p);
> +       devm_kfree(p->dev->dev, plane);
> +}
> +
> +static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
> +                                      u8 alpha)
> +{
> +       atmel_hlcdc_layer_update_start(&plane->layer);
> +       atmel_hlcdc_layer_update_cfg(&plane->layer,
> +                                    plane->layer.desc->layout.general_config,
> +                                    ATMEL_HLCDC_LAYER_GA_MASK,
> +                                    alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
> +       atmel_hlcdc_layer_update_commit(&plane->layer);
> +
> +       return 0;
> +}
> +
> +static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
> +                                         struct drm_property *property,
> +                                         uint64_t value)
> +{
> +       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> +       struct atmel_hlcdc_plane_properties *props = plane->properties;
> +
> +       if (property == props->alpha)
> +               atmel_hlcdc_plane_set_alpha(plane, value);
> +       else
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
> +                               const struct atmel_hlcdc_layer_desc *desc,
> +                               struct atmel_hlcdc_plane_properties *props)
> +{
> +       struct regmap *regmap = plane->layer.hlcdc->regmap;
> +
> +       if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
> +           desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
> +               drm_object_attach_property(&plane->base.base,
> +                                          props->alpha, 255);
> +
> +               /* Set default alpha value */
> +               regmap_update_bits(regmap,
> +                               desc->regs_offset +
> +                               ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
> +                               ATMEL_HLCDC_LAYER_GA_MASK,
> +                               ATMEL_HLCDC_LAYER_GA_MASK);
> +       }
> +
> +       if (desc->layout.csc) {
> +               /*
> +                * TODO: decare a "yuv-to-rgb-conv-factors" property to let
> +                * userspace modify these factors (using a BLOB property ?).
> +                */
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
> +                            0x4c900091);
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
> +                            0x7a5f5090);
> +               regmap_write(regmap,
> +                            desc->regs_offset +
> +                            ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
> +                            0x40040890);
> +       }
> +}
> +
> +static struct drm_plane_funcs layer_plane_funcs = {
> +       .update_plane = atmel_hlcdc_plane_update,
> +       .disable_plane = atmel_hlcdc_plane_disable,
> +       .set_property = atmel_hlcdc_plane_set_property,
> +       .destroy = atmel_hlcdc_plane_destroy,
> +};
> +
> +static struct atmel_hlcdc_plane *
> +atmel_hlcdc_plane_create(struct drm_device *dev,
> +                        const struct atmel_hlcdc_layer_desc *desc,
> +                        struct atmel_hlcdc_plane_properties *props)
> +{
> +       struct atmel_hlcdc_plane *plane;
> +       enum drm_plane_type type;
> +       int ret;
> +
> +       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
> +       if (!plane)
> +               return ERR_PTR(-ENOMEM);
> +
> +       ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       if (desc->type == ATMEL_HLCDC_BASE_LAYER)
> +               type = DRM_PLANE_TYPE_PRIMARY;
> +       else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
> +               type = DRM_PLANE_TYPE_CURSOR;
> +       else
> +               type = DRM_PLANE_TYPE_OVERLAY;
> +
> +       ret = drm_universal_plane_init(dev, &plane->base, 0,
> +                                      &layer_plane_funcs,
> +                                      desc->formats->formats,
> +                                      desc->formats->nformats, type);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       /* Set default property values*/
> +       atmel_hlcdc_plane_init_properties(plane, desc, props);
> +
> +       return plane;
> +}
> +
> +static struct atmel_hlcdc_plane_properties *
> +atmel_hlcdc_plane_create_properties(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_plane_properties *props;
> +
> +       props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
> +       if (!props)
> +               return ERR_PTR(-ENOMEM);
> +
> +       props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
> +       if (!props->alpha)
> +               return ERR_PTR(-ENOMEM);
> +
> +       return props;
> +}
> +
> +struct atmel_hlcdc_planes *
> +atmel_hlcdc_create_planes(struct drm_device *dev)
> +{
> +       struct atmel_hlcdc_dc *dc = dev->dev_private;
> +       struct atmel_hlcdc_plane_properties *props;
> +       struct atmel_hlcdc_planes *planes;
> +       const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
> +       int nlayers = dc->desc->nlayers;
> +       int i;
> +
> +       planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
> +       if (!planes)
> +               return ERR_PTR(-ENOMEM);
> +
> +       for (i = 0; i < nlayers; i++) {
> +               if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
> +                       planes->noverlays++;
> +       }
> +
> +       if (planes->noverlays) {
> +               planes->overlays = devm_kzalloc(dev->dev,
> +                                               planes->noverlays *
> +                                               sizeof(*planes->overlays),
> +                                               GFP_KERNEL);
> +               if (!planes->overlays)
> +                       return ERR_PTR(-ENOMEM);
> +       }
> +
> +       props = atmel_hlcdc_plane_create_properties(dev);
> +       if (IS_ERR(props))
> +               return ERR_CAST(props);
> +
> +       planes->noverlays = 0;
> +       for (i = 0; i < nlayers; i++) {
> +               struct atmel_hlcdc_plane *plane;
> +
> +               if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
> +                       continue;
> +
> +               plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
> +               if (IS_ERR(plane))
> +                       return ERR_CAST(plane);
> +
> +               plane->properties = props;
> +
> +               switch (descs[i].type) {
> +               case ATMEL_HLCDC_BASE_LAYER:
> +                       if (planes->primary)
> +                               return ERR_PTR(-EINVAL);
> +                       planes->primary = plane;
> +                       break;
> +
> +               case ATMEL_HLCDC_OVERLAY_LAYER:
> +                       planes->overlays[planes->noverlays++] = plane;
> +                       break;
> +
> +               case ATMEL_HLCDC_CURSOR_LAYER:
> +                       if (planes->cursor)
> +                               return ERR_PTR(-EINVAL);
> +                       planes->cursor = plane;
> +                       break;
> +
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       return planes;
> +}
> --
> 1.8.3.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08  3:45   ` Rob Clark
@ 2014-07-08  7:23       ` Boris BREZILLON
  2014-07-09  8:18       ` Boris BREZILLON
  1 sibling, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08  7:23 UTC (permalink / raw)
  To: Rob Clark
  Cc: Mark Rutland, devicetree, David Airlie, Nicolas Ferre, dri-devel,
	Thierry Reding, Alexandre Belloni, Laurent Pinchart, Bo Shen,
	Lee Jones, Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Robert Nelson, Andrew Victor,
	linux-arm-kernel

Hello Rob,

On Mon, 7 Jul 2014 23:45:54 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> >
> > This display controller supports at least one primary plane and might
> > provide several overlays and an hardware cursor depending on the IP
> > version.
> >
> > At the moment, this driver only implements an RGB connector to interface
> > with LCD panels, but support for other kind of external devices (like DRM
> > bridges) might be added later.
> >
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  drivers/gpu/drm/Kconfig                         |   2 +
> >  drivers/gpu/drm/Makefile                        |   1 +
> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >  11 files changed, 3382 insertions(+)
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index d1cc2f6..df6f0c1 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"

[...]

> > +
> > +/**
> > + * Atmel HLCDC Plane properties.
> > + *
> > + * This structure stores plane property definitions.
> > + *
> > + * @alpha: alpha blending (or transparency) property
> > + * @csc: YUV to RGB conversion factors property
> > + */
> > +struct atmel_hlcdc_plane_properties {
> > +       struct drm_property *alpha;
> > +       struct drm_property *csc;
> 
> appears like csc is not used yet, so I suppose you can drop it for
> now..  when you do add it, don't forget to update drm.tmp.  But for
> now it at least makes review easier when the driver doesn't add new
> userspace interfaces :-)


Sure, I guess this is a leftover from another patch I made to add Color
Space Conversion configuration.

I'll remove it for the next version.

> 
> > +};
> > +
> > +/**
> > + * Atmel HLCDC Plane.
> > + *
> > + * @base: base DRM plane structure
> > + * @layer: HLCDC layer structure
> > + * @properties: pointer to the property definitions structure
> > + * @alpha: current alpha blending (or transparency) status
> > + */
> > +struct atmel_hlcdc_plane {
> > +       struct drm_plane base;
> > +       struct atmel_hlcdc_layer layer;
> > +       struct atmel_hlcdc_plane_properties *properties;
> > +};
> > +
> > +static inline struct atmel_hlcdc_plane *
> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> > +{
> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> > +}
> > +
> > +static inline struct atmel_hlcdc_plane *
> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> > +{
> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> > +}
> > +
> > +/**
> > + * Atmel HLCDC Plane update request structure.
> > + *
> > + * @crtc_x: x position of the plane relative to the CRTC
> > + * @crtc_y: y position of the plane relative to the CRTC
> > + * @crtc_w: visible width of the plane
> > + * @crtc_h: visible height of the plane
> > + * @src_x: x buffer position
> > + * @src_y: y buffer position
> > + * @src_w: buffer width
> > + * @src_h: buffer height
> > + * @pixel_format: pixel format
> > + * @gems: GEM object object containing image buffers
> > + * @offsets: offsets to apply to the GEM buffers
> > + * @pitches: line size in bytes
> > + * @crtc: crtc to display on
> > + * @finished: finished callback
> > + * @finished_data: data passed to the finished callback
> > + * @bpp: bytes per pixel deduced from pixel_format
> > + * @xstride: value to add to the pixel pointer between each line
> > + * @pstride: value to add to the pixel pointer between each pixel
> > + * @nplanes: number of planes (deduced from pixel_format)
> > + */
> > +struct atmel_hlcdc_plane_update_req {
> > +       int crtc_x;
> > +       int crtc_y;
> > +       unsigned int crtc_w;
> > +       unsigned int crtc_h;
> > +       uint32_t src_x;
> > +       uint32_t src_y;
> > +       uint32_t src_w;
> > +       uint32_t src_h;
> > +       uint32_t pixel_format;
> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> 
> tbh, I've only looked closely, but I don't completely follow all the
> layering here..  I wonder if we'd be better off just moving 'struct
> drm_fb_cma' to header file so you could get the gem objects / pixel
> fmt / width / height directly from the fb object (and then you can
> reference count things at the fb level, rather than at the individual
> gem obj level, too)
> 

Actually, the HW cursor is a drm_plane too, and in this case I cannot
retrieve a drm_fb_cma object, but just a single GEM object (see
atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).

Let me know if you see a better solution.

Best Regards,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08  7:23       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Rob,

On Mon, 7 Jul 2014 23:45:54 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> >
> > This display controller supports at least one primary plane and might
> > provide several overlays and an hardware cursor depending on the IP
> > version.
> >
> > At the moment, this driver only implements an RGB connector to interface
> > with LCD panels, but support for other kind of external devices (like DRM
> > bridges) might be added later.
> >
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  drivers/gpu/drm/Kconfig                         |   2 +
> >  drivers/gpu/drm/Makefile                        |   1 +
> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >  11 files changed, 3382 insertions(+)
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index d1cc2f6..df6f0c1 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"

[...]

> > +
> > +/**
> > + * Atmel HLCDC Plane properties.
> > + *
> > + * This structure stores plane property definitions.
> > + *
> > + * @alpha: alpha blending (or transparency) property
> > + * @csc: YUV to RGB conversion factors property
> > + */
> > +struct atmel_hlcdc_plane_properties {
> > +       struct drm_property *alpha;
> > +       struct drm_property *csc;
> 
> appears like csc is not used yet, so I suppose you can drop it for
> now..  when you do add it, don't forget to update drm.tmp.  But for
> now it at least makes review easier when the driver doesn't add new
> userspace interfaces :-)


Sure, I guess this is a leftover from another patch I made to add Color
Space Conversion configuration.

I'll remove it for the next version.

> 
> > +};
> > +
> > +/**
> > + * Atmel HLCDC Plane.
> > + *
> > + * @base: base DRM plane structure
> > + * @layer: HLCDC layer structure
> > + * @properties: pointer to the property definitions structure
> > + * @alpha: current alpha blending (or transparency) status
> > + */
> > +struct atmel_hlcdc_plane {
> > +       struct drm_plane base;
> > +       struct atmel_hlcdc_layer layer;
> > +       struct atmel_hlcdc_plane_properties *properties;
> > +};
> > +
> > +static inline struct atmel_hlcdc_plane *
> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> > +{
> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> > +}
> > +
> > +static inline struct atmel_hlcdc_plane *
> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> > +{
> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> > +}
> > +
> > +/**
> > + * Atmel HLCDC Plane update request structure.
> > + *
> > + * @crtc_x: x position of the plane relative to the CRTC
> > + * @crtc_y: y position of the plane relative to the CRTC
> > + * @crtc_w: visible width of the plane
> > + * @crtc_h: visible height of the plane
> > + * @src_x: x buffer position
> > + * @src_y: y buffer position
> > + * @src_w: buffer width
> > + * @src_h: buffer height
> > + * @pixel_format: pixel format
> > + * @gems: GEM object object containing image buffers
> > + * @offsets: offsets to apply to the GEM buffers
> > + * @pitches: line size in bytes
> > + * @crtc: crtc to display on
> > + * @finished: finished callback
> > + * @finished_data: data passed to the finished callback
> > + * @bpp: bytes per pixel deduced from pixel_format
> > + * @xstride: value to add to the pixel pointer between each line
> > + * @pstride: value to add to the pixel pointer between each pixel
> > + * @nplanes: number of planes (deduced from pixel_format)
> > + */
> > +struct atmel_hlcdc_plane_update_req {
> > +       int crtc_x;
> > +       int crtc_y;
> > +       unsigned int crtc_w;
> > +       unsigned int crtc_h;
> > +       uint32_t src_x;
> > +       uint32_t src_y;
> > +       uint32_t src_w;
> > +       uint32_t src_h;
> > +       uint32_t pixel_format;
> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> 
> tbh, I've only looked closely, but I don't completely follow all the
> layering here..  I wonder if we'd be better off just moving 'struct
> drm_fb_cma' to header file so you could get the gem objects / pixel
> fmt / width / height directly from the fb object (and then you can
> reference count things at the fb level, rather than at the individual
> gem obj level, too)
> 

Actually, the HW cursor is a drm_plane too, and in this case I cannot
retrieve a drm_fb_cma object, but just a single GEM object (see
atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).

Let me know if you see a better solution.

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08  7:23       ` Boris BREZILLON
@ 2014-07-08 12:49         ` Rob Clark
  -1 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-08 12:49 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> Hello Rob,
>
> On Mon, 7 Jul 2014 23:45:54 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> > controller device.
>> >
>> > This display controller supports at least one primary plane and might
>> > provide several overlays and an hardware cursor depending on the IP
>> > version.
>> >
>> > At the moment, this driver only implements an RGB connector to interface
>> > with LCD panels, but support for other kind of external devices (like DRM
>> > bridges) might be added later.
>> >
>> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> > ---
>> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >  drivers/gpu/drm/Makefile                        |   1 +
>> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >  11 files changed, 3382 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index d1cc2f6..df6f0c1 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>
> [...]
>
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane properties.
>> > + *
>> > + * This structure stores plane property definitions.
>> > + *
>> > + * @alpha: alpha blending (or transparency) property
>> > + * @csc: YUV to RGB conversion factors property
>> > + */
>> > +struct atmel_hlcdc_plane_properties {
>> > +       struct drm_property *alpha;
>> > +       struct drm_property *csc;
>>
>> appears like csc is not used yet, so I suppose you can drop it for
>> now..  when you do add it, don't forget to update drm.tmp.  But for
>> now it at least makes review easier when the driver doesn't add new
>> userspace interfaces :-)
>
>
> Sure, I guess this is a leftover from another patch I made to add Color
> Space Conversion configuration.
>
> I'll remove it for the next version.
>
>>
>> > +};
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane.
>> > + *
>> > + * @base: base DRM plane structure
>> > + * @layer: HLCDC layer structure
>> > + * @properties: pointer to the property definitions structure
>> > + * @alpha: current alpha blending (or transparency) status
>> > + */
>> > +struct atmel_hlcdc_plane {
>> > +       struct drm_plane base;
>> > +       struct atmel_hlcdc_layer layer;
>> > +       struct atmel_hlcdc_plane_properties *properties;
>> > +};
>> > +
>> > +static inline struct atmel_hlcdc_plane *
>> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
>> > +{
>> > +       return container_of(p, struct atmel_hlcdc_plane, base);
>> > +}
>> > +
>> > +static inline struct atmel_hlcdc_plane *
>> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
>> > +{
>> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
>> > +}
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane update request structure.
>> > + *
>> > + * @crtc_x: x position of the plane relative to the CRTC
>> > + * @crtc_y: y position of the plane relative to the CRTC
>> > + * @crtc_w: visible width of the plane
>> > + * @crtc_h: visible height of the plane
>> > + * @src_x: x buffer position
>> > + * @src_y: y buffer position
>> > + * @src_w: buffer width
>> > + * @src_h: buffer height
>> > + * @pixel_format: pixel format
>> > + * @gems: GEM object object containing image buffers
>> > + * @offsets: offsets to apply to the GEM buffers
>> > + * @pitches: line size in bytes
>> > + * @crtc: crtc to display on
>> > + * @finished: finished callback
>> > + * @finished_data: data passed to the finished callback
>> > + * @bpp: bytes per pixel deduced from pixel_format
>> > + * @xstride: value to add to the pixel pointer between each line
>> > + * @pstride: value to add to the pixel pointer between each pixel
>> > + * @nplanes: number of planes (deduced from pixel_format)
>> > + */
>> > +struct atmel_hlcdc_plane_update_req {
>> > +       int crtc_x;
>> > +       int crtc_y;
>> > +       unsigned int crtc_w;
>> > +       unsigned int crtc_h;
>> > +       uint32_t src_x;
>> > +       uint32_t src_y;
>> > +       uint32_t src_w;
>> > +       uint32_t src_h;
>> > +       uint32_t pixel_format;
>> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
>> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
>> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
>>
>> tbh, I've only looked closely, but I don't completely follow all the
>> layering here..  I wonder if we'd be better off just moving 'struct
>> drm_fb_cma' to header file so you could get the gem objects / pixel
>> fmt / width / height directly from the fb object (and then you can
>> reference count things at the fb level, rather than at the individual
>> gem obj level, too)
>>
>
> Actually, the HW cursor is a drm_plane too, and in this case I cannot
> retrieve a drm_fb_cma object, but just a single GEM object (see
> atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).

oh, right..  well maybe for the cursor case it would be possible to
wrap up the gem bo with an internally created fb?  Not sure if that
ends up simplifying things or not, so it is definitely your call.  But
at least my experience with other drivers (that did not use a plane as
a cursor internally) was that I could simplify things after fb gained
refcnt'ing.

BR,
-R

> Let me know if you see a better solution.
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08 12:49         ` Rob Clark
  0 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-08 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> Hello Rob,
>
> On Mon, 7 Jul 2014 23:45:54 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> > controller device.
>> >
>> > This display controller supports at least one primary plane and might
>> > provide several overlays and an hardware cursor depending on the IP
>> > version.
>> >
>> > At the moment, this driver only implements an RGB connector to interface
>> > with LCD panels, but support for other kind of external devices (like DRM
>> > bridges) might be added later.
>> >
>> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> > ---
>> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >  drivers/gpu/drm/Makefile                        |   1 +
>> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >  11 files changed, 3382 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index d1cc2f6..df6f0c1 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>
> [...]
>
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane properties.
>> > + *
>> > + * This structure stores plane property definitions.
>> > + *
>> > + * @alpha: alpha blending (or transparency) property
>> > + * @csc: YUV to RGB conversion factors property
>> > + */
>> > +struct atmel_hlcdc_plane_properties {
>> > +       struct drm_property *alpha;
>> > +       struct drm_property *csc;
>>
>> appears like csc is not used yet, so I suppose you can drop it for
>> now..  when you do add it, don't forget to update drm.tmp.  But for
>> now it at least makes review easier when the driver doesn't add new
>> userspace interfaces :-)
>
>
> Sure, I guess this is a leftover from another patch I made to add Color
> Space Conversion configuration.
>
> I'll remove it for the next version.
>
>>
>> > +};
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane.
>> > + *
>> > + * @base: base DRM plane structure
>> > + * @layer: HLCDC layer structure
>> > + * @properties: pointer to the property definitions structure
>> > + * @alpha: current alpha blending (or transparency) status
>> > + */
>> > +struct atmel_hlcdc_plane {
>> > +       struct drm_plane base;
>> > +       struct atmel_hlcdc_layer layer;
>> > +       struct atmel_hlcdc_plane_properties *properties;
>> > +};
>> > +
>> > +static inline struct atmel_hlcdc_plane *
>> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
>> > +{
>> > +       return container_of(p, struct atmel_hlcdc_plane, base);
>> > +}
>> > +
>> > +static inline struct atmel_hlcdc_plane *
>> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
>> > +{
>> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
>> > +}
>> > +
>> > +/**
>> > + * Atmel HLCDC Plane update request structure.
>> > + *
>> > + * @crtc_x: x position of the plane relative to the CRTC
>> > + * @crtc_y: y position of the plane relative to the CRTC
>> > + * @crtc_w: visible width of the plane
>> > + * @crtc_h: visible height of the plane
>> > + * @src_x: x buffer position
>> > + * @src_y: y buffer position
>> > + * @src_w: buffer width
>> > + * @src_h: buffer height
>> > + * @pixel_format: pixel format
>> > + * @gems: GEM object object containing image buffers
>> > + * @offsets: offsets to apply to the GEM buffers
>> > + * @pitches: line size in bytes
>> > + * @crtc: crtc to display on
>> > + * @finished: finished callback
>> > + * @finished_data: data passed to the finished callback
>> > + * @bpp: bytes per pixel deduced from pixel_format
>> > + * @xstride: value to add to the pixel pointer between each line
>> > + * @pstride: value to add to the pixel pointer between each pixel
>> > + * @nplanes: number of planes (deduced from pixel_format)
>> > + */
>> > +struct atmel_hlcdc_plane_update_req {
>> > +       int crtc_x;
>> > +       int crtc_y;
>> > +       unsigned int crtc_w;
>> > +       unsigned int crtc_h;
>> > +       uint32_t src_x;
>> > +       uint32_t src_y;
>> > +       uint32_t src_w;
>> > +       uint32_t src_h;
>> > +       uint32_t pixel_format;
>> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
>> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
>> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
>>
>> tbh, I've only looked closely, but I don't completely follow all the
>> layering here..  I wonder if we'd be better off just moving 'struct
>> drm_fb_cma' to header file so you could get the gem objects / pixel
>> fmt / width / height directly from the fb object (and then you can
>> reference count things at the fb level, rather than at the individual
>> gem obj level, too)
>>
>
> Actually, the HW cursor is a drm_plane too, and in this case I cannot
> retrieve a drm_fb_cma object, but just a single GEM object (see
> atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).

oh, right..  well maybe for the cursor case it would be possible to
wrap up the gem bo with an internally created fb?  Not sure if that
ends up simplifying things or not, so it is definitely your call.  But
at least my experience with other drivers (that did not use a plane as
a cursor internally) was that I could simplify things after fb gained
refcnt'ing.

BR,
-R

> Let me know if you see a better solution.
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08 12:49         ` Rob Clark
@ 2014-07-08 14:37           ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08 14:37 UTC (permalink / raw)
  To: Rob Clark
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Tue, 8 Jul 2014 08:49:41 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > Hello Rob,
> >
> > On Mon, 7 Jul 2014 23:45:54 -0400
> > Rob Clark <robdclark@gmail.com> wrote:
> >
> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> >> <boris.brezillon@free-electrons.com> wrote:
> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> >> > controller device.
> >> >
> >> > This display controller supports at least one primary plane and might
> >> > provide several overlays and an hardware cursor depending on the IP
> >> > version.
> >> >
> >> > At the moment, this driver only implements an RGB connector to interface
> >> > with LCD panels, but support for other kind of external devices (like DRM
> >> > bridges) might be added later.
> >> >
> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >> > ---
> >> >  drivers/gpu/drm/Kconfig                         |   2 +
> >> >  drivers/gpu/drm/Makefile                        |   1 +
> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >> >  11 files changed, 3382 insertions(+)
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >> >
> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> > index d1cc2f6..df6f0c1 100644
> >> > --- a/drivers/gpu/drm/Kconfig
> >> > +++ b/drivers/gpu/drm/Kconfig
> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >
> > [...]
> >
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane properties.
> >> > + *
> >> > + * This structure stores plane property definitions.
> >> > + *
> >> > + * @alpha: alpha blending (or transparency) property
> >> > + * @csc: YUV to RGB conversion factors property
> >> > + */
> >> > +struct atmel_hlcdc_plane_properties {
> >> > +       struct drm_property *alpha;
> >> > +       struct drm_property *csc;
> >>
> >> appears like csc is not used yet, so I suppose you can drop it for
> >> now..  when you do add it, don't forget to update drm.tmp.  But for
> >> now it at least makes review easier when the driver doesn't add new
> >> userspace interfaces :-)
> >
> >
> > Sure, I guess this is a leftover from another patch I made to add Color
> > Space Conversion configuration.
> >
> > I'll remove it for the next version.
> >
> >>
> >> > +};
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane.
> >> > + *
> >> > + * @base: base DRM plane structure
> >> > + * @layer: HLCDC layer structure
> >> > + * @properties: pointer to the property definitions structure
> >> > + * @alpha: current alpha blending (or transparency) status
> >> > + */
> >> > +struct atmel_hlcdc_plane {
> >> > +       struct drm_plane base;
> >> > +       struct atmel_hlcdc_layer layer;
> >> > +       struct atmel_hlcdc_plane_properties *properties;
> >> > +};
> >> > +
> >> > +static inline struct atmel_hlcdc_plane *
> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> >> > +{
> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> >> > +}
> >> > +
> >> > +static inline struct atmel_hlcdc_plane *
> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> >> > +{
> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> >> > +}
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane update request structure.
> >> > + *
> >> > + * @crtc_x: x position of the plane relative to the CRTC
> >> > + * @crtc_y: y position of the plane relative to the CRTC
> >> > + * @crtc_w: visible width of the plane
> >> > + * @crtc_h: visible height of the plane
> >> > + * @src_x: x buffer position
> >> > + * @src_y: y buffer position
> >> > + * @src_w: buffer width
> >> > + * @src_h: buffer height
> >> > + * @pixel_format: pixel format
> >> > + * @gems: GEM object object containing image buffers
> >> > + * @offsets: offsets to apply to the GEM buffers
> >> > + * @pitches: line size in bytes
> >> > + * @crtc: crtc to display on
> >> > + * @finished: finished callback
> >> > + * @finished_data: data passed to the finished callback
> >> > + * @bpp: bytes per pixel deduced from pixel_format
> >> > + * @xstride: value to add to the pixel pointer between each line
> >> > + * @pstride: value to add to the pixel pointer between each pixel
> >> > + * @nplanes: number of planes (deduced from pixel_format)
> >> > + */
> >> > +struct atmel_hlcdc_plane_update_req {
> >> > +       int crtc_x;
> >> > +       int crtc_y;
> >> > +       unsigned int crtc_w;
> >> > +       unsigned int crtc_h;
> >> > +       uint32_t src_x;
> >> > +       uint32_t src_y;
> >> > +       uint32_t src_w;
> >> > +       uint32_t src_h;
> >> > +       uint32_t pixel_format;
> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> >>
> >> tbh, I've only looked closely, but I don't completely follow all the
> >> layering here..  I wonder if we'd be better off just moving 'struct
> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> >> fmt / width / height directly from the fb object (and then you can
> >> reference count things at the fb level, rather than at the individual
> >> gem obj level, too)
> >>
> >
> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> > retrieve a drm_fb_cma object, but just a single GEM object (see
> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> 
> oh, right..  well maybe for the cursor case it would be possible to
> wrap up the gem bo with an internally created fb?  Not sure if that
> ends up simplifying things or not, so it is definitely your call.  But
> at least my experience with other drivers (that did not use a plane as
> a cursor internally) was that I could simplify things after fb gained
> refcnt'ing.

Unless I'm missing something, I'd say moving to fb objects instead of
GEM objects won't simplify the code much (I'm already refcnt'ing GEM
objects when launching a DMA transfer for a plane update).

The only benefit I can see is consistency with other drivers (which in
fact is a good point).
Indeed atmel_hlcdc_plane_update_req redefines some fields which are
already availables in drm_fb_cma or drm_framebuffer:

- gems (called objs in drm_fb_cma)
- pixel_format
- pitches (offsets must be redefined because it is modified in
  atmel_hlcdc_plane_prepare_update_req)

Anyway, I'll give it a try.

Thanks for your review.

In the meantime, I realized I hadn't subscribed to the dri-devel
ML, which might explain why I didn't get any reviews from DRM
maintainers/developers so far :-).

Best Regards,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08 14:37           ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 8 Jul 2014 08:49:41 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > Hello Rob,
> >
> > On Mon, 7 Jul 2014 23:45:54 -0400
> > Rob Clark <robdclark@gmail.com> wrote:
> >
> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> >> <boris.brezillon@free-electrons.com> wrote:
> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> >> > controller device.
> >> >
> >> > This display controller supports at least one primary plane and might
> >> > provide several overlays and an hardware cursor depending on the IP
> >> > version.
> >> >
> >> > At the moment, this driver only implements an RGB connector to interface
> >> > with LCD panels, but support for other kind of external devices (like DRM
> >> > bridges) might be added later.
> >> >
> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >> > ---
> >> >  drivers/gpu/drm/Kconfig                         |   2 +
> >> >  drivers/gpu/drm/Makefile                        |   1 +
> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >> >  11 files changed, 3382 insertions(+)
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >> >
> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> > index d1cc2f6..df6f0c1 100644
> >> > --- a/drivers/gpu/drm/Kconfig
> >> > +++ b/drivers/gpu/drm/Kconfig
> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >
> > [...]
> >
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane properties.
> >> > + *
> >> > + * This structure stores plane property definitions.
> >> > + *
> >> > + * @alpha: alpha blending (or transparency) property
> >> > + * @csc: YUV to RGB conversion factors property
> >> > + */
> >> > +struct atmel_hlcdc_plane_properties {
> >> > +       struct drm_property *alpha;
> >> > +       struct drm_property *csc;
> >>
> >> appears like csc is not used yet, so I suppose you can drop it for
> >> now..  when you do add it, don't forget to update drm.tmp.  But for
> >> now it at least makes review easier when the driver doesn't add new
> >> userspace interfaces :-)
> >
> >
> > Sure, I guess this is a leftover from another patch I made to add Color
> > Space Conversion configuration.
> >
> > I'll remove it for the next version.
> >
> >>
> >> > +};
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane.
> >> > + *
> >> > + * @base: base DRM plane structure
> >> > + * @layer: HLCDC layer structure
> >> > + * @properties: pointer to the property definitions structure
> >> > + * @alpha: current alpha blending (or transparency) status
> >> > + */
> >> > +struct atmel_hlcdc_plane {
> >> > +       struct drm_plane base;
> >> > +       struct atmel_hlcdc_layer layer;
> >> > +       struct atmel_hlcdc_plane_properties *properties;
> >> > +};
> >> > +
> >> > +static inline struct atmel_hlcdc_plane *
> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> >> > +{
> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> >> > +}
> >> > +
> >> > +static inline struct atmel_hlcdc_plane *
> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> >> > +{
> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> >> > +}
> >> > +
> >> > +/**
> >> > + * Atmel HLCDC Plane update request structure.
> >> > + *
> >> > + * @crtc_x: x position of the plane relative to the CRTC
> >> > + * @crtc_y: y position of the plane relative to the CRTC
> >> > + * @crtc_w: visible width of the plane
> >> > + * @crtc_h: visible height of the plane
> >> > + * @src_x: x buffer position
> >> > + * @src_y: y buffer position
> >> > + * @src_w: buffer width
> >> > + * @src_h: buffer height
> >> > + * @pixel_format: pixel format
> >> > + * @gems: GEM object object containing image buffers
> >> > + * @offsets: offsets to apply to the GEM buffers
> >> > + * @pitches: line size in bytes
> >> > + * @crtc: crtc to display on
> >> > + * @finished: finished callback
> >> > + * @finished_data: data passed to the finished callback
> >> > + * @bpp: bytes per pixel deduced from pixel_format
> >> > + * @xstride: value to add to the pixel pointer between each line
> >> > + * @pstride: value to add to the pixel pointer between each pixel
> >> > + * @nplanes: number of planes (deduced from pixel_format)
> >> > + */
> >> > +struct atmel_hlcdc_plane_update_req {
> >> > +       int crtc_x;
> >> > +       int crtc_y;
> >> > +       unsigned int crtc_w;
> >> > +       unsigned int crtc_h;
> >> > +       uint32_t src_x;
> >> > +       uint32_t src_y;
> >> > +       uint32_t src_w;
> >> > +       uint32_t src_h;
> >> > +       uint32_t pixel_format;
> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> >>
> >> tbh, I've only looked closely, but I don't completely follow all the
> >> layering here..  I wonder if we'd be better off just moving 'struct
> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> >> fmt / width / height directly from the fb object (and then you can
> >> reference count things at the fb level, rather than at the individual
> >> gem obj level, too)
> >>
> >
> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> > retrieve a drm_fb_cma object, but just a single GEM object (see
> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> 
> oh, right..  well maybe for the cursor case it would be possible to
> wrap up the gem bo with an internally created fb?  Not sure if that
> ends up simplifying things or not, so it is definitely your call.  But
> at least my experience with other drivers (that did not use a plane as
> a cursor internally) was that I could simplify things after fb gained
> refcnt'ing.

Unless I'm missing something, I'd say moving to fb objects instead of
GEM objects won't simplify the code much (I'm already refcnt'ing GEM
objects when launching a DMA transfer for a plane update).

The only benefit I can see is consistency with other drivers (which in
fact is a good point).
Indeed atmel_hlcdc_plane_update_req redefines some fields which are
already availables in drm_fb_cma or drm_framebuffer:

- gems (called objs in drm_fb_cma)
- pixel_format
- pitches (offsets must be redefined because it is modified in
  atmel_hlcdc_plane_prepare_update_req)

Anyway, I'll give it a try.

Thanks for your review.

In the meantime, I realized I hadn't subscribed to the dri-devel
ML, which might explain why I didn't get any reviews from DRM
maintainers/developers so far :-).

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08 14:37           ` Boris BREZILLON
@ 2014-07-08 15:41             ` Rob Clark
  -1 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-08 15:41 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> On Tue, 8 Jul 2014 08:49:41 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > Hello Rob,
>> >
>> > On Mon, 7 Jul 2014 23:45:54 -0400
>> > Rob Clark <robdclark@gmail.com> wrote:
>> >
>> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> >> <boris.brezillon@free-electrons.com> wrote:
>> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> >> > controller device.
>> >> >
>> >> > This display controller supports at least one primary plane and might
>> >> > provide several overlays and an hardware cursor depending on the IP
>> >> > version.
>> >> >
>> >> > At the moment, this driver only implements an RGB connector to interface
>> >> > with LCD panels, but support for other kind of external devices (like DRM
>> >> > bridges) might be added later.
>> >> >
>> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> >> > ---
>> >> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >> >  drivers/gpu/drm/Makefile                        |   1 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >> >  11 files changed, 3382 insertions(+)
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >> >
>> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> >> > index d1cc2f6..df6f0c1 100644
>> >> > --- a/drivers/gpu/drm/Kconfig
>> >> > +++ b/drivers/gpu/drm/Kconfig
>> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>> >
>> > [...]
>> >
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane properties.
>> >> > + *
>> >> > + * This structure stores plane property definitions.
>> >> > + *
>> >> > + * @alpha: alpha blending (or transparency) property
>> >> > + * @csc: YUV to RGB conversion factors property
>> >> > + */
>> >> > +struct atmel_hlcdc_plane_properties {
>> >> > +       struct drm_property *alpha;
>> >> > +       struct drm_property *csc;
>> >>
>> >> appears like csc is not used yet, so I suppose you can drop it for
>> >> now..  when you do add it, don't forget to update drm.tmp.  But for
>> >> now it at least makes review easier when the driver doesn't add new
>> >> userspace interfaces :-)
>> >
>> >
>> > Sure, I guess this is a leftover from another patch I made to add Color
>> > Space Conversion configuration.
>> >
>> > I'll remove it for the next version.
>> >
>> >>
>> >> > +};
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane.
>> >> > + *
>> >> > + * @base: base DRM plane structure
>> >> > + * @layer: HLCDC layer structure
>> >> > + * @properties: pointer to the property definitions structure
>> >> > + * @alpha: current alpha blending (or transparency) status
>> >> > + */
>> >> > +struct atmel_hlcdc_plane {
>> >> > +       struct drm_plane base;
>> >> > +       struct atmel_hlcdc_layer layer;
>> >> > +       struct atmel_hlcdc_plane_properties *properties;
>> >> > +};
>> >> > +
>> >> > +static inline struct atmel_hlcdc_plane *
>> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
>> >> > +{
>> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
>> >> > +}
>> >> > +
>> >> > +static inline struct atmel_hlcdc_plane *
>> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
>> >> > +{
>> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
>> >> > +}
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane update request structure.
>> >> > + *
>> >> > + * @crtc_x: x position of the plane relative to the CRTC
>> >> > + * @crtc_y: y position of the plane relative to the CRTC
>> >> > + * @crtc_w: visible width of the plane
>> >> > + * @crtc_h: visible height of the plane
>> >> > + * @src_x: x buffer position
>> >> > + * @src_y: y buffer position
>> >> > + * @src_w: buffer width
>> >> > + * @src_h: buffer height
>> >> > + * @pixel_format: pixel format
>> >> > + * @gems: GEM object object containing image buffers
>> >> > + * @offsets: offsets to apply to the GEM buffers
>> >> > + * @pitches: line size in bytes
>> >> > + * @crtc: crtc to display on
>> >> > + * @finished: finished callback
>> >> > + * @finished_data: data passed to the finished callback
>> >> > + * @bpp: bytes per pixel deduced from pixel_format
>> >> > + * @xstride: value to add to the pixel pointer between each line
>> >> > + * @pstride: value to add to the pixel pointer between each pixel
>> >> > + * @nplanes: number of planes (deduced from pixel_format)
>> >> > + */
>> >> > +struct atmel_hlcdc_plane_update_req {
>> >> > +       int crtc_x;
>> >> > +       int crtc_y;
>> >> > +       unsigned int crtc_w;
>> >> > +       unsigned int crtc_h;
>> >> > +       uint32_t src_x;
>> >> > +       uint32_t src_y;
>> >> > +       uint32_t src_w;
>> >> > +       uint32_t src_h;
>> >> > +       uint32_t pixel_format;
>> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
>> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
>> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
>> >>
>> >> tbh, I've only looked closely, but I don't completely follow all the
>> >> layering here..  I wonder if we'd be better off just moving 'struct
>> >> drm_fb_cma' to header file so you could get the gem objects / pixel
>> >> fmt / width / height directly from the fb object (and then you can
>> >> reference count things at the fb level, rather than at the individual
>> >> gem obj level, too)
>> >>
>> >
>> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
>> > retrieve a drm_fb_cma object, but just a single GEM object (see
>> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
>>
>> oh, right..  well maybe for the cursor case it would be possible to
>> wrap up the gem bo with an internally created fb?  Not sure if that
>> ends up simplifying things or not, so it is definitely your call.  But
>> at least my experience with other drivers (that did not use a plane as
>> a cursor internally) was that I could simplify things after fb gained
>> refcnt'ing.
>
> Unless I'm missing something, I'd say moving to fb objects instead of
> GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> objects when launching a DMA transfer for a plane update).

yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
thing instead of loop over N objects, etc.  Nothing earth-shattering.

BR,
-R

> The only benefit I can see is consistency with other drivers (which in
> fact is a good point).
> Indeed atmel_hlcdc_plane_update_req redefines some fields which are
> already availables in drm_fb_cma or drm_framebuffer:
>
> - gems (called objs in drm_fb_cma)
> - pixel_format
> - pitches (offsets must be redefined because it is modified in
>   atmel_hlcdc_plane_prepare_update_req)
>
> Anyway, I'll give it a try.
>
> Thanks for your review.
>
> In the meantime, I realized I hadn't subscribed to the dri-devel
> ML, which might explain why I didn't get any reviews from DRM
> maintainers/developers so far :-).
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08 15:41             ` Rob Clark
  0 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-08 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> On Tue, 8 Jul 2014 08:49:41 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > Hello Rob,
>> >
>> > On Mon, 7 Jul 2014 23:45:54 -0400
>> > Rob Clark <robdclark@gmail.com> wrote:
>> >
>> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> >> <boris.brezillon@free-electrons.com> wrote:
>> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> >> > controller device.
>> >> >
>> >> > This display controller supports at least one primary plane and might
>> >> > provide several overlays and an hardware cursor depending on the IP
>> >> > version.
>> >> >
>> >> > At the moment, this driver only implements an RGB connector to interface
>> >> > with LCD panels, but support for other kind of external devices (like DRM
>> >> > bridges) might be added later.
>> >> >
>> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> >> > ---
>> >> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >> >  drivers/gpu/drm/Makefile                        |   1 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >> >  11 files changed, 3382 insertions(+)
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >> >
>> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> >> > index d1cc2f6..df6f0c1 100644
>> >> > --- a/drivers/gpu/drm/Kconfig
>> >> > +++ b/drivers/gpu/drm/Kconfig
>> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>> >
>> > [...]
>> >
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane properties.
>> >> > + *
>> >> > + * This structure stores plane property definitions.
>> >> > + *
>> >> > + * @alpha: alpha blending (or transparency) property
>> >> > + * @csc: YUV to RGB conversion factors property
>> >> > + */
>> >> > +struct atmel_hlcdc_plane_properties {
>> >> > +       struct drm_property *alpha;
>> >> > +       struct drm_property *csc;
>> >>
>> >> appears like csc is not used yet, so I suppose you can drop it for
>> >> now..  when you do add it, don't forget to update drm.tmp.  But for
>> >> now it at least makes review easier when the driver doesn't add new
>> >> userspace interfaces :-)
>> >
>> >
>> > Sure, I guess this is a leftover from another patch I made to add Color
>> > Space Conversion configuration.
>> >
>> > I'll remove it for the next version.
>> >
>> >>
>> >> > +};
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane.
>> >> > + *
>> >> > + * @base: base DRM plane structure
>> >> > + * @layer: HLCDC layer structure
>> >> > + * @properties: pointer to the property definitions structure
>> >> > + * @alpha: current alpha blending (or transparency) status
>> >> > + */
>> >> > +struct atmel_hlcdc_plane {
>> >> > +       struct drm_plane base;
>> >> > +       struct atmel_hlcdc_layer layer;
>> >> > +       struct atmel_hlcdc_plane_properties *properties;
>> >> > +};
>> >> > +
>> >> > +static inline struct atmel_hlcdc_plane *
>> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
>> >> > +{
>> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
>> >> > +}
>> >> > +
>> >> > +static inline struct atmel_hlcdc_plane *
>> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
>> >> > +{
>> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
>> >> > +}
>> >> > +
>> >> > +/**
>> >> > + * Atmel HLCDC Plane update request structure.
>> >> > + *
>> >> > + * @crtc_x: x position of the plane relative to the CRTC
>> >> > + * @crtc_y: y position of the plane relative to the CRTC
>> >> > + * @crtc_w: visible width of the plane
>> >> > + * @crtc_h: visible height of the plane
>> >> > + * @src_x: x buffer position
>> >> > + * @src_y: y buffer position
>> >> > + * @src_w: buffer width
>> >> > + * @src_h: buffer height
>> >> > + * @pixel_format: pixel format
>> >> > + * @gems: GEM object object containing image buffers
>> >> > + * @offsets: offsets to apply to the GEM buffers
>> >> > + * @pitches: line size in bytes
>> >> > + * @crtc: crtc to display on
>> >> > + * @finished: finished callback
>> >> > + * @finished_data: data passed to the finished callback
>> >> > + * @bpp: bytes per pixel deduced from pixel_format
>> >> > + * @xstride: value to add to the pixel pointer between each line
>> >> > + * @pstride: value to add to the pixel pointer between each pixel
>> >> > + * @nplanes: number of planes (deduced from pixel_format)
>> >> > + */
>> >> > +struct atmel_hlcdc_plane_update_req {
>> >> > +       int crtc_x;
>> >> > +       int crtc_y;
>> >> > +       unsigned int crtc_w;
>> >> > +       unsigned int crtc_h;
>> >> > +       uint32_t src_x;
>> >> > +       uint32_t src_y;
>> >> > +       uint32_t src_w;
>> >> > +       uint32_t src_h;
>> >> > +       uint32_t pixel_format;
>> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
>> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
>> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
>> >>
>> >> tbh, I've only looked closely, but I don't completely follow all the
>> >> layering here..  I wonder if we'd be better off just moving 'struct
>> >> drm_fb_cma' to header file so you could get the gem objects / pixel
>> >> fmt / width / height directly from the fb object (and then you can
>> >> reference count things at the fb level, rather than at the individual
>> >> gem obj level, too)
>> >>
>> >
>> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
>> > retrieve a drm_fb_cma object, but just a single GEM object (see
>> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
>>
>> oh, right..  well maybe for the cursor case it would be possible to
>> wrap up the gem bo with an internally created fb?  Not sure if that
>> ends up simplifying things or not, so it is definitely your call.  But
>> at least my experience with other drivers (that did not use a plane as
>> a cursor internally) was that I could simplify things after fb gained
>> refcnt'ing.
>
> Unless I'm missing something, I'd say moving to fb objects instead of
> GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> objects when launching a DMA transfer for a plane update).

yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
thing instead of loop over N objects, etc.  Nothing earth-shattering.

BR,
-R

> The only benefit I can see is consistency with other drivers (which in
> fact is a good point).
> Indeed atmel_hlcdc_plane_update_req redefines some fields which are
> already availables in drm_fb_cma or drm_framebuffer:
>
> - gems (called objs in drm_fb_cma)
> - pixel_format
> - pitches (offsets must be redefined because it is modified in
>   atmel_hlcdc_plane_prepare_update_req)
>
> Anyway, I'll give it a try.
>
> Thanks for your review.
>
> In the meantime, I realized I hadn't subscribed to the dri-devel
> ML, which might explain why I didn't get any reviews from DRM
> maintainers/developers so far :-).
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08 15:41             ` Rob Clark
@ 2014-07-08 17:08               ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08 17:08 UTC (permalink / raw)
  To: Rob Clark
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Tue, 8 Jul 2014 11:41:32 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > On Tue, 8 Jul 2014 08:49:41 -0400
> > Rob Clark <robdclark@gmail.com> wrote:
> >
> >> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> >> <boris.brezillon@free-electrons.com> wrote:
> >> > Hello Rob,
> >> >
> >> > On Mon, 7 Jul 2014 23:45:54 -0400
> >> > Rob Clark <robdclark@gmail.com> wrote:
> >> >
> >> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> >> >> <boris.brezillon@free-electrons.com> wrote:
> >> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> >> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> >> >> > controller device.
> >> >> >
> >> >> > This display controller supports at least one primary plane and might
> >> >> > provide several overlays and an hardware cursor depending on the IP
> >> >> > version.
> >> >> >
> >> >> > At the moment, this driver only implements an RGB connector to interface
> >> >> > with LCD panels, but support for other kind of external devices (like DRM
> >> >> > bridges) might be added later.
> >> >> >
> >> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >> >> > ---
> >> >> >  drivers/gpu/drm/Kconfig                         |   2 +
> >> >> >  drivers/gpu/drm/Makefile                        |   1 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >> >> >  11 files changed, 3382 insertions(+)
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >> >> >
> >> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> >> > index d1cc2f6..df6f0c1 100644
> >> >> > --- a/drivers/gpu/drm/Kconfig
> >> >> > +++ b/drivers/gpu/drm/Kconfig
> >> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >> >
> >> > [...]
> >> >
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane properties.
> >> >> > + *
> >> >> > + * This structure stores plane property definitions.
> >> >> > + *
> >> >> > + * @alpha: alpha blending (or transparency) property
> >> >> > + * @csc: YUV to RGB conversion factors property
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane_properties {
> >> >> > +       struct drm_property *alpha;
> >> >> > +       struct drm_property *csc;
> >> >>
> >> >> appears like csc is not used yet, so I suppose you can drop it for
> >> >> now..  when you do add it, don't forget to update drm.tmp.  But for
> >> >> now it at least makes review easier when the driver doesn't add new
> >> >> userspace interfaces :-)
> >> >
> >> >
> >> > Sure, I guess this is a leftover from another patch I made to add Color
> >> > Space Conversion configuration.
> >> >
> >> > I'll remove it for the next version.
> >> >
> >> >>
> >> >> > +};
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane.
> >> >> > + *
> >> >> > + * @base: base DRM plane structure
> >> >> > + * @layer: HLCDC layer structure
> >> >> > + * @properties: pointer to the property definitions structure
> >> >> > + * @alpha: current alpha blending (or transparency) status
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane {
> >> >> > +       struct drm_plane base;
> >> >> > +       struct atmel_hlcdc_layer layer;
> >> >> > +       struct atmel_hlcdc_plane_properties *properties;
> >> >> > +};
> >> >> > +
> >> >> > +static inline struct atmel_hlcdc_plane *
> >> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> >> >> > +{
> >> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> >> >> > +}
> >> >> > +
> >> >> > +static inline struct atmel_hlcdc_plane *
> >> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> >> >> > +{
> >> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> >> >> > +}
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane update request structure.
> >> >> > + *
> >> >> > + * @crtc_x: x position of the plane relative to the CRTC
> >> >> > + * @crtc_y: y position of the plane relative to the CRTC
> >> >> > + * @crtc_w: visible width of the plane
> >> >> > + * @crtc_h: visible height of the plane
> >> >> > + * @src_x: x buffer position
> >> >> > + * @src_y: y buffer position
> >> >> > + * @src_w: buffer width
> >> >> > + * @src_h: buffer height
> >> >> > + * @pixel_format: pixel format
> >> >> > + * @gems: GEM object object containing image buffers
> >> >> > + * @offsets: offsets to apply to the GEM buffers
> >> >> > + * @pitches: line size in bytes
> >> >> > + * @crtc: crtc to display on
> >> >> > + * @finished: finished callback
> >> >> > + * @finished_data: data passed to the finished callback
> >> >> > + * @bpp: bytes per pixel deduced from pixel_format
> >> >> > + * @xstride: value to add to the pixel pointer between each line
> >> >> > + * @pstride: value to add to the pixel pointer between each pixel
> >> >> > + * @nplanes: number of planes (deduced from pixel_format)
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane_update_req {
> >> >> > +       int crtc_x;
> >> >> > +       int crtc_y;
> >> >> > +       unsigned int crtc_w;
> >> >> > +       unsigned int crtc_h;
> >> >> > +       uint32_t src_x;
> >> >> > +       uint32_t src_y;
> >> >> > +       uint32_t src_w;
> >> >> > +       uint32_t src_h;
> >> >> > +       uint32_t pixel_format;
> >> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> >> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> >> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> >> >>
> >> >> tbh, I've only looked closely, but I don't completely follow all the
> >> >> layering here..  I wonder if we'd be better off just moving 'struct
> >> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> >> >> fmt / width / height directly from the fb object (and then you can
> >> >> reference count things at the fb level, rather than at the individual
> >> >> gem obj level, too)
> >> >>
> >> >
> >> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> >> > retrieve a drm_fb_cma object, but just a single GEM object (see
> >> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> >>
> >> oh, right..  well maybe for the cursor case it would be possible to
> >> wrap up the gem bo with an internally created fb?  Not sure if that
> >> ends up simplifying things or not, so it is definitely your call.  But
> >> at least my experience with other drivers (that did not use a plane as
> >> a cursor internally) was that I could simplify things after fb gained
> >> refcnt'ing.
> >
> > Unless I'm missing something, I'd say moving to fb objects instead of
> > GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> > objects when launching a DMA transfer for a plane update).
> 
> yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
> thing instead of loop over N objects, etc.  Nothing earth-shattering.
> 

Okay, my bad, this is definitely simpler with fb objects (I made use of
drm_fb_cma_create to create an fb object when cursor_set is called)
than it was when using GEM objects.

I might even be able to simplify the layer update mechanism with this
approach.

Thanks for the advice.

Best Regards,

Boris


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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08 17:08               ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-08 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 8 Jul 2014 11:41:32 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > On Tue, 8 Jul 2014 08:49:41 -0400
> > Rob Clark <robdclark@gmail.com> wrote:
> >
> >> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> >> <boris.brezillon@free-electrons.com> wrote:
> >> > Hello Rob,
> >> >
> >> > On Mon, 7 Jul 2014 23:45:54 -0400
> >> > Rob Clark <robdclark@gmail.com> wrote:
> >> >
> >> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> >> >> <boris.brezillon@free-electrons.com> wrote:
> >> >> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> >> >> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> >> >> > controller device.
> >> >> >
> >> >> > This display controller supports at least one primary plane and might
> >> >> > provide several overlays and an hardware cursor depending on the IP
> >> >> > version.
> >> >> >
> >> >> > At the moment, this driver only implements an RGB connector to interface
> >> >> > with LCD panels, but support for other kind of external devices (like DRM
> >> >> > bridges) might be added later.
> >> >> >
> >> >> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >> >> > ---
> >> >> >  drivers/gpu/drm/Kconfig                         |   2 +
> >> >> >  drivers/gpu/drm/Makefile                        |   1 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >> >> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >> >> >  11 files changed, 3382 insertions(+)
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >> >> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >> >> >
> >> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> >> > index d1cc2f6..df6f0c1 100644
> >> >> > --- a/drivers/gpu/drm/Kconfig
> >> >> > +++ b/drivers/gpu/drm/Kconfig
> >> >> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >> >
> >> > [...]
> >> >
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane properties.
> >> >> > + *
> >> >> > + * This structure stores plane property definitions.
> >> >> > + *
> >> >> > + * @alpha: alpha blending (or transparency) property
> >> >> > + * @csc: YUV to RGB conversion factors property
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane_properties {
> >> >> > +       struct drm_property *alpha;
> >> >> > +       struct drm_property *csc;
> >> >>
> >> >> appears like csc is not used yet, so I suppose you can drop it for
> >> >> now..  when you do add it, don't forget to update drm.tmp.  But for
> >> >> now it at least makes review easier when the driver doesn't add new
> >> >> userspace interfaces :-)
> >> >
> >> >
> >> > Sure, I guess this is a leftover from another patch I made to add Color
> >> > Space Conversion configuration.
> >> >
> >> > I'll remove it for the next version.
> >> >
> >> >>
> >> >> > +};
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane.
> >> >> > + *
> >> >> > + * @base: base DRM plane structure
> >> >> > + * @layer: HLCDC layer structure
> >> >> > + * @properties: pointer to the property definitions structure
> >> >> > + * @alpha: current alpha blending (or transparency) status
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane {
> >> >> > +       struct drm_plane base;
> >> >> > +       struct atmel_hlcdc_layer layer;
> >> >> > +       struct atmel_hlcdc_plane_properties *properties;
> >> >> > +};
> >> >> > +
> >> >> > +static inline struct atmel_hlcdc_plane *
> >> >> > +drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
> >> >> > +{
> >> >> > +       return container_of(p, struct atmel_hlcdc_plane, base);
> >> >> > +}
> >> >> > +
> >> >> > +static inline struct atmel_hlcdc_plane *
> >> >> > +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> >> >> > +{
> >> >> > +       return container_of(l, struct atmel_hlcdc_plane, layer);
> >> >> > +}
> >> >> > +
> >> >> > +/**
> >> >> > + * Atmel HLCDC Plane update request structure.
> >> >> > + *
> >> >> > + * @crtc_x: x position of the plane relative to the CRTC
> >> >> > + * @crtc_y: y position of the plane relative to the CRTC
> >> >> > + * @crtc_w: visible width of the plane
> >> >> > + * @crtc_h: visible height of the plane
> >> >> > + * @src_x: x buffer position
> >> >> > + * @src_y: y buffer position
> >> >> > + * @src_w: buffer width
> >> >> > + * @src_h: buffer height
> >> >> > + * @pixel_format: pixel format
> >> >> > + * @gems: GEM object object containing image buffers
> >> >> > + * @offsets: offsets to apply to the GEM buffers
> >> >> > + * @pitches: line size in bytes
> >> >> > + * @crtc: crtc to display on
> >> >> > + * @finished: finished callback
> >> >> > + * @finished_data: data passed to the finished callback
> >> >> > + * @bpp: bytes per pixel deduced from pixel_format
> >> >> > + * @xstride: value to add to the pixel pointer between each line
> >> >> > + * @pstride: value to add to the pixel pointer between each pixel
> >> >> > + * @nplanes: number of planes (deduced from pixel_format)
> >> >> > + */
> >> >> > +struct atmel_hlcdc_plane_update_req {
> >> >> > +       int crtc_x;
> >> >> > +       int crtc_y;
> >> >> > +       unsigned int crtc_w;
> >> >> > +       unsigned int crtc_h;
> >> >> > +       uint32_t src_x;
> >> >> > +       uint32_t src_y;
> >> >> > +       uint32_t src_w;
> >> >> > +       uint32_t src_h;
> >> >> > +       uint32_t pixel_format;
> >> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> >> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> >> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> >> >>
> >> >> tbh, I've only looked closely, but I don't completely follow all the
> >> >> layering here..  I wonder if we'd be better off just moving 'struct
> >> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> >> >> fmt / width / height directly from the fb object (and then you can
> >> >> reference count things at the fb level, rather than at the individual
> >> >> gem obj level, too)
> >> >>
> >> >
> >> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> >> > retrieve a drm_fb_cma object, but just a single GEM object (see
> >> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> >>
> >> oh, right..  well maybe for the cursor case it would be possible to
> >> wrap up the gem bo with an internally created fb?  Not sure if that
> >> ends up simplifying things or not, so it is definitely your call.  But
> >> at least my experience with other drivers (that did not use a plane as
> >> a cursor internally) was that I could simplify things after fb gained
> >> refcnt'ing.
> >
> > Unless I'm missing something, I'd say moving to fb objects instead of
> > GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> > objects when launching a DMA transfer for a plane update).
> 
> yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
> thing instead of loop over N objects, etc.  Nothing earth-shattering.
> 

Okay, my bad, this is definitely simpler with fb objects (I made use of
drm_fb_cma_create to create an fb object when cursor_set is called)
than it was when using GEM objects.

I might even be able to simplify the layer update mechanism with this
approach.

Thanks for the advice.

Best Regards,

Boris


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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08 17:08               ` Boris BREZILLON
@ 2014-07-08 23:51                 ` Matt Roper
  -1 siblings, 0 replies; 149+ messages in thread
From: Matt Roper @ 2014-07-08 23:51 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Rob Clark, Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas

On Tue, Jul 08, 2014 at 07:08:20PM +0200, Boris BREZILLON wrote:
> On Tue, 8 Jul 2014 11:41:32 -0400
> Rob Clark <robdclark@gmail.com> wrote:
> 
> > On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
> > <boris.brezillon@free-electrons.com> wrote:
> > > On Tue, 8 Jul 2014 08:49:41 -0400
> > > Rob Clark <robdclark@gmail.com> wrote:
> > >
> > >> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> > >> <boris.brezillon@free-electrons.com> wrote:
> > >> > Hello Rob,
> > >> >
> > >> > On Mon, 7 Jul 2014 23:45:54 -0400
> > >> > Rob Clark <robdclark@gmail.com> wrote:
> > >> >
> > >> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> > >> >> <boris.brezillon@free-electrons.com> wrote:
...
> > >> >> > +/**
> > >> >> > + * Atmel HLCDC Plane update request structure.
> > >> >> > + *
> > >> >> > + * @crtc_x: x position of the plane relative to the CRTC
> > >> >> > + * @crtc_y: y position of the plane relative to the CRTC
> > >> >> > + * @crtc_w: visible width of the plane
> > >> >> > + * @crtc_h: visible height of the plane
> > >> >> > + * @src_x: x buffer position
> > >> >> > + * @src_y: y buffer position
> > >> >> > + * @src_w: buffer width
> > >> >> > + * @src_h: buffer height
> > >> >> > + * @pixel_format: pixel format
> > >> >> > + * @gems: GEM object object containing image buffers
> > >> >> > + * @offsets: offsets to apply to the GEM buffers
> > >> >> > + * @pitches: line size in bytes
> > >> >> > + * @crtc: crtc to display on
> > >> >> > + * @finished: finished callback
> > >> >> > + * @finished_data: data passed to the finished callback
> > >> >> > + * @bpp: bytes per pixel deduced from pixel_format
> > >> >> > + * @xstride: value to add to the pixel pointer between each line
> > >> >> > + * @pstride: value to add to the pixel pointer between each pixel
> > >> >> > + * @nplanes: number of planes (deduced from pixel_format)
> > >> >> > + */
> > >> >> > +struct atmel_hlcdc_plane_update_req {
> > >> >> > +       int crtc_x;
> > >> >> > +       int crtc_y;
> > >> >> > +       unsigned int crtc_w;
> > >> >> > +       unsigned int crtc_h;
> > >> >> > +       uint32_t src_x;
> > >> >> > +       uint32_t src_y;
> > >> >> > +       uint32_t src_w;
> > >> >> > +       uint32_t src_h;
> > >> >> > +       uint32_t pixel_format;
> > >> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> > >> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> > >> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> > >> >>
> > >> >> tbh, I've only looked closely, but I don't completely follow all the
> > >> >> layering here..  I wonder if we'd be better off just moving 'struct
> > >> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> > >> >> fmt / width / height directly from the fb object (and then you can
> > >> >> reference count things at the fb level, rather than at the individual
> > >> >> gem obj level, too)
> > >> >>
> > >> >
> > >> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> > >> > retrieve a drm_fb_cma object, but just a single GEM object (see
> > >> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> > >>
> > >> oh, right..  well maybe for the cursor case it would be possible to
> > >> wrap up the gem bo with an internally created fb?  Not sure if that
> > >> ends up simplifying things or not, so it is definitely your call.  But
> > >> at least my experience with other drivers (that did not use a plane as
> > >> a cursor internally) was that I could simplify things after fb gained
> > >> refcnt'ing.
> > >
> > > Unless I'm missing something, I'd say moving to fb objects instead of
> > > GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> > > objects when launching a DMA transfer for a plane update).
> > 
> > yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
> > thing instead of loop over N objects, etc.  Nothing earth-shattering.
> > 
> 
> Okay, my bad, this is definitely simpler with fb objects (I made use of
> drm_fb_cma_create to create an fb object when cursor_set is called)
> than it was when using GEM objects.
> 
> I might even be able to simplify the layer update mechanism with this
> approach.
> 
> Thanks for the advice.
> 
> Best Regards,
> 
> Boris

Hi Boris.

I haven't really looked at any of your driver in depth, but from a quick
glance it looks like you're registering a cursor drm_plane (i.e., making
use of the new universal plane infrastructure), but you're also
providing an implementation of the legacy cursor ioctls (cursor_set and
cursor_move).  There's some patches working their way through the
pipeline that should make this unnecessary and hopefully simplify your
life a bit:

        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15

The third patch there is the one that's really important for your work.
When a driver provides a cursor plane via the universal plane interface,
cursor_set and cursor_move are automatically implemented for you by
drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
legacy handlers will never get called.  drm_mode_cursor_universal() will
take care of wrapping the bo's into a drm_framebuffer for you.

When I added the universal cursor stuff, I wanted to make sure that as
soon as a driver starts supporting universal planes it can stop
supporting the legacy ioctls directly; otherwise handling refcounting
when userspace switches back and forth between calling legacy ioctl's
and calling setplane() on a cursor plane would be a nightmare.

I think those patches are only available in drm-intel-nightly at the
moment and haven't moved on to drm-next and such yet, since i915 is the
only driver that currently has patches to make use of cursors via the
univeral plane interface (probably landing for kernel 3.17).


Matt

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-08 23:51                 ` Matt Roper
  0 siblings, 0 replies; 149+ messages in thread
From: Matt Roper @ 2014-07-08 23:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 08, 2014 at 07:08:20PM +0200, Boris BREZILLON wrote:
> On Tue, 8 Jul 2014 11:41:32 -0400
> Rob Clark <robdclark@gmail.com> wrote:
> 
> > On Tue, Jul 8, 2014 at 10:37 AM, Boris BREZILLON
> > <boris.brezillon@free-electrons.com> wrote:
> > > On Tue, 8 Jul 2014 08:49:41 -0400
> > > Rob Clark <robdclark@gmail.com> wrote:
> > >
> > >> On Tue, Jul 8, 2014 at 3:23 AM, Boris BREZILLON
> > >> <boris.brezillon@free-electrons.com> wrote:
> > >> > Hello Rob,
> > >> >
> > >> > On Mon, 7 Jul 2014 23:45:54 -0400
> > >> > Rob Clark <robdclark@gmail.com> wrote:
> > >> >
> > >> >> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> > >> >> <boris.brezillon@free-electrons.com> wrote:
...
> > >> >> > +/**
> > >> >> > + * Atmel HLCDC Plane update request structure.
> > >> >> > + *
> > >> >> > + * @crtc_x: x position of the plane relative to the CRTC
> > >> >> > + * @crtc_y: y position of the plane relative to the CRTC
> > >> >> > + * @crtc_w: visible width of the plane
> > >> >> > + * @crtc_h: visible height of the plane
> > >> >> > + * @src_x: x buffer position
> > >> >> > + * @src_y: y buffer position
> > >> >> > + * @src_w: buffer width
> > >> >> > + * @src_h: buffer height
> > >> >> > + * @pixel_format: pixel format
> > >> >> > + * @gems: GEM object object containing image buffers
> > >> >> > + * @offsets: offsets to apply to the GEM buffers
> > >> >> > + * @pitches: line size in bytes
> > >> >> > + * @crtc: crtc to display on
> > >> >> > + * @finished: finished callback
> > >> >> > + * @finished_data: data passed to the finished callback
> > >> >> > + * @bpp: bytes per pixel deduced from pixel_format
> > >> >> > + * @xstride: value to add to the pixel pointer between each line
> > >> >> > + * @pstride: value to add to the pixel pointer between each pixel
> > >> >> > + * @nplanes: number of planes (deduced from pixel_format)
> > >> >> > + */
> > >> >> > +struct atmel_hlcdc_plane_update_req {
> > >> >> > +       int crtc_x;
> > >> >> > +       int crtc_y;
> > >> >> > +       unsigned int crtc_w;
> > >> >> > +       unsigned int crtc_h;
> > >> >> > +       uint32_t src_x;
> > >> >> > +       uint32_t src_y;
> > >> >> > +       uint32_t src_w;
> > >> >> > +       uint32_t src_h;
> > >> >> > +       uint32_t pixel_format;
> > >> >> > +       struct drm_gem_cma_object *gems[ATMEL_HLCDC_MAX_PLANES];
> > >> >> > +       unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> > >> >> > +       unsigned int pitches[ATMEL_HLCDC_MAX_PLANES];
> > >> >>
> > >> >> tbh, I've only looked closely, but I don't completely follow all the
> > >> >> layering here..  I wonder if we'd be better off just moving 'struct
> > >> >> drm_fb_cma' to header file so you could get the gem objects / pixel
> > >> >> fmt / width / height directly from the fb object (and then you can
> > >> >> reference count things at the fb level, rather than at the individual
> > >> >> gem obj level, too)
> > >> >>
> > >> >
> > >> > Actually, the HW cursor is a drm_plane too, and in this case I cannot
> > >> > retrieve a drm_fb_cma object, but just a single GEM object (see
> > >> > atmel_hlcdc_crtc_cursor_set function in atmel_hlcdc_crtc.c).
> > >>
> > >> oh, right..  well maybe for the cursor case it would be possible to
> > >> wrap up the gem bo with an internally created fb?  Not sure if that
> > >> ends up simplifying things or not, so it is definitely your call.  But
> > >> at least my experience with other drivers (that did not use a plane as
> > >> a cursor internally) was that I could simplify things after fb gained
> > >> refcnt'ing.
> > >
> > > Unless I'm missing something, I'd say moving to fb objects instead of
> > > GEM objects won't simplify the code much (I'm already refcnt'ing GEM
> > > objects when launching a DMA transfer for a plane update).
> > 
> > yeah, mostly just saves you a bit of bookkeeping.  Ie. ref/unref one
> > thing instead of loop over N objects, etc.  Nothing earth-shattering.
> > 
> 
> Okay, my bad, this is definitely simpler with fb objects (I made use of
> drm_fb_cma_create to create an fb object when cursor_set is called)
> than it was when using GEM objects.
> 
> I might even be able to simplify the layer update mechanism with this
> approach.
> 
> Thanks for the advice.
> 
> Best Regards,
> 
> Boris

Hi Boris.

I haven't really looked at any of your driver in depth, but from a quick
glance it looks like you're registering a cursor drm_plane (i.e., making
use of the new universal plane infrastructure), but you're also
providing an implementation of the legacy cursor ioctls (cursor_set and
cursor_move).  There's some patches working their way through the
pipeline that should make this unnecessary and hopefully simplify your
life a bit:

        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
        http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15

The third patch there is the one that's really important for your work.
When a driver provides a cursor plane via the universal plane interface,
cursor_set and cursor_move are automatically implemented for you by
drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
legacy handlers will never get called.  drm_mode_cursor_universal() will
take care of wrapping the bo's into a drm_framebuffer for you.

When I added the universal cursor stuff, I wanted to make sure that as
soon as a driver starts supporting universal planes it can stop
supporting the legacy ioctls directly; otherwise handling refcounting
when userspace switches back and forth between calling legacy ioctl's
and calling setplane() on a cursor plane would be a nightmare.

I think those patches are only available in drm-intel-nightly at the
moment and haven't moved on to drm-next and such yet, since i915 is the
only driver that currently has patches to make use of cursors via the
univeral plane interface (probably landing for kernel 3.17).


Matt

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08 23:51                 ` Matt Roper
@ 2014-07-09  7:14                   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-09  7:14 UTC (permalink / raw)
  To: Matt Roper
  Cc: Mark Rutland, devicetree, Jean-Jacques Hiblot, Samuel Ortiz,
	Pawel Moll, linux-pwm, Jean-Christophe Plagniol-Villard,
	Ian Campbell, Nicolas Ferre, dri-devel, Tim Niemeyer,
	Rob Herring, Alexandre Belloni, Laurent Pinchart, Bo Shen,
	Kumar Gala, Thomas Petazzoni, Lee Jones, Andrew Victor

Hi Matt,

On Tue, 8 Jul 2014 16:51:24 -0700
Matt Roper <matthew.d.roper@intel.com> wrote:

> Hi Boris.
> 
> I haven't really looked at any of your driver in depth, but from a quick
> glance it looks like you're registering a cursor drm_plane (i.e., making
> use of the new universal plane infrastructure), but you're also
> providing an implementation of the legacy cursor ioctls (cursor_set and
> cursor_move).  There's some patches working their way through the
> pipeline that should make this unnecessary and hopefully simplify your
> life a bit:
> 
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15
> 
> The third patch there is the one that's really important for your work.
> When a driver provides a cursor plane via the universal plane interface,
> cursor_set and cursor_move are automatically implemented for you by
> drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
> legacy handlers will never get called.  drm_mode_cursor_universal() will
> take care of wrapping the bo's into a drm_framebuffer for you.
> 
> When I added the universal cursor stuff, I wanted to make sure that as
> soon as a driver starts supporting universal planes it can stop
> supporting the legacy ioctls directly; otherwise handling refcounting
> when userspace switches back and forth between calling legacy ioctl's
> and calling setplane() on a cursor plane would be a nightmare.
> 
> I think those patches are only available in drm-intel-nightly at the
> moment and haven't moved on to drm-next and such yet, since i915 is the
> only driver that currently has patches to make use of cursors via the
> univeral plane interface (probably landing for kernel 3.17).

That's great news. I knew there were some work in progress on this
topic, but didn't know it was planned for 3.17. 

I'll move to this solution.

Thanks,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-09  7:14                   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-09  7:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Matt,

On Tue, 8 Jul 2014 16:51:24 -0700
Matt Roper <matthew.d.roper@intel.com> wrote:

> Hi Boris.
> 
> I haven't really looked at any of your driver in depth, but from a quick
> glance it looks like you're registering a cursor drm_plane (i.e., making
> use of the new universal plane infrastructure), but you're also
> providing an implementation of the legacy cursor ioctls (cursor_set and
> cursor_move).  There's some patches working their way through the
> pipeline that should make this unnecessary and hopefully simplify your
> life a bit:
> 
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
>         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15
> 
> The third patch there is the one that's really important for your work.
> When a driver provides a cursor plane via the universal plane interface,
> cursor_set and cursor_move are automatically implemented for you by
> drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
> legacy handlers will never get called.  drm_mode_cursor_universal() will
> take care of wrapping the bo's into a drm_framebuffer for you.
> 
> When I added the universal cursor stuff, I wanted to make sure that as
> soon as a driver starts supporting universal planes it can stop
> supporting the legacy ioctls directly; otherwise handling refcounting
> when userspace switches back and forth between calling legacy ioctl's
> and calling setplane() on a cursor plane would be a nightmare.
> 
> I think those patches are only available in drm-intel-nightly at the
> moment and haven't moved on to drm-next and such yet, since i915 is the
> only driver that currently has patches to make use of cursors via the
> univeral plane interface (probably landing for kernel 3.17).

That's great news. I knew there were some work in progress on this
topic, but didn't know it was planned for 3.17. 

I'll move to this solution.

Thanks,

Boris

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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-08  3:45   ` Rob Clark
@ 2014-07-09  8:18       ` Boris BREZILLON
  2014-07-09  8:18       ` Boris BREZILLON
  1 sibling, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-09  8:18 UTC (permalink / raw)
  To: Rob Clark
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Mon, 7 Jul 2014 23:45:54 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> >
> > This display controller supports at least one primary plane and might
> > provide several overlays and an hardware cursor depending on the IP
> > version.
> >
> > At the moment, this driver only implements an RGB connector to interface
> > with LCD panels, but support for other kind of external devices (like DRM
> > bridges) might be added later.
> >
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  drivers/gpu/drm/Kconfig                         |   2 +
> >  drivers/gpu/drm/Makefile                        |   1 +
> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >  11 files changed, 3382 insertions(+)
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index d1cc2f6..df6f0c1 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >

[...]

> > +/**
> > + * Atmel HLCDC Layer GEM flip garbage collector structure
> > + *
> > + * This structure is used to schedule GEM object release when we are in
> > + * interrupt context (within atmel_hlcdc_layer_irq function).
> > + *
> > + *@list: GEM flip objects to release
> > + *@list_lock: lock to access the GEM flip list
> > + *@work: work queue scheduled when there are GEM flip to collect
> > + *@finished: action to execute the GEM flip and all attached objects have been
> > + *          released
> > + *@finished_data: data passed to the finished callback
> > + *@finished_lock: lock to access finished related fields
> > + */
> > +struct atmel_hlcdc_layer_gem_flip_gc {
> > +       struct list_head list;
> > +       spinlock_t list_lock;
> > +       struct work_struct work;
> > +};
> 
> 
> Please have a look at drm_flip_work.. I think that should simplify
> post-flip cleanup for you..
> 

Now I remember why I didn't make use of drm_flip_work helpers:

I have to specify a fifo size when initializing the
drm_flip_work structure (drm_flip_work_init) and I don't know exactly
what I should choose here.

You might have noticed that I'm queuing the unref work to be done within
the irq handler (which means I'm in irq context), and, AFAIU,
drm_flip_work_queue will execute the function if the FIFO is full
(AFAIK calling drm_framebuffer_unreference in irq context is not safe).

This leaves the following solutions if I ever want to use drm_flip_work:
 - use a threaded irq. Meaning the next frame (or the pending plane
   update) might take a bit longer to be displayed.
 - increase the fifo size, so that it's never entirely filled (relying
   on the assumption that the flip work queue will be executed at least
   as much as the plane update requests)
 - rely on the assumption that work_queue will be executed at least
   once per fb flip. This is true for the primary plane because we're
   using page_flip and only one page_flip can take place at a given
   time, but AFAIK this is not true for plane updates.

My approach is to use a simple list instead of a kfifo to queue fb
flip unref work, this way I don't have to bother about whether the fifo
is full or not.
ITOH, this means I might keep fb references longer than I would when
using drm_flip_work, and potentially get out of resources if plane
updates occurs more often than my unref work queue is called.

Please, let me know what's the preferred solution here.

Best Regards,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-09  8:18       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-09  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 7 Jul 2014 23:45:54 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> >
> > This display controller supports at least one primary plane and might
> > provide several overlays and an hardware cursor depending on the IP
> > version.
> >
> > At the moment, this driver only implements an RGB connector to interface
> > with LCD panels, but support for other kind of external devices (like DRM
> > bridges) might be added later.
> >
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  drivers/gpu/drm/Kconfig                         |   2 +
> >  drivers/gpu/drm/Makefile                        |   1 +
> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
> >  11 files changed, 3382 insertions(+)
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index d1cc2f6..df6f0c1 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
> >

[...]

> > +/**
> > + * Atmel HLCDC Layer GEM flip garbage collector structure
> > + *
> > + * This structure is used to schedule GEM object release when we are in
> > + * interrupt context (within atmel_hlcdc_layer_irq function).
> > + *
> > + *@list: GEM flip objects to release
> > + *@list_lock: lock to access the GEM flip list
> > + *@work: work queue scheduled when there are GEM flip to collect
> > + *@finished: action to execute the GEM flip and all attached objects have been
> > + *          released
> > + *@finished_data: data passed to the finished callback
> > + *@finished_lock: lock to access finished related fields
> > + */
> > +struct atmel_hlcdc_layer_gem_flip_gc {
> > +       struct list_head list;
> > +       spinlock_t list_lock;
> > +       struct work_struct work;
> > +};
> 
> 
> Please have a look at drm_flip_work.. I think that should simplify
> post-flip cleanup for you..
> 

Now I remember why I didn't make use of drm_flip_work helpers:

I have to specify a fifo size when initializing the
drm_flip_work structure (drm_flip_work_init) and I don't know exactly
what I should choose here.

You might have noticed that I'm queuing the unref work to be done within
the irq handler (which means I'm in irq context), and, AFAIU,
drm_flip_work_queue will execute the function if the FIFO is full
(AFAIK calling drm_framebuffer_unreference in irq context is not safe).

This leaves the following solutions if I ever want to use drm_flip_work:
 - use a threaded irq. Meaning the next frame (or the pending plane
   update) might take a bit longer to be displayed.
 - increase the fifo size, so that it's never entirely filled (relying
   on the assumption that the flip work queue will be executed at least
   as much as the plane update requests)
 - rely on the assumption that work_queue will be executed at least
   once per fb flip. This is true for the primary plane because we're
   using page_flip and only one page_flip can take place at a given
   time, but AFAIK this is not true for plane updates.

My approach is to use a simple list instead of a kfifo to queue fb
flip unref work, this way I don't have to bother about whether the fifo
is full or not.
ITOH, this means I might keep fb references longer than I would when
using drm_flip_work, and potentially get out of resources if plane
updates occurs more often than my unref work queue is called.

Please, let me know what's the preferred solution here.

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-09  8:18       ` Boris BREZILLON
@ 2014-07-09 11:53         ` Rob Clark
  -1 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-09 11:53 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Wed, Jul 9, 2014 at 4:18 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> On Mon, 7 Jul 2014 23:45:54 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> > controller device.
>> >
>> > This display controller supports at least one primary plane and might
>> > provide several overlays and an hardware cursor depending on the IP
>> > version.
>> >
>> > At the moment, this driver only implements an RGB connector to interface
>> > with LCD panels, but support for other kind of external devices (like DRM
>> > bridges) might be added later.
>> >
>> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> > ---
>> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >  drivers/gpu/drm/Makefile                        |   1 +
>> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >  11 files changed, 3382 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index d1cc2f6..df6f0c1 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>> >
>
> [...]
>
>> > +/**
>> > + * Atmel HLCDC Layer GEM flip garbage collector structure
>> > + *
>> > + * This structure is used to schedule GEM object release when we are in
>> > + * interrupt context (within atmel_hlcdc_layer_irq function).
>> > + *
>> > + *@list: GEM flip objects to release
>> > + *@list_lock: lock to access the GEM flip list
>> > + *@work: work queue scheduled when there are GEM flip to collect
>> > + *@finished: action to execute the GEM flip and all attached objects have been
>> > + *          released
>> > + *@finished_data: data passed to the finished callback
>> > + *@finished_lock: lock to access finished related fields
>> > + */
>> > +struct atmel_hlcdc_layer_gem_flip_gc {
>> > +       struct list_head list;
>> > +       spinlock_t list_lock;
>> > +       struct work_struct work;
>> > +};
>>
>>
>> Please have a look at drm_flip_work.. I think that should simplify
>> post-flip cleanup for you..
>>
>
> Now I remember why I didn't make use of drm_flip_work helpers:
>
> I have to specify a fifo size when initializing the
> drm_flip_work structure (drm_flip_work_init) and I don't know exactly
> what I should choose here.
>
> You might have noticed that I'm queuing the unref work to be done within
> the irq handler (which means I'm in irq context), and, AFAIU,
> drm_flip_work_queue will execute the function if the FIFO is full
> (AFAIK calling drm_framebuffer_unreference in irq context is not safe).

yeah, the place where it is used so far, it has been ok just to size
the FIFO a couple times bigger than it should ever need to be..

Possibly dynamically growing the FIFO would make it a bit more robust.
I was trying to avoid a list so we didn't have restrictions about what
can be queued up (and didn't have issues queuing something up multiple
times)

> This leaves the following solutions if I ever want to use drm_flip_work:
>  - use a threaded irq. Meaning the next frame (or the pending plane
>    update) might take a bit longer to be displayed.
>  - increase the fifo size, so that it's never entirely filled (relying
>    on the assumption that the flip work queue will be executed at least
>    as much as the plane update requests)
>  - rely on the assumption that work_queue will be executed at least
>    once per fb flip. This is true for the primary plane because we're
>    using page_flip and only one page_flip can take place at a given
>    time, but AFAIK this is not true for plane updates.

At least some of the hw can only do plane updates once per frame
anyway.  I do kinda wish the plane API was better defined in terms of
what happens if you try multiple updates in a frame.  In practice, the
only place I can think of where this is an issue is when using a plane
to implement a hw cursor (because you have userspace that likes to
enable/disable cursor at a high rate sometimes, like spinning
busy-cursor).

> My approach is to use a simple list instead of a kfifo to queue fb
> flip unref work, this way I don't have to bother about whether the fifo
> is full or not.

true, but what happens when you need to queue up the same gem obj or
same fb multiple times?

> ITOH, this means I might keep fb references longer than I would when
> using drm_flip_work, and potentially get out of resources if plane
> updates occurs more often than my unref work queue is called.
>
> Please, let me know what's the preferred solution here.

I suppose making flip-work clever enough to grow it's FIFO on demand
would be a nice enhancement that the other users of flip-work would
benefit from.  It would be nice if we could use a list and not have to
worry about size, but it would be common for userspace to flip between
2 or 3 buffers on a plane, so as soon as you have to start worrying
about FIFO size, you also have to worry about having same buffer
queued up for multiple unref's.

BR,
-R

> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-09 11:53         ` Rob Clark
  0 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-09 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 9, 2014 at 4:18 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> On Mon, 7 Jul 2014 23:45:54 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Mon, Jul 7, 2014 at 12:42 PM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
>> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
>> > controller device.
>> >
>> > This display controller supports at least one primary plane and might
>> > provide several overlays and an hardware cursor depending on the IP
>> > version.
>> >
>> > At the moment, this driver only implements an RGB connector to interface
>> > with LCD panels, but support for other kind of external devices (like DRM
>> > bridges) might be added later.
>> >
>> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> > ---
>> >  drivers/gpu/drm/Kconfig                         |   2 +
>> >  drivers/gpu/drm/Makefile                        |   1 +
>> >  drivers/gpu/drm/atmel-hlcdc/Kconfig             |  11 +
>> >  drivers/gpu/drm/atmel-hlcdc/Makefile            |   7 +
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  | 469 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    | 474 +++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 210 +++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 706 +++++++++++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 422 ++++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c | 351 ++++++++++++
>> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 729 ++++++++++++++++++++++++
>> >  11 files changed, 3382 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Kconfig
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/Makefile
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_panel.c
>> >  create mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index d1cc2f6..df6f0c1 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -182,6 +182,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
>> >
>
> [...]
>
>> > +/**
>> > + * Atmel HLCDC Layer GEM flip garbage collector structure
>> > + *
>> > + * This structure is used to schedule GEM object release when we are in
>> > + * interrupt context (within atmel_hlcdc_layer_irq function).
>> > + *
>> > + *@list: GEM flip objects to release
>> > + *@list_lock: lock to access the GEM flip list
>> > + *@work: work queue scheduled when there are GEM flip to collect
>> > + *@finished: action to execute the GEM flip and all attached objects have been
>> > + *          released
>> > + *@finished_data: data passed to the finished callback
>> > + *@finished_lock: lock to access finished related fields
>> > + */
>> > +struct atmel_hlcdc_layer_gem_flip_gc {
>> > +       struct list_head list;
>> > +       spinlock_t list_lock;
>> > +       struct work_struct work;
>> > +};
>>
>>
>> Please have a look at drm_flip_work.. I think that should simplify
>> post-flip cleanup for you..
>>
>
> Now I remember why I didn't make use of drm_flip_work helpers:
>
> I have to specify a fifo size when initializing the
> drm_flip_work structure (drm_flip_work_init) and I don't know exactly
> what I should choose here.
>
> You might have noticed that I'm queuing the unref work to be done within
> the irq handler (which means I'm in irq context), and, AFAIU,
> drm_flip_work_queue will execute the function if the FIFO is full
> (AFAIK calling drm_framebuffer_unreference in irq context is not safe).

yeah, the place where it is used so far, it has been ok just to size
the FIFO a couple times bigger than it should ever need to be..

Possibly dynamically growing the FIFO would make it a bit more robust.
I was trying to avoid a list so we didn't have restrictions about what
can be queued up (and didn't have issues queuing something up multiple
times)

> This leaves the following solutions if I ever want to use drm_flip_work:
>  - use a threaded irq. Meaning the next frame (or the pending plane
>    update) might take a bit longer to be displayed.
>  - increase the fifo size, so that it's never entirely filled (relying
>    on the assumption that the flip work queue will be executed at least
>    as much as the plane update requests)
>  - rely on the assumption that work_queue will be executed at least
>    once per fb flip. This is true for the primary plane because we're
>    using page_flip and only one page_flip can take place at a given
>    time, but AFAIK this is not true for plane updates.

At least some of the hw can only do plane updates once per frame
anyway.  I do kinda wish the plane API was better defined in terms of
what happens if you try multiple updates in a frame.  In practice, the
only place I can think of where this is an issue is when using a plane
to implement a hw cursor (because you have userspace that likes to
enable/disable cursor at a high rate sometimes, like spinning
busy-cursor).

> My approach is to use a simple list instead of a kfifo to queue fb
> flip unref work, this way I don't have to bother about whether the fifo
> is full or not.

true, but what happens when you need to queue up the same gem obj or
same fb multiple times?

> ITOH, this means I might keep fb references longer than I would when
> using drm_flip_work, and potentially get out of resources if plane
> updates occurs more often than my unref work queue is called.
>
> Please, let me know what's the preferred solution here.

I suppose making flip-work clever enough to grow it's FIFO on demand
would be a nice enhancement that the other users of flip-work would
benefit from.  It would be nice if we could use a list and not have to
worry about size, but it would be common for userspace to flip between
2 or 3 buffers on a plane, so as soon as you have to start worrying
about FIFO size, you also have to worry about having same buffer
queued up for multiple unref's.

BR,
-R

> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-09  7:14                   ` Boris BREZILLON
@ 2014-07-09 14:02                     ` Daniel Vetter
  -1 siblings, 0 replies; 149+ messages in thread
From: Daniel Vetter @ 2014-07-09 14:02 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Matt Roper, Mark Rutland, devicetree, Jean-Jacques Hiblot,
	Samuel Ortiz, Pawel Moll, linux-pwm,
	Jean-Christophe Plagniol-Villard, Ian Campbell, Nicolas Ferre,
	dri-devel, Tim Niemeyer, Rob Herring, Alexandre Belloni,
	Laurent Pinchart, Bo Shen, Kumar Gala, Thomas Petazzoni,
	Lee Jones, Andrew Victor

On Wed, Jul 09, 2014 at 09:14:24AM +0200, Boris BREZILLON wrote:
> Hi Matt,
> 
> On Tue, 8 Jul 2014 16:51:24 -0700
> Matt Roper <matthew.d.roper@intel.com> wrote:
> 
> > Hi Boris.
> > 
> > I haven't really looked at any of your driver in depth, but from a quick
> > glance it looks like you're registering a cursor drm_plane (i.e., making
> > use of the new universal plane infrastructure), but you're also
> > providing an implementation of the legacy cursor ioctls (cursor_set and
> > cursor_move).  There's some patches working their way through the
> > pipeline that should make this unnecessary and hopefully simplify your
> > life a bit:
> > 
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15
> > 
> > The third patch there is the one that's really important for your work.
> > When a driver provides a cursor plane via the universal plane interface,
> > cursor_set and cursor_move are automatically implemented for you by
> > drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
> > legacy handlers will never get called.  drm_mode_cursor_universal() will
> > take care of wrapping the bo's into a drm_framebuffer for you.
> > 
> > When I added the universal cursor stuff, I wanted to make sure that as
> > soon as a driver starts supporting universal planes it can stop
> > supporting the legacy ioctls directly; otherwise handling refcounting
> > when userspace switches back and forth between calling legacy ioctl's
> > and calling setplane() on a cursor plane would be a nightmare.
> > 
> > I think those patches are only available in drm-intel-nightly at the
> > moment and haven't moved on to drm-next and such yet, since i915 is the
> > only driver that currently has patches to make use of cursors via the
> > univeral plane interface (probably landing for kernel 3.17).
> 
> That's great news. I knew there were some work in progress on this
> topic, but didn't know it was planned for 3.17. 
> 
> I'll move to this solution.

As of today those patches have landed in Dave's drm-next branch.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-09 14:02                     ` Daniel Vetter
  0 siblings, 0 replies; 149+ messages in thread
From: Daniel Vetter @ 2014-07-09 14:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 09, 2014 at 09:14:24AM +0200, Boris BREZILLON wrote:
> Hi Matt,
> 
> On Tue, 8 Jul 2014 16:51:24 -0700
> Matt Roper <matthew.d.roper@intel.com> wrote:
> 
> > Hi Boris.
> > 
> > I haven't really looked at any of your driver in depth, but from a quick
> > glance it looks like you're registering a cursor drm_plane (i.e., making
> > use of the new universal plane infrastructure), but you're also
> > providing an implementation of the legacy cursor ioctls (cursor_set and
> > cursor_move).  There's some patches working their way through the
> > pipeline that should make this unnecessary and hopefully simplify your
> > life a bit:
> > 
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=c394c2b08e247c32ef292b75fd8b34312465f8ae
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=b36552b32aa9c69e83a3a20bda56379fb9e52435
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662
> >         http://cgit.freedesktop.org/drm-intel/commit/?h=drm-intel-nightly&id=fc1d3e44ef7c1db93384150fdbf8948dcf949f15
> > 
> > The third patch there is the one that's really important for your work.
> > When a driver provides a cursor plane via the universal plane interface,
> > cursor_set and cursor_move are automatically implemented for you by
> > drm_mode_cursor_universal() in drivers/gpu/drm/drm_crtc.c and your
> > legacy handlers will never get called.  drm_mode_cursor_universal() will
> > take care of wrapping the bo's into a drm_framebuffer for you.
> > 
> > When I added the universal cursor stuff, I wanted to make sure that as
> > soon as a driver starts supporting universal planes it can stop
> > supporting the legacy ioctls directly; otherwise handling refcounting
> > when userspace switches back and forth between calling legacy ioctl's
> > and calling setplane() on a cursor plane would be a nightmare.
> > 
> > I think those patches are only available in drm-intel-nightly at the
> > moment and haven't moved on to drm-next and such yet, since i915 is the
> > only driver that currently has patches to make use of cursors via the
> > univeral plane interface (probably landing for kernel 3.17).
> 
> That's great news. I knew there were some work in progress on this
> topic, but didn't know it was planned for 3.17. 
> 
> I'll move to this solution.

As of today those patches have landed in Dave's drm-next branch.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-07 16:42   ` Boris BREZILLON
@ 2014-07-10 11:16     ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-10 11:16 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

Hi Boris,

Thank you for the patch.

On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> controller device.
> 
> The HLCDC block provides a single RGB output port, and only supports LCD
> panels connection to LCD panels for now.
> 
> The atmel,panel property link the HLCDC RGB output with the LCD panel
> connected on this port (note that the HLCDC RGB connector implementation
> makes use of the DRM panel framework).
> 
> Connection to other external devices (DRM bridges) might be added later by
> mean of a new atmel,xxx (atmel,bridge) property.
> 
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> 100644
> index 0000000..594bdb2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> @@ -0,0 +1,59 @@
> +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> +
> +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> +
> +Required properties:
> + - compatible: value should be one of the following:
> +   "atmel,hlcdc-dc"
> + - interrupts: the HLCDC interrupt definition
> + - pinctrl-names: the pin control state names. Should contain "default",
> +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> + - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
> +   names.

Do you need to switch between the different pinctrl configurations at runtime, 
or is the configuration selected from the panel type, which doesn't change ?

> + - atmel,panel: Should contain a phandle with 2 parameters.
> +   The first cell is a phandle to a DRM panel device
> +   The second cell encodes the RGB mode, which can take the following
> values:
> +   * 0: RGB444
> +   * 1: RGB565
> +   * 2: RGB666
> +   * 3: RGB888
> +   The third cell encodes specific flags describing LCD signals
> configuration
> +   (see Atmel's datasheet for a full description of these
> fields):
> +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> +   * bit 4: DISPPOL: Display Signal Polarity
> +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> Configuration
> +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> Configuration
> +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time

If I'm not mistaken, those are HLCDC configuration values that depend on the 
panel type and characteristics. Shouldn't they then be queries from the panel 
through the drm_panel API at runtime instead of being specified in DT ? This 
would likely require extending the drm_panel API.

> +
> +Example:
> +
> +	hlcdc: hlcdc@f0030000 {
> +		compatible = "atmel,sama5d3-hlcdc";
> +		reg = <0xf0030000 0x2000>;
> +		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
> +		clock-names = "periph_clk","sys_clk", "slow_clk";
> +		status = "disabled";
> +
> +		hlcdc-display-controller {
> +			compatible = "atmel,hlcdc-dc";
> +			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
> +			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", 
"rgb-888";
> +			pinctrl-0 = <&pinctrl_lcd_base>;
> +			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
> +			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
> +			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
> +			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
> +		};
> +
> +		hlcdc_pwm: hlcdc-pwm {
> +			compatible = "atmel,hlcdc-pwm";
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&pinctrl_lcd_pwm>;
> +			#pwm-cells = <3>;
> +		};
> +	};

-- 
Regards,

Laurent Pinchart


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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-10 11:16     ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-10 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

Thank you for the patch.

On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> controller device.
> 
> The HLCDC block provides a single RGB output port, and only supports LCD
> panels connection to LCD panels for now.
> 
> The atmel,panel property link the HLCDC RGB output with the LCD panel
> connected on this port (note that the HLCDC RGB connector implementation
> makes use of the DRM panel framework).
> 
> Connection to other external devices (DRM bridges) might be added later by
> mean of a new atmel,xxx (atmel,bridge) property.
> 
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> 100644
> index 0000000..594bdb2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> @@ -0,0 +1,59 @@
> +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> +
> +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> +
> +Required properties:
> + - compatible: value should be one of the following:
> +   "atmel,hlcdc-dc"
> + - interrupts: the HLCDC interrupt definition
> + - pinctrl-names: the pin control state names. Should contain "default",
> +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> + - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
> +   names.

Do you need to switch between the different pinctrl configurations at runtime, 
or is the configuration selected from the panel type, which doesn't change ?

> + - atmel,panel: Should contain a phandle with 2 parameters.
> +   The first cell is a phandle to a DRM panel device
> +   The second cell encodes the RGB mode, which can take the following
> values:
> +   * 0: RGB444
> +   * 1: RGB565
> +   * 2: RGB666
> +   * 3: RGB888
> +   The third cell encodes specific flags describing LCD signals
> configuration
> +   (see Atmel's datasheet for a full description of these
> fields):
> +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> +   * bit 4: DISPPOL: Display Signal Polarity
> +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> Configuration
> +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> Configuration
> +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time

If I'm not mistaken, those are HLCDC configuration values that depend on the 
panel type and characteristics. Shouldn't they then be queries from the panel 
through the drm_panel API at runtime instead of being specified in DT ? This 
would likely require extending the drm_panel API.

> +
> +Example:
> +
> +	hlcdc: hlcdc at f0030000 {
> +		compatible = "atmel,sama5d3-hlcdc";
> +		reg = <0xf0030000 0x2000>;
> +		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
> +		clock-names = "periph_clk","sys_clk", "slow_clk";
> +		status = "disabled";
> +
> +		hlcdc-display-controller {
> +			compatible = "atmel,hlcdc-dc";
> +			interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
> +			pinctrl-names = "default", "rgb-444", "rgb-565", "rgb-666", 
"rgb-888";
> +			pinctrl-0 = <&pinctrl_lcd_base>;
> +			pinctrl-1 = <&pinctrl_lcd_base &pinctrl_lcd_rgb444>;
> +			pinctrl-2 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
> +			pinctrl-3 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>;
> +			pinctrl-4 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
> +		};
> +
> +		hlcdc_pwm: hlcdc-pwm {
> +			compatible = "atmel,hlcdc-pwm";
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&pinctrl_lcd_pwm>;
> +			#pwm-cells = <3>;
> +		};
> +	};

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-10 11:16     ` Laurent Pinchart
@ 2014-07-10 12:56       ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-10 12:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Laurent,

On Thu, 10 Jul 2014 13:16:21 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> > 
> > The HLCDC block provides a single RGB output port, and only supports LCD
> > panels connection to LCD panels for now.
> > 
> > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > connected on this port (note that the HLCDC RGB connector implementation
> > makes use of the DRM panel framework).
> > 
> > Connection to other external devices (DRM bridges) might be added later by
> > mean of a new atmel,xxx (atmel,bridge) property.
> > 
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++++++
> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > 100644
> > index 0000000..594bdb2
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > @@ -0,0 +1,59 @@
> > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > +
> > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > +
> > +Required properties:
> > + - compatible: value should be one of the following:
> > +   "atmel,hlcdc-dc"
> > + - interrupts: the HLCDC interrupt definition
> > + - pinctrl-names: the pin control state names. Should contain "default",
> > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > + - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
> > +   names.
> 
> Do you need to switch between the different pinctrl configurations at runtime, 
> or is the configuration selected from the panel type, which doesn't change ?

At the moment no, but if we ever need to support different devices on
the same RGB connector (actually Atmel's sama5d3xek boards have an
RGB to HDMI bridge connected on the same RGB connector) and these
devices do not support the same RGB mode (say your LCD panel supports
RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
the output you select you'll have to change your pinctrl config at
runtime.

I'd say we could get rid of this runtime pinctrl config as a first step
if DT ABI stability was not required.
But it is, and I'd like to have a future proof binding to handle these
tricky cases when they occurs (if they ever do).

Anyway, I'm open to any other alternative that could let me add support
for this later on.

BTW, is there any reason for not defining an RGB connector type (I'm
currently defining HLCDC connector as an LVDS connector) ?

> 
> > + - atmel,panel: Should contain a phandle with 2 parameters.
> > +   The first cell is a phandle to a DRM panel device
> > +   The second cell encodes the RGB mode, which can take the following
> > values:
> > +   * 0: RGB444
> > +   * 1: RGB565
> > +   * 2: RGB666
> > +   * 3: RGB888
> > +   The third cell encodes specific flags describing LCD signals
> > configuration
> > +   (see Atmel's datasheet for a full description of these
> > fields):
> > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > +   * bit 4: DISPPOL: Display Signal Polarity
> > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > Configuration
> > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > Configuration
> > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> 
> If I'm not mistaken, those are HLCDC configuration values that depend on the 
> panel type and characteristics. Shouldn't they then be queries from the panel 
> through the drm_panel API at runtime instead of being specified in DT ? This 
> would likely require extending the drm_panel API.

HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
GUARDTIME value.

Another question I had regarding these flags is whether they were LCD
panel specific or a mix of panel and board implementation.
Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
expects in terms of polarity, but nothing prevents the HW designer from
inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
A solution would be to override some drm_display_mode settings with
informations taken from the DT.

Thanks for your review.

Best Regards,

Boris

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-10 12:56       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-10 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Laurent,

On Thu, 10 Jul 2014 13:16:21 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> > 
> > The HLCDC block provides a single RGB output port, and only supports LCD
> > panels connection to LCD panels for now.
> > 
> > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > connected on this port (note that the HLCDC RGB connector implementation
> > makes use of the DRM panel framework).
> > 
> > Connection to other external devices (DRM bridges) might be added later by
> > mean of a new atmel,xxx (atmel,bridge) property.
> > 
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++++++
> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > 100644
> > index 0000000..594bdb2
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > @@ -0,0 +1,59 @@
> > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > +
> > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > +
> > +Required properties:
> > + - compatible: value should be one of the following:
> > +   "atmel,hlcdc-dc"
> > + - interrupts: the HLCDC interrupt definition
> > + - pinctrl-names: the pin control state names. Should contain "default",
> > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > + - pinctrl-[0-4]: should contain the pinctrl states described by pinctrl
> > +   names.
> 
> Do you need to switch between the different pinctrl configurations at runtime, 
> or is the configuration selected from the panel type, which doesn't change ?

At the moment no, but if we ever need to support different devices on
the same RGB connector (actually Atmel's sama5d3xek boards have an
RGB to HDMI bridge connected on the same RGB connector) and these
devices do not support the same RGB mode (say your LCD panel supports
RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
the output you select you'll have to change your pinctrl config at
runtime.

I'd say we could get rid of this runtime pinctrl config as a first step
if DT ABI stability was not required.
But it is, and I'd like to have a future proof binding to handle these
tricky cases when they occurs (if they ever do).

Anyway, I'm open to any other alternative that could let me add support
for this later on.

BTW, is there any reason for not defining an RGB connector type (I'm
currently defining HLCDC connector as an LVDS connector) ?

> 
> > + - atmel,panel: Should contain a phandle with 2 parameters.
> > +   The first cell is a phandle to a DRM panel device
> > +   The second cell encodes the RGB mode, which can take the following
> > values:
> > +   * 0: RGB444
> > +   * 1: RGB565
> > +   * 2: RGB666
> > +   * 3: RGB888
> > +   The third cell encodes specific flags describing LCD signals
> > configuration
> > +   (see Atmel's datasheet for a full description of these
> > fields):
> > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > +   * bit 4: DISPPOL: Display Signal Polarity
> > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > Configuration
> > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > Configuration
> > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> 
> If I'm not mistaken, those are HLCDC configuration values that depend on the 
> panel type and characteristics. Shouldn't they then be queries from the panel 
> through the drm_panel API at runtime instead of being specified in DT ? This 
> would likely require extending the drm_panel API.

HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
GUARDTIME value.

Another question I had regarding these flags is whether they were LCD
panel specific or a mix of panel and board implementation.
Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
expects in terms of polarity, but nothing prevents the HW designer from
inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
A solution would be to override some drm_display_mode settings with
informations taken from the DT.

Thanks for your review.

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-10 12:56       ` Boris BREZILLON
@ 2014-07-11 10:37         ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-11 10:37 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Samuel Ortiz, Lee Jones, Thierry Reding, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

Hi Boris,

On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > controller device.
> > > 
> > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > panels connection to LCD panels for now.
> > > 
> > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > connected on this port (note that the HLCDC RGB connector implementation
> > > makes use of the DRM panel framework).
> > > 
> > > Connection to other external devices (DRM bridges) might be added later
> > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > 
> > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > ---
> > > 
> > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > >  1 file changed, 59 insertions(+)
> > >  create mode 100644
> > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > 
> > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > 100644
> > > index 0000000..594bdb2
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > @@ -0,0 +1,59 @@
> > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > +
> > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > device.
> > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > details.
> > > +
> > > +Required properties:
> > > + - compatible: value should be one of the following:
> > > +   "atmel,hlcdc-dc"
> > > + - interrupts: the HLCDC interrupt definition
> > > + - pinctrl-names: the pin control state names. Should contain
> > > "default",
> > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > pinctrl
> > > +   names.
> > 
> > Do you need to switch between the different pinctrl configurations at
> > runtime, or is the configuration selected from the panel type, which
> > doesn't change ?
>
> At the moment no, but if we ever need to support different devices on
> the same RGB connector (actually Atmel's sama5d3xek boards have an
> RGB to HDMI bridge connected on the same RGB connector) and these
> devices do not support the same RGB mode (say your LCD panel supports
> RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> the output you select you'll have to change your pinctrl config at
> runtime.

Just to make sure I understand the use case correctly, are you talking about 
two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
connected to the same output, with the ability to switch between the two at 
runtime ? That's a valid case (on a side note we shouldn't forget that the 
option of using both devices at the same time should be supported as well), 
but I would probably go for a fixed pinctrl configuration that supports both, 
although switching configurations at runtime would be a micro-optimization 
that might make sense.

> I'd say we could get rid of this runtime pinctrl config as a first step
> if DT ABI stability was not required.
> But it is, and I'd like to have a future proof binding to handle these
> tricky cases when they occurs (if they ever do).

I think we have a shortcoming of the pinctrl API here in the general case. The 
API only allows you to select a single configuration per device. Imagine the 
same display controller, with two DPI outputs, each of them configurable in 
444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
so we'll have to fix this eventually. From a DT stability point of view, I 
would thus avoid specifying multiple pinctrl configurations now until we come 
up with a standard way to support this use case.

> Anyway, I'm open to any other alternative that could let me add support
> for this later on.
> 
> BTW, is there any reason for not defining an RGB connector type (I'm
> currently defining HLCDC connector as an LVDS connector) ?

Not that I know of. The DRM API has been developed before display on embedded 
systems became such a hot topic. If we had to redo it today, panels might be 
exposed to userspace as such, with a connector. We have to live with the past, 
so the connector will stay, but adding a new RGB connector type could make 
sense (although we might need a different name, in a way the VGA and LVDS 
connectors also carry RGB signals).

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following
> > > values:
> > > +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > > +   The third cell encodes specific flags describing LCD signals
> > > configuration
> > > +   (see Atmel's datasheet for a full description of these
> > > fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > If I'm not mistaken, those are HLCDC configuration values that depend on
> > the panel type and characteristics. Shouldn't they then be queries from
> > the panel through the drm_panel API at runtime instead of being specified
> > in DT ? This would likely require extending the drm_panel API.
> 
> HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> GUARDTIME value.
> 
> Another question I had regarding these flags is whether they were LCD
> panel specific or a mix of panel and board implementation.
> Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> expects in terms of polarity, but nothing prevents the HW designer from
> inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
>
> A solution would be to override some drm_display_mode settings with
> informations taken from the DT.

Given that I gave the exact same argument during a V4L2 DT bindings design 
review, I can only agree :-) It thus makes sense to specify polarities in the 
HLCDC DT node. The RGB mode, however, should probably be queried from the 
panel, as I don't expect it to be board-dependent but only panel-dependent.

I'm not sure about the other bits in the third cell, maybe we should discuss 
them in more details. I'm always wary when I see DT bindings referring to a 
datasheet :-) Getting the information from the panel by default, with a 
possible override, is an interesting option. You would thus likely need 
several DT properties associated with each connection to a panel. Would it 
then make sense to use the OF graph DT bindings instead of the atmel,panel 
property to specify connections ? You could store per-connection data in the 
endpoint and/or port nodes.

> Thanks for your review.

You're welcome. Sorry for not having had time to review the driver itself. 
Given my limited bandwidth at the moment I've decided to concentrate on the DT 
bindings first.

-- 
Regards,

Laurent Pinchart


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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-11 10:37         ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-11 10:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > controller device.
> > > 
> > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > panels connection to LCD panels for now.
> > > 
> > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > connected on this port (note that the HLCDC RGB connector implementation
> > > makes use of the DRM panel framework).
> > > 
> > > Connection to other external devices (DRM bridges) might be added later
> > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > 
> > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > ---
> > > 
> > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > >  1 file changed, 59 insertions(+)
> > >  create mode 100644
> > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > 
> > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > 100644
> > > index 0000000..594bdb2
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > @@ -0,0 +1,59 @@
> > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > +
> > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > device.
> > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > details.
> > > +
> > > +Required properties:
> > > + - compatible: value should be one of the following:
> > > +   "atmel,hlcdc-dc"
> > > + - interrupts: the HLCDC interrupt definition
> > > + - pinctrl-names: the pin control state names. Should contain
> > > "default",
> > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > pinctrl
> > > +   names.
> > 
> > Do you need to switch between the different pinctrl configurations at
> > runtime, or is the configuration selected from the panel type, which
> > doesn't change ?
>
> At the moment no, but if we ever need to support different devices on
> the same RGB connector (actually Atmel's sama5d3xek boards have an
> RGB to HDMI bridge connected on the same RGB connector) and these
> devices do not support the same RGB mode (say your LCD panel supports
> RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> the output you select you'll have to change your pinctrl config at
> runtime.

Just to make sure I understand the use case correctly, are you talking about 
two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
connected to the same output, with the ability to switch between the two at 
runtime ? That's a valid case (on a side note we shouldn't forget that the 
option of using both devices at the same time should be supported as well), 
but I would probably go for a fixed pinctrl configuration that supports both, 
although switching configurations at runtime would be a micro-optimization 
that might make sense.

> I'd say we could get rid of this runtime pinctrl config as a first step
> if DT ABI stability was not required.
> But it is, and I'd like to have a future proof binding to handle these
> tricky cases when they occurs (if they ever do).

I think we have a shortcoming of the pinctrl API here in the general case. The 
API only allows you to select a single configuration per device. Imagine the 
same display controller, with two DPI outputs, each of them configurable in 
444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
so we'll have to fix this eventually. From a DT stability point of view, I 
would thus avoid specifying multiple pinctrl configurations now until we come 
up with a standard way to support this use case.

> Anyway, I'm open to any other alternative that could let me add support
> for this later on.
> 
> BTW, is there any reason for not defining an RGB connector type (I'm
> currently defining HLCDC connector as an LVDS connector) ?

Not that I know of. The DRM API has been developed before display on embedded 
systems became such a hot topic. If we had to redo it today, panels might be 
exposed to userspace as such, with a connector. We have to live with the past, 
so the connector will stay, but adding a new RGB connector type could make 
sense (although we might need a different name, in a way the VGA and LVDS 
connectors also carry RGB signals).

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following
> > > values:
> > > +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > > +   The third cell encodes specific flags describing LCD signals
> > > configuration
> > > +   (see Atmel's datasheet for a full description of these
> > > fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > If I'm not mistaken, those are HLCDC configuration values that depend on
> > the panel type and characteristics. Shouldn't they then be queries from
> > the panel through the drm_panel API at runtime instead of being specified
> > in DT ? This would likely require extending the drm_panel API.
> 
> HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> GUARDTIME value.
> 
> Another question I had regarding these flags is whether they were LCD
> panel specific or a mix of panel and board implementation.
> Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> expects in terms of polarity, but nothing prevents the HW designer from
> inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
>
> A solution would be to override some drm_display_mode settings with
> informations taken from the DT.

Given that I gave the exact same argument during a V4L2 DT bindings design 
review, I can only agree :-) It thus makes sense to specify polarities in the 
HLCDC DT node. The RGB mode, however, should probably be queried from the 
panel, as I don't expect it to be board-dependent but only panel-dependent.

I'm not sure about the other bits in the third cell, maybe we should discuss 
them in more details. I'm always wary when I see DT bindings referring to a 
datasheet :-) Getting the information from the panel by default, with a 
possible override, is an interesting option. You would thus likely need 
several DT properties associated with each connection to a panel. Would it 
then make sense to use the OF graph DT bindings instead of the atmel,panel 
property to specify connections ? You could store per-connection data in the 
endpoint and/or port nodes.

> Thanks for your review.

You're welcome. Sorry for not having had time to review the driver itself. 
Given my limited bandwidth at the moment I've decided to concentrate on the DT 
bindings first.

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-11 10:37         ` Laurent Pinchart
@ 2014-07-11 12:00           ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 12:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

On Fri, 11 Jul 2014 12:37:46 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> > On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > controller device.
> > > > 
> > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > panels connection to LCD panels for now.
> > > > 
> > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > makes use of the DRM panel framework).
> > > > 
> > > > Connection to other external devices (DRM bridges) might be added later
> > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > 
> > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > ---
> > > > 
> > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > >  1 file changed, 59 insertions(+)
> > > >  create mode 100644
> > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > > 100644
> > > > index 0000000..594bdb2
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > @@ -0,0 +1,59 @@
> > > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > > +
> > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > > device.
> > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > > details.
> > > > +
> > > > +Required properties:
> > > > + - compatible: value should be one of the following:
> > > > +   "atmel,hlcdc-dc"
> > > > + - interrupts: the HLCDC interrupt definition
> > > > + - pinctrl-names: the pin control state names. Should contain
> > > > "default",
> > > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > > pinctrl
> > > > +   names.
> > > 
> > > Do you need to switch between the different pinctrl configurations at
> > > runtime, or is the configuration selected from the panel type, which
> > > doesn't change ?
> >
> > At the moment no, but if we ever need to support different devices on
> > the same RGB connector (actually Atmel's sama5d3xek boards have an
> > RGB to HDMI bridge connected on the same RGB connector) and these
> > devices do not support the same RGB mode (say your LCD panel supports
> > RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> > the output you select you'll have to change your pinctrl config at
> > runtime.
> 
> Just to make sure I understand the use case correctly, are you talking about 
> two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
> connected to the same output, with the ability to switch between the two at 
> runtime ?

Exactly.

> That's a valid case (on a side note we shouldn't forget that the 
> option of using both devices at the same time should be supported as well), 

AFAICT this is only possible if both devices connected to the RGB
connector use the same mode.

> but I would probably go for a fixed pinctrl configuration that supports both, 
> although switching configurations at runtime would be a micro-optimization 
> that might make sense.

Yep, it should work, and I agree that we're unlikely to reuse some RGB
pins for other usage when the active device is the one using RGB666
mode.

> 
> > I'd say we could get rid of this runtime pinctrl config as a first step
> > if DT ABI stability was not required.
> > But it is, and I'd like to have a future proof binding to handle these
> > tricky cases when they occurs (if they ever do).
> 
> I think we have a shortcoming of the pinctrl API here in the general case. The 
> API only allows you to select a single configuration per device. Imagine the 
> same display controller, with two DPI outputs, each of them configurable in 
> 444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
> 16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
> so we'll have to fix this eventually. From a DT stability point of view, I 
> would thus avoid specifying multiple pinctrl configurations now until we come 
> up with a standard way to support this use case.

Given your inputs, I guess I'll drop dynamic pinctrl config for the
next version.

> 
> > Anyway, I'm open to any other alternative that could let me add support
> > for this later on.
> > 
> > BTW, is there any reason for not defining an RGB connector type (I'm
> > currently defining HLCDC connector as an LVDS connector) ?
> 
> Not that I know of. The DRM API has been developed before display on embedded 
> systems became such a hot topic. If we had to redo it today, panels might be 
> exposed to userspace as such, with a connector. We have to live with the past, 
> so the connector will stay, but adding a new RGB connector type could make 
> sense (although we might need a different name, in a way the VGA and LVDS 
> connectors also carry RGB signals).

I had the same concern: I didn't find how this kind of connectors
was named (most of the time they're just referenced as RGB) :-).
What about RAW_RGB ?

> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following
> > > > values:
> > > > +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > > +   The third cell encodes specific flags describing LCD signals
> > > > configuration
> > > > +   (see Atmel's datasheet for a full description of these
> > > > fields):
> > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > > Synchronization
> > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > > Configuration
> > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > > Configuration
> > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > 
> > > If I'm not mistaken, those are HLCDC configuration values that depend on
> > > the panel type and characteristics. Shouldn't they then be queries from
> > > the panel through the drm_panel API at runtime instead of being specified
> > > in DT ? This would likely require extending the drm_panel API.
> > 
> > HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> > DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> > GUARDTIME value.
> > 
> > Another question I had regarding these flags is whether they were LCD
> > panel specific or a mix of panel and board implementation.
> > Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> > expects in terms of polarity, but nothing prevents the HW designer from
> > inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
> >
> > A solution would be to override some drm_display_mode settings with
> > informations taken from the DT.
> 
> Given that I gave the exact same argument during a V4L2 DT bindings design 
> review, I can only agree :-) It thus makes sense to specify polarities in the 
> HLCDC DT node. The RGB mode, however, should probably be queried from the 
> panel, as I don't expect it to be board-dependent but only panel-dependent.

Yes, what I had in mind is some kind of RGB connector framework (or
just helper functions), where you could define the supported RGB modes
and rely on another infrastructure to define the supported drm display
modes.
Because RGB connector is not just related to panels: see this RGB to
HDMI bridge [1] (this is the one used on Atmel's dev boards).
Moreover, simple panels are connector agnostics for now, and I'm not
sure we want to change that.

[1]http://pdf1.alldatasheet.fr/datasheet-pdf/view/218068/SILICONIMAGE/SII9022.html

> 
> I'm not sure about the other bits in the third cell, maybe we should discuss 
> them in more details. I'm always wary when I see DT bindings referring to a 
> datasheet :-) Getting the information from the panel by default, with a 
> possible override, is an interesting option. You would thus likely need 
> several DT properties associated with each connection to a panel. Would it 
> then make sense to use the OF graph DT bindings instead of the atmel,panel 
> property to specify connections ? You could store per-connection data in the 
> endpoint and/or port nodes.

I'll take a look at these bindings and let you know if they match my
needs.

> 
> > Thanks for your review.
> 
> You're welcome. Sorry for not having had time to review the driver itself. 
> Given my limited bandwidth at the moment I've decided to concentrate on the DT 
> bindings first.

No problem, after all DT bindings is the most tricky part of our work
nowadays, isn't it ;-) ?

Thanks,

Boris

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-11 12:00           ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 11 Jul 2014 12:37:46 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> > On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > controller device.
> > > > 
> > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > panels connection to LCD panels for now.
> > > > 
> > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > makes use of the DRM panel framework).
> > > > 
> > > > Connection to other external devices (DRM bridges) might be added later
> > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > 
> > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > ---
> > > > 
> > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > >  1 file changed, 59 insertions(+)
> > > >  create mode 100644
> > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > > 100644
> > > > index 0000000..594bdb2
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > @@ -0,0 +1,59 @@
> > > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > > +
> > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > > device.
> > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > > details.
> > > > +
> > > > +Required properties:
> > > > + - compatible: value should be one of the following:
> > > > +   "atmel,hlcdc-dc"
> > > > + - interrupts: the HLCDC interrupt definition
> > > > + - pinctrl-names: the pin control state names. Should contain
> > > > "default",
> > > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > > pinctrl
> > > > +   names.
> > > 
> > > Do you need to switch between the different pinctrl configurations at
> > > runtime, or is the configuration selected from the panel type, which
> > > doesn't change ?
> >
> > At the moment no, but if we ever need to support different devices on
> > the same RGB connector (actually Atmel's sama5d3xek boards have an
> > RGB to HDMI bridge connected on the same RGB connector) and these
> > devices do not support the same RGB mode (say your LCD panel supports
> > RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> > the output you select you'll have to change your pinctrl config at
> > runtime.
> 
> Just to make sure I understand the use case correctly, are you talking about 
> two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
> connected to the same output, with the ability to switch between the two at 
> runtime ?

Exactly.

> That's a valid case (on a side note we shouldn't forget that the 
> option of using both devices at the same time should be supported as well), 

AFAICT this is only possible if both devices connected to the RGB
connector use the same mode.

> but I would probably go for a fixed pinctrl configuration that supports both, 
> although switching configurations at runtime would be a micro-optimization 
> that might make sense.

Yep, it should work, and I agree that we're unlikely to reuse some RGB
pins for other usage when the active device is the one using RGB666
mode.

> 
> > I'd say we could get rid of this runtime pinctrl config as a first step
> > if DT ABI stability was not required.
> > But it is, and I'd like to have a future proof binding to handle these
> > tricky cases when they occurs (if they ever do).
> 
> I think we have a shortcoming of the pinctrl API here in the general case. The 
> API only allows you to select a single configuration per device. Imagine the 
> same display controller, with two DPI outputs, each of them configurable in 
> 444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
> 16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
> so we'll have to fix this eventually. From a DT stability point of view, I 
> would thus avoid specifying multiple pinctrl configurations now until we come 
> up with a standard way to support this use case.

Given your inputs, I guess I'll drop dynamic pinctrl config for the
next version.

> 
> > Anyway, I'm open to any other alternative that could let me add support
> > for this later on.
> > 
> > BTW, is there any reason for not defining an RGB connector type (I'm
> > currently defining HLCDC connector as an LVDS connector) ?
> 
> Not that I know of. The DRM API has been developed before display on embedded 
> systems became such a hot topic. If we had to redo it today, panels might be 
> exposed to userspace as such, with a connector. We have to live with the past, 
> so the connector will stay, but adding a new RGB connector type could make 
> sense (although we might need a different name, in a way the VGA and LVDS 
> connectors also carry RGB signals).

I had the same concern: I didn't find how this kind of connectors
was named (most of the time they're just referenced as RGB) :-).
What about RAW_RGB ?

> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following
> > > > values:
> > > > +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > > +   The third cell encodes specific flags describing LCD signals
> > > > configuration
> > > > +   (see Atmel's datasheet for a full description of these
> > > > fields):
> > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > > Synchronization
> > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > > Configuration
> > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > > Configuration
> > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > 
> > > If I'm not mistaken, those are HLCDC configuration values that depend on
> > > the panel type and characteristics. Shouldn't they then be queries from
> > > the panel through the drm_panel API at runtime instead of being specified
> > > in DT ? This would likely require extending the drm_panel API.
> > 
> > HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> > DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> > GUARDTIME value.
> > 
> > Another question I had regarding these flags is whether they were LCD
> > panel specific or a mix of panel and board implementation.
> > Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> > expects in terms of polarity, but nothing prevents the HW designer from
> > inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
> >
> > A solution would be to override some drm_display_mode settings with
> > informations taken from the DT.
> 
> Given that I gave the exact same argument during a V4L2 DT bindings design 
> review, I can only agree :-) It thus makes sense to specify polarities in the 
> HLCDC DT node. The RGB mode, however, should probably be queried from the 
> panel, as I don't expect it to be board-dependent but only panel-dependent.

Yes, what I had in mind is some kind of RGB connector framework (or
just helper functions), where you could define the supported RGB modes
and rely on another infrastructure to define the supported drm display
modes.
Because RGB connector is not just related to panels: see this RGB to
HDMI bridge [1] (this is the one used on Atmel's dev boards).
Moreover, simple panels are connector agnostics for now, and I'm not
sure we want to change that.

[1]http://pdf1.alldatasheet.fr/datasheet-pdf/view/218068/SILICONIMAGE/SII9022.html

> 
> I'm not sure about the other bits in the third cell, maybe we should discuss 
> them in more details. I'm always wary when I see DT bindings referring to a 
> datasheet :-) Getting the information from the panel by default, with a 
> possible override, is an interesting option. You would thus likely need 
> several DT properties associated with each connection to a panel. Would it 
> then make sense to use the OF graph DT bindings instead of the atmel,panel 
> property to specify connections ? You could store per-connection data in the 
> endpoint and/or port nodes.

I'll take a look at these bindings and let you know if they match my
needs.

> 
> > Thanks for your review.
> 
> You're welcome. Sorry for not having had time to review the driver itself. 
> Given my limited bandwidth at the moment I've decided to concentrate on the DT 
> bindings first.

No problem, after all DT bindings is the most tricky part of our work
nowadays, isn't it ;-) ?

Thanks,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-11 12:00           ` Boris BREZILLON
@ 2014-07-11 12:19             ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 12:19 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Laurent Pinchart, Samuel Ortiz, Lee Jones, Thierry Reding,
	linux-pwm, David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson

On Fri, 11 Jul 2014 14:00:25 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> On Fri, 11 Jul 2014 12:37:46 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Boris,
> > 
> > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> > > On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > > > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > > controller device.
> > > > > 
> > > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > > panels connection to LCD panels for now.
> > > > > 
> > > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > > makes use of the DRM panel framework).
> > > > > 
> > > > > Connection to other external devices (DRM bridges) might be added later
> > > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > > 
> > > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > > ---
> > > > > 
> > > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > > >  1 file changed, 59 insertions(+)
> > > > >  create mode 100644
> > > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > > > 100644
> > > > > index 0000000..594bdb2
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > @@ -0,0 +1,59 @@
> > > > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > > > +
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > > > device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > > > details.
> > > > > +
> > > > > +Required properties:
> > > > > + - compatible: value should be one of the following:
> > > > > +   "atmel,hlcdc-dc"
> > > > > + - interrupts: the HLCDC interrupt definition
> > > > > + - pinctrl-names: the pin control state names. Should contain
> > > > > "default",
> > > > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > > > pinctrl
> > > > > +   names.
> > > > 
> > > > Do you need to switch between the different pinctrl configurations at
> > > > runtime, or is the configuration selected from the panel type, which
> > > > doesn't change ?
> > >
> > > At the moment no, but if we ever need to support different devices on
> > > the same RGB connector (actually Atmel's sama5d3xek boards have an
> > > RGB to HDMI bridge connected on the same RGB connector) and these
> > > devices do not support the same RGB mode (say your LCD panel supports
> > > RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> > > the output you select you'll have to change your pinctrl config at
> > > runtime.
> > 
> > Just to make sure I understand the use case correctly, are you talking about 
> > two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
> > connected to the same output, with the ability to switch between the two at 
> > runtime ?
> 
> Exactly.
> 
> > That's a valid case (on a side note we shouldn't forget that the 
> > option of using both devices at the same time should be supported as well), 
> 
> AFAICT this is only possible if both devices connected to the RGB
> connector use the same mode.
> 
> > but I would probably go for a fixed pinctrl configuration that supports both, 
> > although switching configurations at runtime would be a micro-optimization 
> > that might make sense.
> 
> Yep, it should work, and I agree that we're unlikely to reuse some RGB
> pins for other usage when the active device is the one using RGB666
> mode.
> 
> > 
> > > I'd say we could get rid of this runtime pinctrl config as a first step
> > > if DT ABI stability was not required.
> > > But it is, and I'd like to have a future proof binding to handle these
> > > tricky cases when they occurs (if they ever do).
> > 
> > I think we have a shortcoming of the pinctrl API here in the general case. The 
> > API only allows you to select a single configuration per device. Imagine the 
> > same display controller, with two DPI outputs, each of them configurable in 
> > 444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
> > 16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
> > so we'll have to fix this eventually. From a DT stability point of view, I 
> > would thus avoid specifying multiple pinctrl configurations now until we come 
> > up with a standard way to support this use case.
> 
> Given your inputs, I guess I'll drop dynamic pinctrl config for the
> next version.
> 
> > 
> > > Anyway, I'm open to any other alternative that could let me add support
> > > for this later on.
> > > 
> > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > currently defining HLCDC connector as an LVDS connector) ?
> > 
> > Not that I know of. The DRM API has been developed before display on embedded 
> > systems became such a hot topic. If we had to redo it today, panels might be 
> > exposed to userspace as such, with a connector. We have to live with the past, 
> > so the connector will stay, but adding a new RGB connector type could make 
> > sense (although we might need a different name, in a way the VGA and LVDS 
> > connectors also carry RGB signals).
> 
> I had the same concern: I didn't find how this kind of connectors
> was named (most of the time they're just referenced as RGB) :-).
> What about RAW_RGB ?

Okay, actually there is a widely used name for this kind of connectors
and it's "Parallel RGB" (thanks Thomas ;-)).

> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following
> > > > > values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > > +   The third cell encodes specific flags describing LCD signals
> > > > > configuration
> > > > > +   (see Atmel's datasheet for a full description of these
> > > > > fields):
> > > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > > > Synchronization
> > > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > > > Configuration
> > > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > > > Configuration
> > > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > > 
> > > > If I'm not mistaken, those are HLCDC configuration values that depend on
> > > > the panel type and characteristics. Shouldn't they then be queries from
> > > > the panel through the drm_panel API at runtime instead of being specified
> > > > in DT ? This would likely require extending the drm_panel API.
> > > 
> > > HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> > > DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> > > GUARDTIME value.
> > > 
> > > Another question I had regarding these flags is whether they were LCD
> > > panel specific or a mix of panel and board implementation.
> > > Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> > > expects in terms of polarity, but nothing prevents the HW designer from
> > > inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
> > >
> > > A solution would be to override some drm_display_mode settings with
> > > informations taken from the DT.
> > 
> > Given that I gave the exact same argument during a V4L2 DT bindings design 
> > review, I can only agree :-) It thus makes sense to specify polarities in the 
> > HLCDC DT node. The RGB mode, however, should probably be queried from the 
> > panel, as I don't expect it to be board-dependent but only panel-dependent.
> 
> Yes, what I had in mind is some kind of RGB connector framework (or
> just helper functions), where you could define the supported RGB modes
> and rely on another infrastructure to define the supported drm display
> modes.
> Because RGB connector is not just related to panels: see this RGB to
> HDMI bridge [1] (this is the one used on Atmel's dev boards).
> Moreover, simple panels are connector agnostics for now, and I'm not
> sure we want to change that.
> 
> [1]http://pdf1.alldatasheet.fr/datasheet-pdf/view/218068/SILICONIMAGE/SII9022.html
> 
> > 
> > I'm not sure about the other bits in the third cell, maybe we should discuss 
> > them in more details. I'm always wary when I see DT bindings referring to a 
> > datasheet :-) Getting the information from the panel by default, with a 
> > possible override, is an interesting option. You would thus likely need 
> > several DT properties associated with each connection to a panel. Would it 
> > then make sense to use the OF graph DT bindings instead of the atmel,panel 
> > property to specify connections ? You could store per-connection data in the 
> > endpoint and/or port nodes.
> 
> I'll take a look at these bindings and let you know if they match my
> needs.
> 
> > 
> > > Thanks for your review.
> > 
> > You're welcome. Sorry for not having had time to review the driver itself. 
> > Given my limited bandwidth at the moment I've decided to concentrate on the DT 
> > bindings first.
> 
> No problem, after all DT bindings is the most tricky part of our work
> nowadays, isn't it ;-) ?
> 
> Thanks,
> 
> Boris
> 



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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-11 12:19             ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 12:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 11 Jul 2014 14:00:25 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> On Fri, 11 Jul 2014 12:37:46 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Boris,
> > 
> > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> > > On Thu, 10 Jul 2014 13:16:21 +0200 Laurent Pinchart wrote:
> > > > On Monday 07 July 2014 18:42:59 Boris BREZILLON wrote:
> > > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > > controller device.
> > > > > 
> > > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > > panels connection to LCD panels for now.
> > > > > 
> > > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > > makes use of the DRM panel framework).
> > > > > 
> > > > > Connection to other external devices (DRM bridges) might be added later
> > > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > > 
> > > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > > ---
> > > > > 
> > > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > > >  1 file changed, 59 insertions(+)
> > > > >  create mode 100644
> > > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt new file mode
> > > > > 100644
> > > > > index 0000000..594bdb2
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > @@ -0,0 +1,59 @@
> > > > > +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
> > > > > +
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD
> > > > > device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more
> > > > > details.
> > > > > +
> > > > > +Required properties:
> > > > > + - compatible: value should be one of the following:
> > > > > +   "atmel,hlcdc-dc"
> > > > > + - interrupts: the HLCDC interrupt definition
> > > > > + - pinctrl-names: the pin control state names. Should contain
> > > > > "default",
> > > > > +   "rgb-444", "rgb-565", "rgb-666" and "rgb-888".
> > > > > + - pinctrl-[0-4]: should contain the pinctrl states described by
> > > > > pinctrl
> > > > > +   names.
> > > > 
> > > > Do you need to switch between the different pinctrl configurations at
> > > > runtime, or is the configuration selected from the panel type, which
> > > > doesn't change ?
> > >
> > > At the moment no, but if we ever need to support different devices on
> > > the same RGB connector (actually Atmel's sama5d3xek boards have an
> > > RGB to HDMI bridge connected on the same RGB connector) and these
> > > devices do not support the same RGB mode (say your LCD panel supports
> > > RGB888 and your RGB to HDMI bridge supports RGB555), then depending on
> > > the output you select you'll have to change your pinctrl config at
> > > runtime.
> > 
> > Just to make sure I understand the use case correctly, are you talking about 
> > two devices (for example an RGB666 panel and an RGB888 RGB to HDMI bridge) 
> > connected to the same output, with the ability to switch between the two at 
> > runtime ?
> 
> Exactly.
> 
> > That's a valid case (on a side note we shouldn't forget that the 
> > option of using both devices at the same time should be supported as well), 
> 
> AFAICT this is only possible if both devices connected to the RGB
> connector use the same mode.
> 
> > but I would probably go for a fixed pinctrl configuration that supports both, 
> > although switching configurations at runtime would be a micro-optimization 
> > that might make sense.
> 
> Yep, it should work, and I agree that we're unlikely to reuse some RGB
> pins for other usage when the active device is the one using RGB666
> mode.
> 
> > 
> > > I'd say we could get rid of this runtime pinctrl config as a first step
> > > if DT ABI stability was not required.
> > > But it is, and I'd like to have a future proof binding to handle these
> > > tricky cases when they occurs (if they ever do).
> > 
> > I think we have a shortcoming of the pinctrl API here in the general case. The 
> > API only allows you to select a single configuration per device. Imagine the 
> > same display controller, with two DPI outputs, each of them configurable in 
> > 444, 565, 666 or 888 modes. With the current API we would have to create 4*4 = 
> > 16 pinctrl configurations for all combinations. That obviously wouldn't scale, 
> > so we'll have to fix this eventually. From a DT stability point of view, I 
> > would thus avoid specifying multiple pinctrl configurations now until we come 
> > up with a standard way to support this use case.
> 
> Given your inputs, I guess I'll drop dynamic pinctrl config for the
> next version.
> 
> > 
> > > Anyway, I'm open to any other alternative that could let me add support
> > > for this later on.
> > > 
> > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > currently defining HLCDC connector as an LVDS connector) ?
> > 
> > Not that I know of. The DRM API has been developed before display on embedded 
> > systems became such a hot topic. If we had to redo it today, panels might be 
> > exposed to userspace as such, with a connector. We have to live with the past, 
> > so the connector will stay, but adding a new RGB connector type could make 
> > sense (although we might need a different name, in a way the VGA and LVDS 
> > connectors also carry RGB signals).
> 
> I had the same concern: I didn't find how this kind of connectors
> was named (most of the time they're just referenced as RGB) :-).
> What about RAW_RGB ?

Okay, actually there is a widely used name for this kind of connectors
and it's "Parallel RGB" (thanks Thomas ;-)).

> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following
> > > > > values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > > +   The third cell encodes specific flags describing LCD signals
> > > > > configuration
> > > > > +   (see Atmel's datasheet for a full description of these
> > > > > fields):
> > > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > > > Synchronization
> > > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > > > Configuration
> > > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > > > Configuration
> > > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > > 
> > > > If I'm not mistaken, those are HLCDC configuration values that depend on
> > > > the panel type and characteristics. Shouldn't they then be queries from
> > > > the panel through the drm_panel API at runtime instead of being specified
> > > > in DT ? This would likely require extending the drm_panel API.
> > > 
> > > HSPOL and VSPOL can be deduced from DRM_MODE_FLAG_[PN]HSYNC and
> > > DRM_MODE_FLAG_[PN]VSYNC, I'm not sure for the other flags or the
> > > GUARDTIME value.
> > > 
> > > Another question I had regarding these flags is whether they were LCD
> > > panel specific or a mix of panel and board implementation.
> > > Take the VSYNC HSYNC polarity, of course the LCD panel defines what it
> > > expects in terms of polarity, but nothing prevents the HW designer from
> > > inverting the VSYNC/HSYNC polarity (expect common sense :-)), right ?
> > >
> > > A solution would be to override some drm_display_mode settings with
> > > informations taken from the DT.
> > 
> > Given that I gave the exact same argument during a V4L2 DT bindings design 
> > review, I can only agree :-) It thus makes sense to specify polarities in the 
> > HLCDC DT node. The RGB mode, however, should probably be queried from the 
> > panel, as I don't expect it to be board-dependent but only panel-dependent.
> 
> Yes, what I had in mind is some kind of RGB connector framework (or
> just helper functions), where you could define the supported RGB modes
> and rely on another infrastructure to define the supported drm display
> modes.
> Because RGB connector is not just related to panels: see this RGB to
> HDMI bridge [1] (this is the one used on Atmel's dev boards).
> Moreover, simple panels are connector agnostics for now, and I'm not
> sure we want to change that.
> 
> [1]http://pdf1.alldatasheet.fr/datasheet-pdf/view/218068/SILICONIMAGE/SII9022.html
> 
> > 
> > I'm not sure about the other bits in the third cell, maybe we should discuss 
> > them in more details. I'm always wary when I see DT bindings referring to a 
> > datasheet :-) Getting the information from the panel by default, with a 
> > possible override, is an interesting option. You would thus likely need 
> > several DT properties associated with each connection to a panel. Would it 
> > then make sense to use the OF graph DT bindings instead of the atmel,panel 
> > property to specify connections ? You could store per-connection data in the 
> > endpoint and/or port nodes.
> 
> I'll take a look at these bindings and let you know if they match my
> needs.
> 
> > 
> > > Thanks for your review.
> > 
> > You're welcome. Sorry for not having had time to review the driver itself. 
> > Given my limited bandwidth at the moment I've decided to concentrate on the DT 
> > bindings first.
> 
> No problem, after all DT bindings is the most tricky part of our work
> nowadays, isn't it ;-) ?
> 
> Thanks,
> 
> Boris
> 



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

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

* [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full
  2014-07-09 11:53         ` Rob Clark
  (?)
@ 2014-07-11 15:17         ` Boris BREZILLON
  2014-07-11 15:41           ` Rob Clark
  -1 siblings, 1 reply; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 15:17 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

Make use of lists instead of kfifo in order to dynamically allocate
task entry when someone require some delayed work, and thus preventing
drm_flip_work_queue from directly calling func instead of queuing this
call.
This allow drm_flip_work_queue to be safely called even within irq
handlers.

Add new helper functions to allocate a flip work task and queue it when
needed. This prevents allocating data within irq context (which might
impact the time spent in the irq handler).

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
---
Hi Rob,

This is a proposal for what you suggested (dynamically growing the drm
flip work queue in order to avoid direct call of work->func when calling
drm_flip_work_queue).

I'm not sure this is exactly what you expected, because I'm now using
lists instead of kfifo (and thus lose the lockless part), but at least
we can now safely call drm_flip_work_queue or drm_flip_work_queue_task
from irq handlers :-).

You were also worried about queueing the same framebuffer multiple times
and with this implementation you shouldn't have any problem (at least with
drm_flip_work_queue, what people do with drm_flip_work_queue_task is their
own responsability, but they should allocate one task for each operation
even if they are manipulating the same framebuffer).

This is just a suggestion, so don't hesitate to tell me that it doesn't
match your expectations.

Best Regards,

Boris

 drivers/gpu/drm/drm_flip_work.c | 95 ++++++++++++++++++++++++++++++-----------
 include/drm/drm_flip_work.h     | 29 +++++++++----
 2 files changed, 92 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c
index f9c7fa3..21d5715 100644
--- a/drivers/gpu/drm/drm_flip_work.c
+++ b/drivers/gpu/drm/drm_flip_work.c
@@ -25,6 +25,43 @@
 #include "drm_flip_work.h"
 
 /**
+ * drm_flip_work_allocate_task - allocate a flip-work task
+ * @data: data associated to the task
+ *
+ * Allocate a drm_flip_task object and attach private data to it.
+ */
+struct drm_flip_task *drm_flip_work_allocate_task(void *data)
+{
+	struct drm_flip_task *task;
+
+	task = kzalloc(sizeof(*task), GFP_KERNEL);
+	if (task)
+		task->data = data;
+
+	return task;
+}
+EXPORT_SYMBOL(drm_flip_work_allocate_task);
+
+/**
+ * drm_flip_work_queue_task - queue a specific task
+ * @work: the flip-work
+ * @task: the task to handle
+ *
+ * Queues task, that will later be run (passed back to drm_flip_func_t
+ * func) on a work queue after drm_flip_work_commit() is called.
+ */
+void drm_flip_work_queue_task(struct drm_flip_work *work,
+			      struct drm_flip_task *task)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	list_add_tail(&task->node, &work->queued);
+	spin_unlock_irqrestore(&work->lock, flags);
+}
+EXPORT_SYMBOL(drm_flip_work_queue_task);
+
+/**
  * drm_flip_work_queue - queue work
  * @work: the flip-work
  * @val: the value to queue
@@ -34,10 +71,14 @@
  */
 void drm_flip_work_queue(struct drm_flip_work *work, void *val)
 {
-	if (kfifo_put(&work->fifo, val)) {
-		atomic_inc(&work->pending);
+	struct drm_flip_task *task;
+
+	task = kzalloc(sizeof(*task), GFP_KERNEL);
+	if (task) {
+		task->data = val;
+		drm_flip_work_queue_task(work, task);
 	} else {
-		DRM_ERROR("%s fifo full!\n", work->name);
+		DRM_ERROR("%s could not allocate task!\n", work->name);
 		work->func(work, val);
 	}
 }
@@ -56,9 +97,12 @@ EXPORT_SYMBOL(drm_flip_work_queue);
 void drm_flip_work_commit(struct drm_flip_work *work,
 		struct workqueue_struct *wq)
 {
-	uint32_t pending = atomic_read(&work->pending);
-	atomic_add(pending, &work->count);
-	atomic_sub(pending, &work->pending);
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	list_splice_tail(&work->queued, &work->commited);
+	INIT_LIST_HEAD(&work->queued);
+	spin_unlock_irqrestore(&work->lock, flags);
 	queue_work(wq, &work->worker);
 }
 EXPORT_SYMBOL(drm_flip_work_commit);
@@ -66,14 +110,26 @@ EXPORT_SYMBOL(drm_flip_work_commit);
 static void flip_worker(struct work_struct *w)
 {
 	struct drm_flip_work *work = container_of(w, struct drm_flip_work, worker);
-	uint32_t count = atomic_read(&work->count);
-	void *val = NULL;
+	struct list_head tasks;
+	unsigned long flags;
 
-	atomic_sub(count, &work->count);
+	while (1) {
+		struct drm_flip_task *task, *tmp;
 
-	while(count--)
-		if (!WARN_ON(!kfifo_get(&work->fifo, &val)))
-			work->func(work, val);
+		INIT_LIST_HEAD(&tasks);
+		spin_lock_irqsave(&work->lock, flags);
+		list_splice_tail(&work->commited, &tasks);
+		INIT_LIST_HEAD(&work->commited);
+		spin_unlock_irqrestore(&work->lock, flags);
+
+		if (list_empty(&tasks))
+			break;
+
+		list_for_each_entry_safe(task, tmp, &tasks, node) {
+			work->func(work, task->data);
+			kfree(task);
+		}
+	}
 }
 
 /**
@@ -91,19 +147,11 @@ static void flip_worker(struct work_struct *w)
 int drm_flip_work_init(struct drm_flip_work *work, int size,
 		const char *name, drm_flip_func_t func)
 {
-	int ret;
-
 	work->name = name;
-	atomic_set(&work->count, 0);
-	atomic_set(&work->pending, 0);
+	INIT_LIST_HEAD(&work->queued);
+	INIT_LIST_HEAD(&work->commited);
 	work->func = func;
 
-	ret = kfifo_alloc(&work->fifo, size, GFP_KERNEL);
-	if (ret) {
-		DRM_ERROR("could not allocate %s fifo\n", name);
-		return ret;
-	}
-
 	INIT_WORK(&work->worker, flip_worker);
 
 	return 0;
@@ -118,7 +166,6 @@ EXPORT_SYMBOL(drm_flip_work_init);
  */
 void drm_flip_work_cleanup(struct drm_flip_work *work)
 {
-	WARN_ON(!kfifo_is_empty(&work->fifo));
-	kfifo_free(&work->fifo);
+	WARN_ON(!list_empty(&work->queued) || !list_empty(&work->commited));
 }
 EXPORT_SYMBOL(drm_flip_work_cleanup);
diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h
index 9eed34d..549981f 100644
--- a/include/drm/drm_flip_work.h
+++ b/include/drm/drm_flip_work.h
@@ -25,6 +25,7 @@
 #define DRM_FLIP_WORK_H
 
 #include <linux/kfifo.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 
 /**
@@ -32,9 +33,7 @@
  *
  * Util to queue up work to run from work-queue context after flip/vblank.
  * Typically this can be used to defer unref of framebuffer's, cursor
- * bo's, etc until after vblank.  The APIs are all safe (and lockless)
- * for up to one producer and once consumer at a time.  The single-consumer
- * aspect is ensured by committing the queued work to a single work-queue.
+ * bo's, etc until after vblank.  The APIs are all safe.
  */
 
 struct drm_flip_work;
@@ -51,22 +50,36 @@ struct drm_flip_work;
 typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val);
 
 /**
+ * struct drm_flip_task - flip work task
+ * @node: list entry element
+ * @data: data to pass to work->func
+ */
+struct drm_flip_task {
+	struct list_head node;
+	void *data;
+};
+
+/**
  * struct drm_flip_work - flip work queue
  * @name: debug name
- * @pending: number of queued but not committed items
- * @count: number of committed items
  * @func: callback fxn called for each committed item
  * @worker: worker which calls @func
- * @fifo: queue of committed items
+ * @queued: queued tasks
+ * @commited: commited tasks
+ * @lock: lock to access queued and commited lists
  */
 struct drm_flip_work {
 	const char *name;
-	atomic_t pending, count;
 	drm_flip_func_t func;
 	struct work_struct worker;
-	DECLARE_KFIFO_PTR(fifo, void *);
+	struct list_head queued;
+	struct list_head commited;
+	spinlock_t lock;
 };
 
+struct drm_flip_task *drm_flip_work_allocate_task(void *data);
+void drm_flip_work_queue_task(struct drm_flip_work *work,
+			      struct drm_flip_task *task);
 void drm_flip_work_queue(struct drm_flip_work *work, void *val);
 void drm_flip_work_commit(struct drm_flip_work *work,
 		struct workqueue_struct *wq);
-- 
1.8.3.2

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

* Re: [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full
  2014-07-11 15:17         ` [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full Boris BREZILLON
@ 2014-07-11 15:41           ` Rob Clark
  2014-07-11 15:47             ` Boris BREZILLON
  0 siblings, 1 reply; 149+ messages in thread
From: Rob Clark @ 2014-07-11 15:41 UTC (permalink / raw)
  To: Boris BREZILLON; +Cc: dri-devel

On Fri, Jul 11, 2014 at 11:17 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> Make use of lists instead of kfifo in order to dynamically allocate
> task entry when someone require some delayed work, and thus preventing
> drm_flip_work_queue from directly calling func instead of queuing this
> call.
> This allow drm_flip_work_queue to be safely called even within irq
> handlers.
>
> Add new helper functions to allocate a flip work task and queue it when
> needed. This prevents allocating data within irq context (which might
> impact the time spent in the irq handler).
>
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
> Hi Rob,
>
> This is a proposal for what you suggested (dynamically growing the drm
> flip work queue in order to avoid direct call of work->func when calling
> drm_flip_work_queue).
>
> I'm not sure this is exactly what you expected, because I'm now using
> lists instead of kfifo (and thus lose the lockless part), but at least
> we can now safely call drm_flip_work_queue or drm_flip_work_queue_task
> from irq handlers :-).
>
> You were also worried about queueing the same framebuffer multiple times
> and with this implementation you shouldn't have any problem (at least with
> drm_flip_work_queue, what people do with drm_flip_work_queue_task is their
> own responsability, but they should allocate one task for each operation
> even if they are manipulating the same framebuffer).

yeah, if we are dynamically allocating the list nodes, that solves the
queuing-up-multiple-times issue..

I wonder if drm_flip_work_allocate_task() should use GPF_ATOMIC when
allocating?  I guess maybe it is possible to pre-allocate the task
from non-irq context, and then queue it from irq context.. it makes
the API a bit more complex, but there are only a couple users
currently, so I suppose this should be doable.

BR,
-R

> This is just a suggestion, so don't hesitate to tell me that it doesn't
> match your expectations.
>
> Best Regards,
>
> Boris
>
>  drivers/gpu/drm/drm_flip_work.c | 95 ++++++++++++++++++++++++++++++-----------
>  include/drm/drm_flip_work.h     | 29 +++++++++----
>  2 files changed, 92 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c
> index f9c7fa3..21d5715 100644
> --- a/drivers/gpu/drm/drm_flip_work.c
> +++ b/drivers/gpu/drm/drm_flip_work.c
> @@ -25,6 +25,43 @@
>  #include "drm_flip_work.h"
>
>  /**
> + * drm_flip_work_allocate_task - allocate a flip-work task
> + * @data: data associated to the task
> + *
> + * Allocate a drm_flip_task object and attach private data to it.
> + */
> +struct drm_flip_task *drm_flip_work_allocate_task(void *data)
> +{
> +       struct drm_flip_task *task;
> +
> +       task = kzalloc(sizeof(*task), GFP_KERNEL);
> +       if (task)
> +               task->data = data;
> +
> +       return task;
> +}
> +EXPORT_SYMBOL(drm_flip_work_allocate_task);
> +
> +/**
> + * drm_flip_work_queue_task - queue a specific task
> + * @work: the flip-work
> + * @task: the task to handle
> + *
> + * Queues task, that will later be run (passed back to drm_flip_func_t
> + * func) on a work queue after drm_flip_work_commit() is called.
> + */
> +void drm_flip_work_queue_task(struct drm_flip_work *work,
> +                             struct drm_flip_task *task)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&work->lock, flags);
> +       list_add_tail(&task->node, &work->queued);
> +       spin_unlock_irqrestore(&work->lock, flags);
> +}
> +EXPORT_SYMBOL(drm_flip_work_queue_task);
> +
> +/**
>   * drm_flip_work_queue - queue work
>   * @work: the flip-work
>   * @val: the value to queue
> @@ -34,10 +71,14 @@
>   */
>  void drm_flip_work_queue(struct drm_flip_work *work, void *val)
>  {
> -       if (kfifo_put(&work->fifo, val)) {
> -               atomic_inc(&work->pending);
> +       struct drm_flip_task *task;
> +
> +       task = kzalloc(sizeof(*task), GFP_KERNEL);
> +       if (task) {
> +               task->data = val;
> +               drm_flip_work_queue_task(work, task);
>         } else {
> -               DRM_ERROR("%s fifo full!\n", work->name);
> +               DRM_ERROR("%s could not allocate task!\n", work->name);
>                 work->func(work, val);
>         }
>  }
> @@ -56,9 +97,12 @@ EXPORT_SYMBOL(drm_flip_work_queue);
>  void drm_flip_work_commit(struct drm_flip_work *work,
>                 struct workqueue_struct *wq)
>  {
> -       uint32_t pending = atomic_read(&work->pending);
> -       atomic_add(pending, &work->count);
> -       atomic_sub(pending, &work->pending);
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&work->lock, flags);
> +       list_splice_tail(&work->queued, &work->commited);
> +       INIT_LIST_HEAD(&work->queued);
> +       spin_unlock_irqrestore(&work->lock, flags);
>         queue_work(wq, &work->worker);
>  }
>  EXPORT_SYMBOL(drm_flip_work_commit);
> @@ -66,14 +110,26 @@ EXPORT_SYMBOL(drm_flip_work_commit);
>  static void flip_worker(struct work_struct *w)
>  {
>         struct drm_flip_work *work = container_of(w, struct drm_flip_work, worker);
> -       uint32_t count = atomic_read(&work->count);
> -       void *val = NULL;
> +       struct list_head tasks;
> +       unsigned long flags;
>
> -       atomic_sub(count, &work->count);
> +       while (1) {
> +               struct drm_flip_task *task, *tmp;
>
> -       while(count--)
> -               if (!WARN_ON(!kfifo_get(&work->fifo, &val)))
> -                       work->func(work, val);
> +               INIT_LIST_HEAD(&tasks);
> +               spin_lock_irqsave(&work->lock, flags);
> +               list_splice_tail(&work->commited, &tasks);
> +               INIT_LIST_HEAD(&work->commited);
> +               spin_unlock_irqrestore(&work->lock, flags);
> +
> +               if (list_empty(&tasks))
> +                       break;
> +
> +               list_for_each_entry_safe(task, tmp, &tasks, node) {
> +                       work->func(work, task->data);
> +                       kfree(task);
> +               }
> +       }
>  }
>
>  /**
> @@ -91,19 +147,11 @@ static void flip_worker(struct work_struct *w)
>  int drm_flip_work_init(struct drm_flip_work *work, int size,
>                 const char *name, drm_flip_func_t func)
>  {
> -       int ret;
> -
>         work->name = name;
> -       atomic_set(&work->count, 0);
> -       atomic_set(&work->pending, 0);
> +       INIT_LIST_HEAD(&work->queued);
> +       INIT_LIST_HEAD(&work->commited);
>         work->func = func;
>
> -       ret = kfifo_alloc(&work->fifo, size, GFP_KERNEL);
> -       if (ret) {
> -               DRM_ERROR("could not allocate %s fifo\n", name);
> -               return ret;
> -       }
> -
>         INIT_WORK(&work->worker, flip_worker);
>
>         return 0;
> @@ -118,7 +166,6 @@ EXPORT_SYMBOL(drm_flip_work_init);
>   */
>  void drm_flip_work_cleanup(struct drm_flip_work *work)
>  {
> -       WARN_ON(!kfifo_is_empty(&work->fifo));
> -       kfifo_free(&work->fifo);
> +       WARN_ON(!list_empty(&work->queued) || !list_empty(&work->commited));
>  }
>  EXPORT_SYMBOL(drm_flip_work_cleanup);
> diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h
> index 9eed34d..549981f 100644
> --- a/include/drm/drm_flip_work.h
> +++ b/include/drm/drm_flip_work.h
> @@ -25,6 +25,7 @@
>  #define DRM_FLIP_WORK_H
>
>  #include <linux/kfifo.h>
> +#include <linux/spinlock.h>
>  #include <linux/workqueue.h>
>
>  /**
> @@ -32,9 +33,7 @@
>   *
>   * Util to queue up work to run from work-queue context after flip/vblank.
>   * Typically this can be used to defer unref of framebuffer's, cursor
> - * bo's, etc until after vblank.  The APIs are all safe (and lockless)
> - * for up to one producer and once consumer at a time.  The single-consumer
> - * aspect is ensured by committing the queued work to a single work-queue.
> + * bo's, etc until after vblank.  The APIs are all safe.
>   */
>
>  struct drm_flip_work;
> @@ -51,22 +50,36 @@ struct drm_flip_work;
>  typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val);
>
>  /**
> + * struct drm_flip_task - flip work task
> + * @node: list entry element
> + * @data: data to pass to work->func
> + */
> +struct drm_flip_task {
> +       struct list_head node;
> +       void *data;
> +};
> +
> +/**
>   * struct drm_flip_work - flip work queue
>   * @name: debug name
> - * @pending: number of queued but not committed items
> - * @count: number of committed items
>   * @func: callback fxn called for each committed item
>   * @worker: worker which calls @func
> - * @fifo: queue of committed items
> + * @queued: queued tasks
> + * @commited: commited tasks
> + * @lock: lock to access queued and commited lists
>   */
>  struct drm_flip_work {
>         const char *name;
> -       atomic_t pending, count;
>         drm_flip_func_t func;
>         struct work_struct worker;
> -       DECLARE_KFIFO_PTR(fifo, void *);
> +       struct list_head queued;
> +       struct list_head commited;
> +       spinlock_t lock;
>  };
>
> +struct drm_flip_task *drm_flip_work_allocate_task(void *data);
> +void drm_flip_work_queue_task(struct drm_flip_work *work,
> +                             struct drm_flip_task *task);
>  void drm_flip_work_queue(struct drm_flip_work *work, void *val);
>  void drm_flip_work_commit(struct drm_flip_work *work,
>                 struct workqueue_struct *wq);
> --
> 1.8.3.2
>

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

* Re: [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full
  2014-07-11 15:41           ` Rob Clark
@ 2014-07-11 15:47             ` Boris BREZILLON
  2014-07-11 15:57               ` Boris BREZILLON
  2014-07-11 16:05               ` Rob Clark
  0 siblings, 2 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 15:47 UTC (permalink / raw)
  To: Rob Clark; +Cc: dri-devel

On Fri, 11 Jul 2014 11:41:12 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Fri, Jul 11, 2014 at 11:17 AM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > Make use of lists instead of kfifo in order to dynamically allocate
> > task entry when someone require some delayed work, and thus preventing
> > drm_flip_work_queue from directly calling func instead of queuing this
> > call.
> > This allow drm_flip_work_queue to be safely called even within irq
> > handlers.
> >
> > Add new helper functions to allocate a flip work task and queue it when
> > needed. This prevents allocating data within irq context (which might
> > impact the time spent in the irq handler).
> >
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> > Hi Rob,
> >
> > This is a proposal for what you suggested (dynamically growing the drm
> > flip work queue in order to avoid direct call of work->func when calling
> > drm_flip_work_queue).
> >
> > I'm not sure this is exactly what you expected, because I'm now using
> > lists instead of kfifo (and thus lose the lockless part), but at least
> > we can now safely call drm_flip_work_queue or drm_flip_work_queue_task
> > from irq handlers :-).
> >
> > You were also worried about queueing the same framebuffer multiple times
> > and with this implementation you shouldn't have any problem (at least with
> > drm_flip_work_queue, what people do with drm_flip_work_queue_task is their
> > own responsability, but they should allocate one task for each operation
> > even if they are manipulating the same framebuffer).
> 
> yeah, if we are dynamically allocating the list nodes, that solves the
> queuing-up-multiple-times issue..
> 
> I wonder if drm_flip_work_allocate_task() should use GPF_ATOMIC when
> allocating?

That's funny, I was actually modifying the API to pass gfp_t flags to
this function ;-)

> I guess maybe it is possible to pre-allocate the task
> from non-irq context, and then queue it from irq context.. it makes
> the API a bit more complex, but there are only a couple users
> currently, so I suppose this should be doable.

I tried to keep the existing API so that existing users won't see the
difference (I guess none of them are calling drm_flip_work_queue).

I just added the drm_flip_work_allocate_task and
drm_flip_work_queue_task for those who want more control on the
queuing process.

Best Regards,

Boris





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

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

* Re: [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full
  2014-07-11 15:47             ` Boris BREZILLON
@ 2014-07-11 15:57               ` Boris BREZILLON
  2014-07-11 16:05               ` Rob Clark
  1 sibling, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-11 15:57 UTC (permalink / raw)
  To: Boris BREZILLON; +Cc: dri-devel

On Fri, 11 Jul 2014 17:47:05 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> On Fri, 11 Jul 2014 11:41:12 -0400
> Rob Clark <robdclark@gmail.com> wrote:
> 
> > On Fri, Jul 11, 2014 at 11:17 AM, Boris BREZILLON
> > <boris.brezillon@free-electrons.com> wrote:
> > > Make use of lists instead of kfifo in order to dynamically allocate
> > > task entry when someone require some delayed work, and thus preventing
> > > drm_flip_work_queue from directly calling func instead of queuing this
> > > call.
> > > This allow drm_flip_work_queue to be safely called even within irq
> > > handlers.
> > >
> > > Add new helper functions to allocate a flip work task and queue it when
> > > needed. This prevents allocating data within irq context (which might
> > > impact the time spent in the irq handler).
> > >
> > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > ---
> > > Hi Rob,
> > >
> > > This is a proposal for what you suggested (dynamically growing the drm
> > > flip work queue in order to avoid direct call of work->func when calling
> > > drm_flip_work_queue).
> > >
> > > I'm not sure this is exactly what you expected, because I'm now using
> > > lists instead of kfifo (and thus lose the lockless part), but at least
> > > we can now safely call drm_flip_work_queue or drm_flip_work_queue_task
> > > from irq handlers :-).
> > >
> > > You were also worried about queueing the same framebuffer multiple times
> > > and with this implementation you shouldn't have any problem (at least with
> > > drm_flip_work_queue, what people do with drm_flip_work_queue_task is their
> > > own responsability, but they should allocate one task for each operation
> > > even if they are manipulating the same framebuffer).
> > 
> > yeah, if we are dynamically allocating the list nodes, that solves the
> > queuing-up-multiple-times issue..
> > 
> > I wonder if drm_flip_work_allocate_task() should use GPF_ATOMIC when
> > allocating?
> 
> That's funny, I was actually modifying the API to pass gfp_t flags to
> this function ;-)
> 
> > I guess maybe it is possible to pre-allocate the task
> > from non-irq context, and then queue it from irq context.. it makes
> > the API a bit more complex, but there are only a couple users
> > currently, so I suppose this should be doable.
> 
> I tried to keep the existing API so that existing users won't see the
> difference (I guess none of them are calling drm_flip_work_queue).

Some words are missing :-):

(I guess none of them are calling drm_flip_work_queue from irq
handlers).

> 
> I just added the drm_flip_work_allocate_task and
> drm_flip_work_queue_task for those who want more control on the
> queuing process.
> 
> Best Regards,
> 
> Boris
> 
> 
> 
> 
> 



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

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

* Re: [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full
  2014-07-11 15:47             ` Boris BREZILLON
  2014-07-11 15:57               ` Boris BREZILLON
@ 2014-07-11 16:05               ` Rob Clark
  1 sibling, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-11 16:05 UTC (permalink / raw)
  To: Boris BREZILLON; +Cc: dri-devel

On Fri, Jul 11, 2014 at 11:47 AM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> On Fri, 11 Jul 2014 11:41:12 -0400
> Rob Clark <robdclark@gmail.com> wrote:
>
>> On Fri, Jul 11, 2014 at 11:17 AM, Boris BREZILLON
>> <boris.brezillon@free-electrons.com> wrote:
>> > Make use of lists instead of kfifo in order to dynamically allocate
>> > task entry when someone require some delayed work, and thus preventing
>> > drm_flip_work_queue from directly calling func instead of queuing this
>> > call.
>> > This allow drm_flip_work_queue to be safely called even within irq
>> > handlers.
>> >
>> > Add new helper functions to allocate a flip work task and queue it when
>> > needed. This prevents allocating data within irq context (which might
>> > impact the time spent in the irq handler).
>> >
>> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
>> > ---
>> > Hi Rob,
>> >
>> > This is a proposal for what you suggested (dynamically growing the drm
>> > flip work queue in order to avoid direct call of work->func when calling
>> > drm_flip_work_queue).
>> >
>> > I'm not sure this is exactly what you expected, because I'm now using
>> > lists instead of kfifo (and thus lose the lockless part), but at least
>> > we can now safely call drm_flip_work_queue or drm_flip_work_queue_task
>> > from irq handlers :-).
>> >
>> > You were also worried about queueing the same framebuffer multiple times
>> > and with this implementation you shouldn't have any problem (at least with
>> > drm_flip_work_queue, what people do with drm_flip_work_queue_task is their
>> > own responsability, but they should allocate one task for each operation
>> > even if they are manipulating the same framebuffer).
>>
>> yeah, if we are dynamically allocating the list nodes, that solves the
>> queuing-up-multiple-times issue..
>>
>> I wonder if drm_flip_work_allocate_task() should use GPF_ATOMIC when
>> allocating?
>
> That's funny, I was actually modifying the API to pass gfp_t flags to
> this function ;-)

yeah, I think passing gfp flags is the better idea

>> I guess maybe it is possible to pre-allocate the task
>> from non-irq context, and then queue it from irq context.. it makes
>> the API a bit more complex, but there are only a couple users
>> currently, so I suppose this should be doable.
>
> I tried to keep the existing API so that existing users won't see the
> difference (I guess none of them are calling drm_flip_work_queue).

we do have existing users that call drm_flip_work_queue() from irq..
but I suppose adding gfp flags arg to drm_flip_work_queue() seems like
a reasonable solution.

BR,
-R

> I just added the drm_flip_work_allocate_task and
> drm_flip_work_queue_task for those who want more control on the
> queuing process.
>
> Best Regards,
>
> Boris
>
>
>
>
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-07 16:42   ` Boris BREZILLON
@ 2014-07-12 18:16     ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-12 18:16 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

Hello,

On Mon,  7 Jul 2014 18:42:58 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:


> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> +{
> +	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +	unsigned long flags;
> +	int i;
> +
> +	spin_lock_irqsave(&dma->lock, flags);
> +	for (i = 0; i < layer->max_planes; i++) {
> +		if (!dma->cur[i])
> +			break;
> +
> +		dma->cur[i]->ctrl = 0;
> +	}
> +	spin_unlock_irqrestore(&dma->lock, flags);
> +
> +	return 0;
> +}


I'm trying to simplify the hlcdc_layer code and in order to do that I
need to know what's expected when a user calls plane_disable (or more
exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
to 0).

The HLCDC Display Controller support two types of disable:

1) The plane is disabled at the end of the current frame (the is the
solution I'm using)

2) The plane is disabled right away (I haven't tested it, but I think
this solution could generate some sort of artifacts for a short period
of time, because the framebuffer might be partially displayed)

If solution 1 is chosen, should I wait for the plane to be actually
disabled before returning ?
A the moment, I'm not: I'm just asking for the plane to be disabled and
then return. And this is where some of my complicated code come from,
because I must handle the case where a user disable the plane then re
enable it right away (modetest cursor test is doing a lot of cursor
enable/disable in a short period of time, and this is how I tested all
this weird use cases).

Best Regards,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-12 18:16     ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-12 18:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Mon,  7 Jul 2014 18:42:58 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:


> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> +{
> +	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> +	unsigned long flags;
> +	int i;
> +
> +	spin_lock_irqsave(&dma->lock, flags);
> +	for (i = 0; i < layer->max_planes; i++) {
> +		if (!dma->cur[i])
> +			break;
> +
> +		dma->cur[i]->ctrl = 0;
> +	}
> +	spin_unlock_irqrestore(&dma->lock, flags);
> +
> +	return 0;
> +}


I'm trying to simplify the hlcdc_layer code and in order to do that I
need to know what's expected when a user calls plane_disable (or more
exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
to 0).

The HLCDC Display Controller support two types of disable:

1) The plane is disabled at the end of the current frame (the is the
solution I'm using)

2) The plane is disabled right away (I haven't tested it, but I think
this solution could generate some sort of artifacts for a short period
of time, because the framebuffer might be partially displayed)

If solution 1 is chosen, should I wait for the plane to be actually
disabled before returning ?
A the moment, I'm not: I'm just asking for the plane to be disabled and
then return. And this is where some of my complicated code come from,
because I must handle the case where a user disable the plane then re
enable it right away (modetest cursor test is doing a lot of cursor
enable/disable in a short period of time, and this is how I tested all
this weird use cases).

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-12 18:16     ` Boris BREZILLON
@ 2014-07-12 18:37       ` Rob Clark
  -1 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-12 18:37 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Jean-Jacques Hiblot, Samuel Ortiz,
	Pawel Moll, linux-pwm, Jean-Christophe Plagniol-Villard,
	Ian Campbell, Nicolas Ferre, dri-devel, Tim Niemeyer,
	Thomas Petazzoni, Rob Herring, Alexandre Belloni,
	Laurent Pinchart, Bo Shen, Kumar Gala, Lee Jones, Andrew Victor

On Sat, Jul 12, 2014 at 2:16 PM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> Hello,
>
> On Mon,  7 Jul 2014 18:42:58 +0200
> Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:
>
>
>> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
>> +{
>> +     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
>> +     unsigned long flags;
>> +     int i;
>> +
>> +     spin_lock_irqsave(&dma->lock, flags);
>> +     for (i = 0; i < layer->max_planes; i++) {
>> +             if (!dma->cur[i])
>> +                     break;
>> +
>> +             dma->cur[i]->ctrl = 0;
>> +     }
>> +     spin_unlock_irqrestore(&dma->lock, flags);
>> +
>> +     return 0;
>> +}
>
>
> I'm trying to simplify the hlcdc_layer code and in order to do that I
> need to know what's expected when a user calls plane_disable (or more
> exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
> to 0).
>
> The HLCDC Display Controller support two types of disable:
>
> 1) The plane is disabled at the end of the current frame (the is the
> solution I'm using)
>
> 2) The plane is disabled right away (I haven't tested it, but I think
> this solution could generate some sort of artifacts for a short period
> of time, because the framebuffer might be partially displayed)
>
> If solution 1 is chosen, should I wait for the plane to be actually
> disabled before returning ?

for cursor in particular, if you block, it is going to be a massive
slowdown for some apps.  I remember at least older gdm would rapidly
flash a spinning cursor.  As a result, if you wait for vsync each
time, it would take a couple minutes to login!

if #2 works, I'd recommend it.  Otherwise you may have to do some of
the same hijinks that I have to do in mdp4_crtc for the cursor.

BR,
-R

> A the moment, I'm not: I'm just asking for the plane to be disabled and
> then return. And this is where some of my complicated code come from,
> because I must handle the case where a user disable the plane then re
> enable it right away (modetest cursor test is doing a lot of cursor
> enable/disable in a short period of time, and this is how I tested all
> this weird use cases).
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-12 18:37       ` Rob Clark
  0 siblings, 0 replies; 149+ messages in thread
From: Rob Clark @ 2014-07-12 18:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jul 12, 2014 at 2:16 PM, Boris BREZILLON
<boris.brezillon@free-electrons.com> wrote:
> Hello,
>
> On Mon,  7 Jul 2014 18:42:58 +0200
> Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:
>
>
>> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
>> +{
>> +     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
>> +     unsigned long flags;
>> +     int i;
>> +
>> +     spin_lock_irqsave(&dma->lock, flags);
>> +     for (i = 0; i < layer->max_planes; i++) {
>> +             if (!dma->cur[i])
>> +                     break;
>> +
>> +             dma->cur[i]->ctrl = 0;
>> +     }
>> +     spin_unlock_irqrestore(&dma->lock, flags);
>> +
>> +     return 0;
>> +}
>
>
> I'm trying to simplify the hlcdc_layer code and in order to do that I
> need to know what's expected when a user calls plane_disable (or more
> exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
> to 0).
>
> The HLCDC Display Controller support two types of disable:
>
> 1) The plane is disabled at the end of the current frame (the is the
> solution I'm using)
>
> 2) The plane is disabled right away (I haven't tested it, but I think
> this solution could generate some sort of artifacts for a short period
> of time, because the framebuffer might be partially displayed)
>
> If solution 1 is chosen, should I wait for the plane to be actually
> disabled before returning ?

for cursor in particular, if you block, it is going to be a massive
slowdown for some apps.  I remember at least older gdm would rapidly
flash a spinning cursor.  As a result, if you wait for vsync each
time, it would take a couple minutes to login!

if #2 works, I'd recommend it.  Otherwise you may have to do some of
the same hijinks that I have to do in mdp4_crtc for the cursor.

BR,
-R

> A the moment, I'm not: I'm just asking for the plane to be disabled and
> then return. And this is where some of my complicated code come from,
> because I must handle the case where a user disable the plane then re
> enable it right away (modetest cursor test is doing a lot of cursor
> enable/disable in a short period of time, and this is how I tested all
> this weird use cases).
>
> Best Regards,
>
> Boris
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-07 16:42   ` Boris BREZILLON
@ 2014-07-14 10:05     ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-14 10:05 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3449 bytes --]

On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> controller device.
> 
> The HLCDC block provides a single RGB output port, and only supports LCD
> panels connection to LCD panels for now.
> 
> The atmel,panel property link the HLCDC RGB output with the LCD panel
> connected on this port (note that the HLCDC RGB connector implementation
> makes use of the DRM panel framework).
> 
> Connection to other external devices (DRM bridges) might be added later by
> mean of a new atmel,xxx (atmel,bridge) property.
> 
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

This is the wrong directory. Device tree bindings describe hardware, but
DRM is a Linux-specific framework. And yes, there are already files in
that directory, I know, but that doesn't make it any better.

I suggest either devicetree/bindings/gpu or devicetree/bindings/video.

> diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
[...]
> +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.

I think it's better to refer to these using relative filenames. When the
device tree bindings are moved out of the kernel tree, they may no
longer use the same hierarchy.

> +Required properties:
> + - compatible: value should be one of the following:
> +   "atmel,hlcdc-dc"

There's only one value, so perhaps: should be "atmel,hlcdc-dc".

> + - atmel,panel: Should contain a phandle with 2 parameters.
> +   The first cell is a phandle to a DRM panel device
> +   The second cell encodes the RGB mode, which can take the following values:
> +   * 0: RGB444
> +   * 1: RGB565
> +   * 2: RGB666
> +   * 3: RGB888

These are properties of the panel and should be obtained from the panel
directly rather than an additional cell in this specifier.

> +   The third cell encodes specific flags describing LCD signals configuration
> +   (see Atmel's datasheet for a full description of these fields):
> +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> +   * bit 4: DISPPOL: Display Signal Polarity
> +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time

Similarly for most of these: HSPOL and VSPOL seem to correspond to the
DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
vsync_end of the same structure.

As for the others, maybe if you could explain what exactly they are we
may be able to find a better fit.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-14 10:05     ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-14 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> controller device.
> 
> The HLCDC block provides a single RGB output port, and only supports LCD
> panels connection to LCD panels for now.
> 
> The atmel,panel property link the HLCDC RGB output with the LCD panel
> connected on this port (note that the HLCDC RGB connector implementation
> makes use of the DRM panel framework).
> 
> Connection to other external devices (DRM bridges) might be added later by
> mean of a new atmel,xxx (atmel,bridge) property.
> 
> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> ---
>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

This is the wrong directory. Device tree bindings describe hardware, but
DRM is a Linux-specific framework. And yes, there are already files in
that directory, I know, but that doesn't make it any better.

I suggest either devicetree/bindings/gpu or devicetree/bindings/video.

> diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
[...]
> +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.

I think it's better to refer to these using relative filenames. When the
device tree bindings are moved out of the kernel tree, they may no
longer use the same hierarchy.

> +Required properties:
> + - compatible: value should be one of the following:
> +   "atmel,hlcdc-dc"

There's only one value, so perhaps: should be "atmel,hlcdc-dc".

> + - atmel,panel: Should contain a phandle with 2 parameters.
> +   The first cell is a phandle to a DRM panel device
> +   The second cell encodes the RGB mode, which can take the following values:
> +   * 0: RGB444
> +   * 1: RGB565
> +   * 2: RGB666
> +   * 3: RGB888

These are properties of the panel and should be obtained from the panel
directly rather than an additional cell in this specifier.

> +   The third cell encodes specific flags describing LCD signals configuration
> +   (see Atmel's datasheet for a full description of these fields):
> +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> +   * bit 4: DISPPOL: Display Signal Polarity
> +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time

Similarly for most of these: HSPOL and VSPOL seem to correspond to the
DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
vsync_end of the same structure.

As for the others, maybe if you could explain what exactly they are we
may be able to find a better fit.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140714/b4cf2773/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-11 12:00           ` Boris BREZILLON
@ 2014-07-14 10:18             ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-14 10:18 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 1278 bytes --]

On Fri, Jul 11, 2014 at 02:00:25PM +0200, Boris BREZILLON wrote:
> On Fri, 11 Jul 2014 12:37:46 +0200 Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
[...]
> > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > currently defining HLCDC connector as an LVDS connector) ?
> > 
> > Not that I know of. The DRM API has been developed before display on embedded 
> > systems became such a hot topic. If we had to redo it today, panels might be 
> > exposed to userspace as such, with a connector. We have to live with the past, 
> > so the connector will stay, but adding a new RGB connector type could make 
> > sense (although we might need a different name, in a way the VGA and LVDS 
> > connectors also carry RGB signals).
> 
> I had the same concern: I didn't find how this kind of connectors
> was named (most of the time they're just referenced as RGB) :-).
> What about RAW_RGB ?

Are there even panels that take raw RGB as input? In all cases I've seen
(which admittedly may not be all that many) there's always a transparent
RGB/LVDS bridge, so the "connector" is in fact LVDS, not RGB, even if
the display controller outputs RGB directly.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-14 10:18             ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-14 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 11, 2014 at 02:00:25PM +0200, Boris BREZILLON wrote:
> On Fri, 11 Jul 2014 12:37:46 +0200 Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
[...]
> > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > currently defining HLCDC connector as an LVDS connector) ?
> > 
> > Not that I know of. The DRM API has been developed before display on embedded 
> > systems became such a hot topic. If we had to redo it today, panels might be 
> > exposed to userspace as such, with a connector. We have to live with the past, 
> > so the connector will stay, but adding a new RGB connector type could make 
> > sense (although we might need a different name, in a way the VGA and LVDS 
> > connectors also carry RGB signals).
> 
> I had the same concern: I didn't find how this kind of connectors
> was named (most of the time they're just referenced as RGB) :-).
> What about RAW_RGB ?

Are there even panels that take raw RGB as input? In all cases I've seen
(which admittedly may not be all that many) there's always a transparent
RGB/LVDS bridge, so the "connector" is in fact LVDS, not RGB, even if
the display controller outputs RGB directly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140714/cadcc8c0/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-14 10:05     ` Thierry Reding
@ 2014-07-15 10:06       ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 10:06 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

Hello Thierry,

On Mon, 14 Jul 2014 12:05:43 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> > 
> > The HLCDC block provides a single RGB output port, and only supports LCD
> > panels connection to LCD panels for now.
> > 
> > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > connected on this port (note that the HLCDC RGB connector implementation
> > makes use of the DRM panel framework).
> > 
> > Connection to other external devices (DRM bridges) might be added later by
> > mean of a new atmel,xxx (atmel,bridge) property.
> > 
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> This is the wrong directory. Device tree bindings describe hardware, but
> DRM is a Linux-specific framework. And yes, there are already files in
> that directory, I know, but that doesn't make it any better.
> 
> I suggest either devicetree/bindings/gpu or devicetree/bindings/video.

No problem, I'll move the documentation into devicetree/bindings/video
(the HLCDC does not provide any 3D rendering functionality and thus
I'm not sure moving the bindings documentation into
devicetree/bindings/gpu makes sense).

> 
> > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> [...]
> > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> 
> I think it's better to refer to these using relative filenames. When the
> device tree bindings are moved out of the kernel tree, they may no
> longer use the same hierarchy.

Sure.
By relative path you mean ../../mfd/atmel-hlcdc.txt or just
mfd/atmel-hlcdc.txt ?

> 
> > +Required properties:
> > + - compatible: value should be one of the following:
> > +   "atmel,hlcdc-dc"
> 
> There's only one value, so perhaps: should be "atmel,hlcdc-dc".

Yes, I'll fix that.

> 
> > + - atmel,panel: Should contain a phandle with 2 parameters.
> > +   The first cell is a phandle to a DRM panel device
> > +   The second cell encodes the RGB mode, which can take the following values:
> > +   * 0: RGB444
> > +   * 1: RGB565
> > +   * 2: RGB666
> > +   * 3: RGB888
> 
> These are properties of the panel and should be obtained from the panel
> directly rather than an additional cell in this specifier.

Okay.
What's the preferred way of doing this ?
What about defining an rgb-mode property in the panel node.

BTW, have you received this series [1] adding support for the LCD panel
I'm testing this driver with.

[1] https://lkml.org/lkml/2014/6/5/612

> 
> > +   The third cell encodes specific flags describing LCD signals configuration
> > +   (see Atmel's datasheet for a full description of these fields):
> > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > +   * bit 4: DISPPOL: Display Signal Polarity
> > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> 
> Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> vsync_end of the same structure.

I agree with HSPOL and VSPOL.

> 
> As for the others, maybe if you could explain what exactly they are we
> may be able to find a better fit.

Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
Output Timing Generation" page 603), and I think you will get more
informations from these diagrams than if I try to explain what I
understood ;-).

Best Regards,

Boris

[1]https://lkml.org/lkml/2014/6/5/612
[2]http://www.atmel.com/Images/Atmel_11121_32-bit-Cortex-A5-Microcontroller_SAMA5D3_Datasheet.pdf

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:06       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 10:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Thierry,

On Mon, 14 Jul 2014 12:05:43 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > controller device.
> > 
> > The HLCDC block provides a single RGB output port, and only supports LCD
> > panels connection to LCD panels for now.
> > 
> > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > connected on this port (note that the HLCDC RGB connector implementation
> > makes use of the DRM panel framework).
> > 
> > Connection to other external devices (DRM bridges) might be added later by
> > mean of a new atmel,xxx (atmel,bridge) property.
> > 
> > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > ---
> >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++++++++++++++
> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> This is the wrong directory. Device tree bindings describe hardware, but
> DRM is a Linux-specific framework. And yes, there are already files in
> that directory, I know, but that doesn't make it any better.
> 
> I suggest either devicetree/bindings/gpu or devicetree/bindings/video.

No problem, I'll move the documentation into devicetree/bindings/video
(the HLCDC does not provide any 3D rendering functionality and thus
I'm not sure moving the bindings documentation into
devicetree/bindings/gpu makes sense).

> 
> > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> [...]
> > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> 
> I think it's better to refer to these using relative filenames. When the
> device tree bindings are moved out of the kernel tree, they may no
> longer use the same hierarchy.

Sure.
By relative path you mean ../../mfd/atmel-hlcdc.txt or just
mfd/atmel-hlcdc.txt ?

> 
> > +Required properties:
> > + - compatible: value should be one of the following:
> > +   "atmel,hlcdc-dc"
> 
> There's only one value, so perhaps: should be "atmel,hlcdc-dc".

Yes, I'll fix that.

> 
> > + - atmel,panel: Should contain a phandle with 2 parameters.
> > +   The first cell is a phandle to a DRM panel device
> > +   The second cell encodes the RGB mode, which can take the following values:
> > +   * 0: RGB444
> > +   * 1: RGB565
> > +   * 2: RGB666
> > +   * 3: RGB888
> 
> These are properties of the panel and should be obtained from the panel
> directly rather than an additional cell in this specifier.

Okay.
What's the preferred way of doing this ?
What about defining an rgb-mode property in the panel node.

BTW, have you received this series [1] adding support for the LCD panel
I'm testing this driver with.

[1] https://lkml.org/lkml/2014/6/5/612

> 
> > +   The third cell encodes specific flags describing LCD signals configuration
> > +   (see Atmel's datasheet for a full description of these fields):
> > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > +   * bit 4: DISPPOL: Display Signal Polarity
> > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> 
> Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> vsync_end of the same structure.

I agree with HSPOL and VSPOL.

> 
> As for the others, maybe if you could explain what exactly they are we
> may be able to find a better fit.

Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
Output Timing Generation" page 603), and I think you will get more
informations from these diagrams than if I try to explain what I
understood ;-).

Best Regards,

Boris

[1]https://lkml.org/lkml/2014/6/5/612
[2]http://www.atmel.com/Images/Atmel_11121_32-bit-Cortex-A5-Microcontroller_SAMA5D3_Datasheet.pdf

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:06       ` Boris BREZILLON
@ 2014-07-15 10:20         ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 10:20 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Boris,

On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > controller device.
> > > 
> > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > panels connection to LCD panels for now.
> > > 
> > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > connected on this port (note that the HLCDC RGB connector implementation
> > > makes use of the DRM panel framework).
> > > 
> > > Connection to other external devices (DRM bridges) might be added later
> > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > 
> > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > ---
> > > 
> > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > >  1 file changed, 59 insertions(+)
> > >  create mode 100644
> > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

[snip]

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following
> > > values: +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > 
> > These are properties of the panel and should be obtained from the panel
> > directly rather than an additional cell in this specifier.
> 
> Okay.
> What's the preferred way of doing this ?
> What about defining an rgb-mode property in the panel node.

You could do that, but it won't help you much, as the HLCDC driver must not 
parse properties from the panel node. You should instead extend the drm_panel 
API with a function to retrieve panel properties. The HLCDC driver will then 
query the panel driver at runtime for the interface type. The panel driver 
will get the information from hardcoded data in the driver, from DT or 
possibly in some cases by querying the panel hardware directly.

> BTW, have you received this series [1] adding support for the LCD panel
> I'm testing this driver with.
> 
> [1] https://lkml.org/lkml/2014/6/5/612
> 
> > > +   The third cell encodes specific flags describing LCD signals
> > > configuration
> > > +   (see Atmel's datasheet for a full description of these fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > vsync_end of the same structure.
> 
> I agree with HSPOL and VSPOL.
> 
> > As for the others, maybe if you could explain what exactly they are we
> > may be able to find a better fit.
> 
> Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> Output Timing Generation" page 603), and I think you will get more
> informations from these diagrams than if I try to explain what I
> understood ;-).

The VSP* bits fine-tune the VSYNC pulse generation timings by specifying the 
relationship between the VSYNC edges and the HSYNC pulses at the beginning and 
end of the VSYNC pulse. It might make sense to turn that into standard DRM 
properties, but we'll need to research if and how other vendor offer similar 
features.

As for GUARDTIME, I would split it into its own property. What are the typical 
values you have seen being used in read systems ?

-- 
Regards,

Laurent Pinchart

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:20         ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > controller device.
> > > 
> > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > panels connection to LCD panels for now.
> > > 
> > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > connected on this port (note that the HLCDC RGB connector implementation
> > > makes use of the DRM panel framework).
> > > 
> > > Connection to other external devices (DRM bridges) might be added later
> > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > 
> > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > ---
> > > 
> > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > >  1 file changed, 59 insertions(+)
> > >  create mode 100644
> > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt

[snip]

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following
> > > values: +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > 
> > These are properties of the panel and should be obtained from the panel
> > directly rather than an additional cell in this specifier.
> 
> Okay.
> What's the preferred way of doing this ?
> What about defining an rgb-mode property in the panel node.

You could do that, but it won't help you much, as the HLCDC driver must not 
parse properties from the panel node. You should instead extend the drm_panel 
API with a function to retrieve panel properties. The HLCDC driver will then 
query the panel driver at runtime for the interface type. The panel driver 
will get the information from hardcoded data in the driver, from DT or 
possibly in some cases by querying the panel hardware directly.

> BTW, have you received this series [1] adding support for the LCD panel
> I'm testing this driver with.
> 
> [1] https://lkml.org/lkml/2014/6/5/612
> 
> > > +   The third cell encodes specific flags describing LCD signals
> > > configuration
> > > +   (see Atmel's datasheet for a full description of these fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal
> > > Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup
> > > Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold
> > > Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > vsync_end of the same structure.
> 
> I agree with HSPOL and VSPOL.
> 
> > As for the others, maybe if you could explain what exactly they are we
> > may be able to find a better fit.
> 
> Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> Output Timing Generation" page 603), and I think you will get more
> informations from these diagrams than if I try to explain what I
> understood ;-).

The VSP* bits fine-tune the VSYNC pulse generation timings by specifying the 
relationship between the VSYNC edges and the HSYNC pulses at the beginning and 
end of the VSYNC pulse. It might make sense to turn that into standard DRM 
properties, but we'll need to research if and how other vendor offer similar 
features.

As for GUARDTIME, I would split it into its own property. What are the typical 
values you have seen being used in read systems ?

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:06       ` Boris BREZILLON
@ 2014-07-15 10:31         ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:31 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3850 bytes --]

On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
[...]
> > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > [...]
> > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > 
> > I think it's better to refer to these using relative filenames. When the
> > device tree bindings are moved out of the kernel tree, they may no
> > longer use the same hierarchy.
> 
> Sure.
> By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> mfd/atmel-hlcdc.txt ?

I think the former is more explicit.

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following values:
> > > +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > 
> > These are properties of the panel and should be obtained from the panel
> > directly rather than an additional cell in this specifier.
> 
> Okay.
> What's the preferred way of doing this ?
> What about defining an rgb-mode property in the panel node.

There's .bpc in struct drm_display_info, I suspect that it could be used
for this. Alternatively, maybe we could extend the list of color formats
that go into drm_display_info.color_formats? RGB444 is already covered.

Also, like Laurent said, this shouldn't go into the device tree, since
it's already implied by the panel's compatible value, so we'd be
duplicating information.

> BTW, have you received this series [1] adding support for the LCD panel
> I'm testing this driver with.
> 
> [1] https://lkml.org/lkml/2014/6/5/612

I don't think I've seen it in my inbox, let me check my archives.

> > > +   The third cell encodes specific flags describing LCD signals configuration
> > > +   (see Atmel's datasheet for a full description of these fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > vsync_end of the same structure.
> 
> I agree with HSPOL and VSPOL.
> 
> > 
> > As for the others, maybe if you could explain what exactly they are we
> > may be able to find a better fit.
> 
> Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> Output Timing Generation" page 603), and I think you will get more
> informations from these diagrams than if I try to explain what I
> understood ;-).

These look like knobs to tune the signal in a very fine-grained manner.
To be honest, maybe the best way to solve this would be by omitting them
for now and choose some default that's likely to work on most devices.
Does the panel that you use specify how it expects HSYNC to be timed vs.
VSYNC?

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:31         ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
[...]
> > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > [...]
> > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > 
> > I think it's better to refer to these using relative filenames. When the
> > device tree bindings are moved out of the kernel tree, they may no
> > longer use the same hierarchy.
> 
> Sure.
> By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> mfd/atmel-hlcdc.txt ?

I think the former is more explicit.

> > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > +   The first cell is a phandle to a DRM panel device
> > > +   The second cell encodes the RGB mode, which can take the following values:
> > > +   * 0: RGB444
> > > +   * 1: RGB565
> > > +   * 2: RGB666
> > > +   * 3: RGB888
> > 
> > These are properties of the panel and should be obtained from the panel
> > directly rather than an additional cell in this specifier.
> 
> Okay.
> What's the preferred way of doing this ?
> What about defining an rgb-mode property in the panel node.

There's .bpc in struct drm_display_info, I suspect that it could be used
for this. Alternatively, maybe we could extend the list of color formats
that go into drm_display_info.color_formats? RGB444 is already covered.

Also, like Laurent said, this shouldn't go into the device tree, since
it's already implied by the panel's compatible value, so we'd be
duplicating information.

> BTW, have you received this series [1] adding support for the LCD panel
> I'm testing this driver with.
> 
> [1] https://lkml.org/lkml/2014/6/5/612

I don't think I've seen it in my inbox, let me check my archives.

> > > +   The third cell encodes specific flags describing LCD signals configuration
> > > +   (see Atmel's datasheet for a full description of these fields):
> > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > 
> > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > vsync_end of the same structure.
> 
> I agree with HSPOL and VSPOL.
> 
> > 
> > As for the others, maybe if you could explain what exactly they are we
> > may be able to find a better fit.
> 
> Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> Output Timing Generation" page 603), and I think you will get more
> informations from these diagrams than if I try to explain what I
> understood ;-).

These look like knobs to tune the signal in a very fine-grained manner.
To be honest, maybe the best way to solve this would be by omitting them
for now and choose some default that's likely to work on most devices.
Does the panel that you use specify how it expects HSYNC to be timed vs.
VSYNC?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140715/91760266/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:20         ` Laurent Pinchart
@ 2014-07-15 10:37           ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Boris BREZILLON, Samuel Ortiz, Lee Jones, linux-pwm,
	David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer

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

On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> Hi Boris,
> 
> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > controller device.
> > > > 
> > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > panels connection to LCD panels for now.
> > > > 
> > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > makes use of the DRM panel framework).
> > > > 
> > > > Connection to other external devices (DRM bridges) might be added later
> > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > 
> > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > ---
> > > > 
> > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > >  1 file changed, 59 insertions(+)
> > > >  create mode 100644
> > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> [snip]
> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following
> > > > values: +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > 
> > > These are properties of the panel and should be obtained from the panel
> > > directly rather than an additional cell in this specifier.
> > 
> > Okay.
> > What's the preferred way of doing this ?
> > What about defining an rgb-mode property in the panel node.
> 
> You could do that, but it won't help you much, as the HLCDC driver must not 
> parse properties from the panel node. You should instead extend the drm_panel 
> API with a function to retrieve panel properties. The HLCDC driver will then 
> query the panel driver at runtime for the interface type. The panel driver 
> will get the information from hardcoded data in the driver, from DT or 
> possibly in some cases by querying the panel hardware directly.

My preference for this would be that we either add this to some existing
structure (struct drm_display_info seems like a good candidate) or if
the number of parameters grows out of hands, then maybe even introduce a
new type of device that's specific for the interface. DRM panels are an
abstraction for panels, that is, interface-agnostic, and if we start
exposing interface specific parameters things will start to become very
unwieldy.

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:37           ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> Hi Boris,
> 
> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > > The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs (i.e.
> > > > at91sam9n12, at91sam9x5 family or sama5d3 family) provides a display
> > > > controller device.
> > > > 
> > > > The HLCDC block provides a single RGB output port, and only supports LCD
> > > > panels connection to LCD panels for now.
> > > > 
> > > > The atmel,panel property link the HLCDC RGB output with the LCD panel
> > > > connected on this port (note that the HLCDC RGB connector implementation
> > > > makes use of the DRM panel framework).
> > > > 
> > > > Connection to other external devices (DRM bridges) might be added later
> > > > by mean of a new atmel,xxx (atmel,bridge) property.
> > > > 
> > > > Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > > ---
> > > > 
> > > >  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++++++
> > > >  1 file changed, 59 insertions(+)
> > > >  create mode 100644
> > > >  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> 
> [snip]
> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following
> > > > values: +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > 
> > > These are properties of the panel and should be obtained from the panel
> > > directly rather than an additional cell in this specifier.
> > 
> > Okay.
> > What's the preferred way of doing this ?
> > What about defining an rgb-mode property in the panel node.
> 
> You could do that, but it won't help you much, as the HLCDC driver must not 
> parse properties from the panel node. You should instead extend the drm_panel 
> API with a function to retrieve panel properties. The HLCDC driver will then 
> query the panel driver at runtime for the interface type. The panel driver 
> will get the information from hardcoded data in the driver, from DT or 
> possibly in some cases by querying the panel hardware directly.

My preference for this would be that we either add this to some existing
structure (struct drm_display_info seems like a good candidate) or if
the number of parameters grows out of hands, then maybe even introduce a
new type of device that's specific for the interface. DRM panels are an
abstraction for panels, that is, interface-agnostic, and if we start
exposing interface specific parameters things will start to become very
unwieldy.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140715/4a4ecd4a/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:37           ` Thierry Reding
@ 2014-07-15 10:43             ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 10:43 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3733 bytes --]

Hi Thierry,

On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> >>>> display controller device.
> >>>> 
> >>>> The HLCDC block provides a single RGB output port, and only supports
> >>>> LCD panels connection to LCD panels for now.
> >>>> 
> >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>> panel connected on this port (note that the HLCDC RGB connector
> >>>> implementation makes use of the DRM panel framework).
> >>>> 
> >>>> Connection to other external devices (DRM bridges) might be added
> >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>> 
> >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >>>> ---
> >>>> 
> >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> >>>>  1 file changed, 59 insertions(+)
> >>>>  create mode 100644
> >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > 
> > [snip]
> > 
> >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>> +   The first cell is a phandle to a DRM panel device
> >>>> +   The second cell encodes the RGB mode, which can take the
> >>>> following values:
> >>>> +   * 0: RGB444
> >>>> +   * 1: RGB565
> >>>> +   * 2: RGB666
> >>>> +   * 3: RGB888
> >>> 
> >>> These are properties of the panel and should be obtained from the
> >>> panel directly rather than an additional cell in this specifier.
> >> 
> >> Okay.
> >> What's the preferred way of doing this ?
> >> What about defining an rgb-mode property in the panel node.
> > 
> > You could do that, but it won't help you much, as the HLCDC driver must
> > not parse properties from the panel node. You should instead extend the
> > drm_panel API with a function to retrieve panel properties. The HLCDC
> > driver will then query the panel driver at runtime for the interface
> > type. The panel driver will get the information from hardcoded data in
> > the driver, from DT or possibly in some cases by querying the panel
> > hardware directly.
> 
> My preference for this would be that we either add this to some existing
> structure (struct drm_display_info seems like a good candidate) or if
> the number of parameters grows out of hands, then maybe even introduce a
> new type of device that's specific for the interface. DRM panels are an
> abstraction for panels, that is, interface-agnostic, and if we start
> exposing interface specific parameters things will start to become very
> unwieldy.

I agree with the goal of keeping drm_panel interface-agnostic. However, one 
way or another, interface parameters will need to be communicated between the 
panel driver and the controller driver. My preference, if we need to extend 
the number and/or scope of parameters beyond what drm_display_info could 
reasonably contain, would be to implement a new drm_panel operation to 
query/configure interface parameters, using a structure that contains the 
interface type and a union of type-specific structures. This would keep the 
API generic in the sense of not requiring explicit knowledge of all interfaces 
in the drivers, while offering the flexibility we need with a way to easily 
detect the interface type at runtime and react on unknown/unsupported types.

-- 
Regards,

Laurent Pinchart

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:43             ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 10:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> >>>> display controller device.
> >>>> 
> >>>> The HLCDC block provides a single RGB output port, and only supports
> >>>> LCD panels connection to LCD panels for now.
> >>>> 
> >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>> panel connected on this port (note that the HLCDC RGB connector
> >>>> implementation makes use of the DRM panel framework).
> >>>> 
> >>>> Connection to other external devices (DRM bridges) might be added
> >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>> 
> >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >>>> ---
> >>>> 
> >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> >>>>  1 file changed, 59 insertions(+)
> >>>>  create mode 100644
> >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > 
> > [snip]
> > 
> >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>> +   The first cell is a phandle to a DRM panel device
> >>>> +   The second cell encodes the RGB mode, which can take the
> >>>> following values:
> >>>> +   * 0: RGB444
> >>>> +   * 1: RGB565
> >>>> +   * 2: RGB666
> >>>> +   * 3: RGB888
> >>> 
> >>> These are properties of the panel and should be obtained from the
> >>> panel directly rather than an additional cell in this specifier.
> >> 
> >> Okay.
> >> What's the preferred way of doing this ?
> >> What about defining an rgb-mode property in the panel node.
> > 
> > You could do that, but it won't help you much, as the HLCDC driver must
> > not parse properties from the panel node. You should instead extend the
> > drm_panel API with a function to retrieve panel properties. The HLCDC
> > driver will then query the panel driver at runtime for the interface
> > type. The panel driver will get the information from hardcoded data in
> > the driver, from DT or possibly in some cases by querying the panel
> > hardware directly.
> 
> My preference for this would be that we either add this to some existing
> structure (struct drm_display_info seems like a good candidate) or if
> the number of parameters grows out of hands, then maybe even introduce a
> new type of device that's specific for the interface. DRM panels are an
> abstraction for panels, that is, interface-agnostic, and if we start
> exposing interface specific parameters things will start to become very
> unwieldy.

I agree with the goal of keeping drm_panel interface-agnostic. However, one 
way or another, interface parameters will need to be communicated between the 
panel driver and the controller driver. My preference, if we need to extend 
the number and/or scope of parameters beyond what drm_display_info could 
reasonably contain, would be to implement a new drm_panel operation to 
query/configure interface parameters, using a structure that contains the 
interface type and a union of type-specific structures. This would keep the 
API generic in the sense of not requiring explicit knowledge of all interfaces 
in the drivers, while offering the flexibility we need with a way to easily 
detect the interface type at runtime and react on unknown/unsupported types.

-- 
Regards,

Laurent Pinchart
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140715/d4d38661/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:43             ` Laurent Pinchart
@ 2014-07-15 10:52               ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:52 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Boris BREZILLON, Samuel Ortiz, Lee Jones, linux-pwm,
	David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer

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

On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > >>>> display controller device.
> > >>>> 
> > >>>> The HLCDC block provides a single RGB output port, and only supports
> > >>>> LCD panels connection to LCD panels for now.
> > >>>> 
> > >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>> implementation makes use of the DRM panel framework).
> > >>>> 
> > >>>> Connection to other external devices (DRM bridges) might be added
> > >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>> 
> > >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > >>>> ---
> > >>>> 
> > >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> > >>>>  1 file changed, 59 insertions(+)
> > >>>>  create mode 100644
> > >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > 
> > > [snip]
> > > 
> > >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>> +   The first cell is a phandle to a DRM panel device
> > >>>> +   The second cell encodes the RGB mode, which can take the
> > >>>> following values:
> > >>>> +   * 0: RGB444
> > >>>> +   * 1: RGB565
> > >>>> +   * 2: RGB666
> > >>>> +   * 3: RGB888
> > >>> 
> > >>> These are properties of the panel and should be obtained from the
> > >>> panel directly rather than an additional cell in this specifier.
> > >> 
> > >> Okay.
> > >> What's the preferred way of doing this ?
> > >> What about defining an rgb-mode property in the panel node.
> > > 
> > > You could do that, but it won't help you much, as the HLCDC driver must
> > > not parse properties from the panel node. You should instead extend the
> > > drm_panel API with a function to retrieve panel properties. The HLCDC
> > > driver will then query the panel driver at runtime for the interface
> > > type. The panel driver will get the information from hardcoded data in
> > > the driver, from DT or possibly in some cases by querying the panel
> > > hardware directly.
> > 
> > My preference for this would be that we either add this to some existing
> > structure (struct drm_display_info seems like a good candidate) or if
> > the number of parameters grows out of hands, then maybe even introduce a
> > new type of device that's specific for the interface. DRM panels are an
> > abstraction for panels, that is, interface-agnostic, and if we start
> > exposing interface specific parameters things will start to become very
> > unwieldy.
> 
> I agree with the goal of keeping drm_panel interface-agnostic. However, one 
> way or another, interface parameters will need to be communicated between the 
> panel driver and the controller driver. My preference, if we need to extend 
> the number and/or scope of parameters beyond what drm_display_info could 
> reasonably contain, would be to implement a new drm_panel operation to 
> query/configure interface parameters, using a structure that contains the 
> interface type and a union of type-specific structures. This would keep the 
> API generic in the sense of not requiring explicit knowledge of all interfaces 
> in the drivers, while offering the flexibility we need with a way to easily 
> detect the interface type at runtime and react on unknown/unsupported types.

That's exactly what I was hoping could be avoided. If instead we modeled
the interface type as a bus, we could for example have an lvds_bus along
with an lvds_device and then use that as the natural place to store
these properties. Much like we do for DSI.

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 10:52               ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-15 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > >>>> display controller device.
> > >>>> 
> > >>>> The HLCDC block provides a single RGB output port, and only supports
> > >>>> LCD panels connection to LCD panels for now.
> > >>>> 
> > >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>> implementation makes use of the DRM panel framework).
> > >>>> 
> > >>>> Connection to other external devices (DRM bridges) might be added
> > >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>> 
> > >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > >>>> ---
> > >>>> 
> > >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> > >>>>  1 file changed, 59 insertions(+)
> > >>>>  create mode 100644
> > >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > 
> > > [snip]
> > > 
> > >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>> +   The first cell is a phandle to a DRM panel device
> > >>>> +   The second cell encodes the RGB mode, which can take the
> > >>>> following values:
> > >>>> +   * 0: RGB444
> > >>>> +   * 1: RGB565
> > >>>> +   * 2: RGB666
> > >>>> +   * 3: RGB888
> > >>> 
> > >>> These are properties of the panel and should be obtained from the
> > >>> panel directly rather than an additional cell in this specifier.
> > >> 
> > >> Okay.
> > >> What's the preferred way of doing this ?
> > >> What about defining an rgb-mode property in the panel node.
> > > 
> > > You could do that, but it won't help you much, as the HLCDC driver must
> > > not parse properties from the panel node. You should instead extend the
> > > drm_panel API with a function to retrieve panel properties. The HLCDC
> > > driver will then query the panel driver at runtime for the interface
> > > type. The panel driver will get the information from hardcoded data in
> > > the driver, from DT or possibly in some cases by querying the panel
> > > hardware directly.
> > 
> > My preference for this would be that we either add this to some existing
> > structure (struct drm_display_info seems like a good candidate) or if
> > the number of parameters grows out of hands, then maybe even introduce a
> > new type of device that's specific for the interface. DRM panels are an
> > abstraction for panels, that is, interface-agnostic, and if we start
> > exposing interface specific parameters things will start to become very
> > unwieldy.
> 
> I agree with the goal of keeping drm_panel interface-agnostic. However, one 
> way or another, interface parameters will need to be communicated between the 
> panel driver and the controller driver. My preference, if we need to extend 
> the number and/or scope of parameters beyond what drm_display_info could 
> reasonably contain, would be to implement a new drm_panel operation to 
> query/configure interface parameters, using a structure that contains the 
> interface type and a union of type-specific structures. This would keep the 
> API generic in the sense of not requiring explicit knowledge of all interfaces 
> in the drivers, while offering the flexibility we need with a way to easily 
> detect the interface type at runtime and react on unknown/unsupported types.

That's exactly what I was hoping could be avoided. If instead we modeled
the interface type as a bus, we could for example have an lvds_bus along
with an lvds_device and then use that as the natural place to store
these properties. Much like we do for DSI.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140715/3a881c50/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:52               ` Thierry Reding
@ 2014-07-15 11:07                 ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 11:07 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 5039 bytes --]

Hi Thierry,

On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> >> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> >>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> >>>>>> display controller device.
> >>>>>> 
> >>>>>> The HLCDC block provides a single RGB output port, and only
> >>>>>> supports LCD panels connection to LCD panels for now.
> >>>>>> 
> >>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>>>> panel connected on this port (note that the HLCDC RGB connector
> >>>>>> implementation makes use of the DRM panel framework).
> >>>>>> 
> >>>>>> Connection to other external devices (DRM bridges) might be added
> >>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>>>> 
> >>>>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >>>>>> ---
> >>>>>> 
> >>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++
> >>>>>>  1 file changed, 59 insertions(+)
> >>>>>>  create mode 100644
> >>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> >>> 
> >>> [snip]
> >>> 
> >>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>> following values:
> >>>>>> +   * 0: RGB444
> >>>>>> +   * 1: RGB565
> >>>>>> +   * 2: RGB666
> >>>>>> +   * 3: RGB888
> >>>>> 
> >>>>> These are properties of the panel and should be obtained from the
> >>>> panel directly rather than an additional cell in this specifier.
> >>>> 
> >>>> Okay.
> >>>> What's the preferred way of doing this ?
> >>>> What about defining an rgb-mode property in the panel node.
> >>> 
> >>> You could do that, but it won't help you much, as the HLCDC driver
> >>> must not parse properties from the panel node. You should instead
> >>> extend the drm_panel API with a function to retrieve panel properties.
> >>> The HLCDC driver will then query the panel driver at runtime for the
> >>> interface type. The panel driver will get the information from
> >>> hardcoded data in the driver, from DT or possibly in some cases by
> >>> querying the panel hardware directly.
> >> 
> >> My preference for this would be that we either add this to some existing
> >> structure (struct drm_display_info seems like a good candidate) or if
> >> the number of parameters grows out of hands, then maybe even introduce a
> >> new type of device that's specific for the interface. DRM panels are an
> >> abstraction for panels, that is, interface-agnostic, and if we start
> >> exposing interface specific parameters things will start to become very
> >> unwieldy.
> > 
> > I agree with the goal of keeping drm_panel interface-agnostic. However,
> > one way or another, interface parameters will need to be communicated
> > between the panel driver and the controller driver. My preference, if we
> > need to extend the number and/or scope of parameters beyond what
> > drm_display_info could reasonably contain, would be to implement a new
> > drm_panel operation to query/configure interface parameters, using a
> > structure that contains the interface type and a union of type-specific
> > structures. This would keep the API generic in the sense of not requiring
> > explicit knowledge of all interfaces in the drivers, while offering the
> > flexibility we need with a way to easily detect the interface type at
> > runtime and react on unknown/unsupported types.
>
> That's exactly what I was hoping could be avoided. If instead we modeled
> the interface type as a bus, we could for example have an lvds_bus along
> with an lvds_device and then use that as the natural place to store
> these properties. Much like we do for DSI.

And I believe that's what we should avoid ;-) First of all, let's not forget 
that Linux models control busses, not data busses. DSI is a special case as it 
combines the control and data busses, but in the general case the same 
implementation isn't possible. An LVDS panel controlled through I2C needs to 
be an I2C device sitting on an I2C bus.

Then, I believe it would make all drivers simpler if we had a single object 
type to deal with, with proper abstractions for bus types. A drm_panel that 
can model panels regardless of the data bus type, with one operation that 
conveys bus-specific information, makes storing the objects and communicating 
with them simpler than having to deal with different kind of devices.

-- 
Regards,

Laurent Pinchart

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 11:07                 ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-15 11:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> >> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> >>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> >>>>>> display controller device.
> >>>>>> 
> >>>>>> The HLCDC block provides a single RGB output port, and only
> >>>>>> supports LCD panels connection to LCD panels for now.
> >>>>>> 
> >>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>>>> panel connected on this port (note that the HLCDC RGB connector
> >>>>>> implementation makes use of the DRM panel framework).
> >>>>>> 
> >>>>>> Connection to other external devices (DRM bridges) might be added
> >>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>>>> 
> >>>>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> >>>>>> ---
> >>>>>> 
> >>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++
> >>>>>>  1 file changed, 59 insertions(+)
> >>>>>>  create mode 100644
> >>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> >>> 
> >>> [snip]
> >>> 
> >>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>> following values:
> >>>>>> +   * 0: RGB444
> >>>>>> +   * 1: RGB565
> >>>>>> +   * 2: RGB666
> >>>>>> +   * 3: RGB888
> >>>>> 
> >>>>> These are properties of the panel and should be obtained from the
> >>>> panel directly rather than an additional cell in this specifier.
> >>>> 
> >>>> Okay.
> >>>> What's the preferred way of doing this ?
> >>>> What about defining an rgb-mode property in the panel node.
> >>> 
> >>> You could do that, but it won't help you much, as the HLCDC driver
> >>> must not parse properties from the panel node. You should instead
> >>> extend the drm_panel API with a function to retrieve panel properties.
> >>> The HLCDC driver will then query the panel driver at runtime for the
> >>> interface type. The panel driver will get the information from
> >>> hardcoded data in the driver, from DT or possibly in some cases by
> >>> querying the panel hardware directly.
> >> 
> >> My preference for this would be that we either add this to some existing
> >> structure (struct drm_display_info seems like a good candidate) or if
> >> the number of parameters grows out of hands, then maybe even introduce a
> >> new type of device that's specific for the interface. DRM panels are an
> >> abstraction for panels, that is, interface-agnostic, and if we start
> >> exposing interface specific parameters things will start to become very
> >> unwieldy.
> > 
> > I agree with the goal of keeping drm_panel interface-agnostic. However,
> > one way or another, interface parameters will need to be communicated
> > between the panel driver and the controller driver. My preference, if we
> > need to extend the number and/or scope of parameters beyond what
> > drm_display_info could reasonably contain, would be to implement a new
> > drm_panel operation to query/configure interface parameters, using a
> > structure that contains the interface type and a union of type-specific
> > structures. This would keep the API generic in the sense of not requiring
> > explicit knowledge of all interfaces in the drivers, while offering the
> > flexibility we need with a way to easily detect the interface type at
> > runtime and react on unknown/unsupported types.
>
> That's exactly what I was hoping could be avoided. If instead we modeled
> the interface type as a bus, we could for example have an lvds_bus along
> with an lvds_device and then use that as the natural place to store
> these properties. Much like we do for DSI.

And I believe that's what we should avoid ;-) First of all, let's not forget 
that Linux models control busses, not data busses. DSI is a special case as it 
combines the control and data busses, but in the general case the same 
implementation isn't possible. An LVDS panel controlled through I2C needs to 
be an I2C device sitting on an I2C bus.

Then, I believe it would make all drivers simpler if we had a single object 
type to deal with, with proper abstractions for bus types. A drm_panel that 
can model panels regardless of the data bus type, with one operation that 
conveys bus-specific information, makes storing the objects and communicating 
with them simpler than having to deal with different kind of devices.

-- 
Regards,

Laurent Pinchart
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140715/a39b1cb9/attachment.sig>

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

* Re: [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
  2014-07-12 18:37       ` Rob Clark
@ 2014-07-15 11:26         ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 11:26 UTC (permalink / raw)
  To: Rob Clark
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni

On Sat, 12 Jul 2014 14:37:16 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Sat, Jul 12, 2014 at 2:16 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > Hello,
> >
> > On Mon,  7 Jul 2014 18:42:58 +0200
> > Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:
> >
> >
> >> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> >> +{
> >> +     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> >> +     unsigned long flags;
> >> +     int i;
> >> +
> >> +     spin_lock_irqsave(&dma->lock, flags);
> >> +     for (i = 0; i < layer->max_planes; i++) {
> >> +             if (!dma->cur[i])
> >> +                     break;
> >> +
> >> +             dma->cur[i]->ctrl = 0;
> >> +     }
> >> +     spin_unlock_irqrestore(&dma->lock, flags);
> >> +
> >> +     return 0;
> >> +}
> >
> >
> > I'm trying to simplify the hlcdc_layer code and in order to do that I
> > need to know what's expected when a user calls plane_disable (or more
> > exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
> > to 0).
> >
> > The HLCDC Display Controller support two types of disable:
> >
> > 1) The plane is disabled at the end of the current frame (the is the
> > solution I'm using)
> >
> > 2) The plane is disabled right away (I haven't tested it, but I think
> > this solution could generate some sort of artifacts for a short period
> > of time, because the framebuffer might be partially displayed)
> >
> > If solution 1 is chosen, should I wait for the plane to be actually
> > disabled before returning ?
> 
> for cursor in particular, if you block, it is going to be a massive
> slowdown for some apps.  I remember at least older gdm would rapidly
> flash a spinning cursor.  As a result, if you wait for vsync each
> time, it would take a couple minutes to login!

That makes sense.

> 
> if #2 works, I'd recommend it.  Otherwise you may have to do some of
> the same hijinks that I have to do in mdp4_crtc for the cursor.

I already have a working solution which does not block with #1, I was
just trying to simplify my code ;-).
I'll try #2 and if it works without any side effects I'll go for it.

Thanks,

Boris

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

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

* [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support
@ 2014-07-15 11:26         ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 12 Jul 2014 14:37:16 -0400
Rob Clark <robdclark@gmail.com> wrote:

> On Sat, Jul 12, 2014 at 2:16 PM, Boris BREZILLON
> <boris.brezillon@free-electrons.com> wrote:
> > Hello,
> >
> > On Mon,  7 Jul 2014 18:42:58 +0200
> > Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:
> >
> >
> >> +int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> >> +{
> >> +     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> >> +     unsigned long flags;
> >> +     int i;
> >> +
> >> +     spin_lock_irqsave(&dma->lock, flags);
> >> +     for (i = 0; i < layer->max_planes; i++) {
> >> +             if (!dma->cur[i])
> >> +                     break;
> >> +
> >> +             dma->cur[i]->ctrl = 0;
> >> +     }
> >> +     spin_unlock_irqrestore(&dma->lock, flags);
> >> +
> >> +     return 0;
> >> +}
> >
> >
> > I'm trying to simplify the hlcdc_layer code and in order to do that I
> > need to know what's expected when a user calls plane_disable (or more
> > exactly DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set
> > to 0).
> >
> > The HLCDC Display Controller support two types of disable:
> >
> > 1) The plane is disabled at the end of the current frame (the is the
> > solution I'm using)
> >
> > 2) The plane is disabled right away (I haven't tested it, but I think
> > this solution could generate some sort of artifacts for a short period
> > of time, because the framebuffer might be partially displayed)
> >
> > If solution 1 is chosen, should I wait for the plane to be actually
> > disabled before returning ?
> 
> for cursor in particular, if you block, it is going to be a massive
> slowdown for some apps.  I remember at least older gdm would rapidly
> flash a spinning cursor.  As a result, if you wait for vsync each
> time, it would take a couple minutes to login!

That makes sense.

> 
> if #2 works, I'd recommend it.  Otherwise you may have to do some of
> the same hijinks that I have to do in mdp4_crtc for the cursor.

I already have a working solution which does not block with #1, I was
just trying to simplify my code ;-).
I'll try #2 and if it works without any side effects I'll go for it.

Thanks,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-14 10:18             ` Thierry Reding
@ 2014-07-15 11:45               ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 11:45 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

On Mon, 14 Jul 2014 12:18:08 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 11, 2014 at 02:00:25PM +0200, Boris BREZILLON wrote:
> > On Fri, 11 Jul 2014 12:37:46 +0200 Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> [...]
> > > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > > currently defining HLCDC connector as an LVDS connector) ?
> > > 
> > > Not that I know of. The DRM API has been developed before display on embedded 
> > > systems became such a hot topic. If we had to redo it today, panels might be 
> > > exposed to userspace as such, with a connector. We have to live with the past, 
> > > so the connector will stay, but adding a new RGB connector type could make 
> > > sense (although we might need a different name, in a way the VGA and LVDS 
> > > connectors also carry RGB signals).
> > 
> > I had the same concern: I didn't find how this kind of connectors
> > was named (most of the time they're just referenced as RGB) :-).
> > What about RAW_RGB ?
> 
> Are there even panels that take raw RGB as input? In all cases I've seen
> (which admittedly may not be all that many) there's always a transparent
> RGB/LVDS bridge, so the "connector" is in fact LVDS, not RGB, even if
> the display controller outputs RGB directly.

At least the LCD module I'm using (FL500WVR00-A0T) is taking raw RGB as
input ;-).

Best Regards,

Boris

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 11:45               ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 14 Jul 2014 12:18:08 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 11, 2014 at 02:00:25PM +0200, Boris BREZILLON wrote:
> > On Fri, 11 Jul 2014 12:37:46 +0200 Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > > On Thursday 10 July 2014 14:56:26 Boris BREZILLON wrote:
> [...]
> > > > BTW, is there any reason for not defining an RGB connector type (I'm
> > > > currently defining HLCDC connector as an LVDS connector) ?
> > > 
> > > Not that I know of. The DRM API has been developed before display on embedded 
> > > systems became such a hot topic. If we had to redo it today, panels might be 
> > > exposed to userspace as such, with a connector. We have to live with the past, 
> > > so the connector will stay, but adding a new RGB connector type could make 
> > > sense (although we might need a different name, in a way the VGA and LVDS 
> > > connectors also carry RGB signals).
> > 
> > I had the same concern: I didn't find how this kind of connectors
> > was named (most of the time they're just referenced as RGB) :-).
> > What about RAW_RGB ?
> 
> Are there even panels that take raw RGB as input? In all cases I've seen
> (which admittedly may not be all that many) there's always a transparent
> RGB/LVDS bridge, so the "connector" is in fact LVDS, not RGB, even if
> the display controller outputs RGB directly.

At least the LCD module I'm using (FL500WVR00-A0T) is taking raw RGB as
input ;-).

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:52               ` Thierry Reding
@ 2014-07-15 12:14                 ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 12:14 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Laurent Pinchart, Samuel Ortiz, Lee Jones, linux-pwm,
	David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer

On Tue, 15 Jul 2014 12:52:54 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > Hi Thierry,
> > 
> > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > > On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > > > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > > >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > > >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > > >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > > >>>> display controller device.
> > > >>>> 
> > > >>>> The HLCDC block provides a single RGB output port, and only supports
> > > >>>> LCD panels connection to LCD panels for now.
> > > >>>> 
> > > >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > > >>>> panel connected on this port (note that the HLCDC RGB connector
> > > >>>> implementation makes use of the DRM panel framework).
> > > >>>> 
> > > >>>> Connection to other external devices (DRM bridges) might be added
> > > >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > > >>>> 
> > > >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > >>>> ---
> > > >>>> 
> > > >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> > > >>>>  1 file changed, 59 insertions(+)
> > > >>>>  create mode 100644
> > > >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > 
> > > > [snip]
> > > > 
> > > >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>> +   The first cell is a phandle to a DRM panel device
> > > >>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>> following values:
> > > >>>> +   * 0: RGB444
> > > >>>> +   * 1: RGB565
> > > >>>> +   * 2: RGB666
> > > >>>> +   * 3: RGB888
> > > >>> 
> > > >>> These are properties of the panel and should be obtained from the
> > > >>> panel directly rather than an additional cell in this specifier.
> > > >> 
> > > >> Okay.
> > > >> What's the preferred way of doing this ?
> > > >> What about defining an rgb-mode property in the panel node.
> > > > 
> > > > You could do that, but it won't help you much, as the HLCDC driver must
> > > > not parse properties from the panel node. You should instead extend the
> > > > drm_panel API with a function to retrieve panel properties. The HLCDC
> > > > driver will then query the panel driver at runtime for the interface
> > > > type. The panel driver will get the information from hardcoded data in
> > > > the driver, from DT or possibly in some cases by querying the panel
> > > > hardware directly.
> > > 
> > > My preference for this would be that we either add this to some existing
> > > structure (struct drm_display_info seems like a good candidate) or if
> > > the number of parameters grows out of hands, then maybe even introduce a
> > > new type of device that's specific for the interface. DRM panels are an
> > > abstraction for panels, that is, interface-agnostic, and if we start
> > > exposing interface specific parameters things will start to become very
> > > unwieldy.
> > 
> > I agree with the goal of keeping drm_panel interface-agnostic. However, one 
> > way or another, interface parameters will need to be communicated between the 
> > panel driver and the controller driver. My preference, if we need to extend 
> > the number and/or scope of parameters beyond what drm_display_info could 
> > reasonably contain, would be to implement a new drm_panel operation to 
> > query/configure interface parameters, using a structure that contains the 
> > interface type and a union of type-specific structures. This would keep the 
> > API generic in the sense of not requiring explicit knowledge of all interfaces 
> > in the drivers, while offering the flexibility we need with a way to easily 
> > detect the interface type at runtime and react on unknown/unsupported types.
> 
> That's exactly what I was hoping could be avoided. If instead we modeled
> the interface type as a bus, we could for example have an lvds_bus along
> with an lvds_device and then use that as the natural place to store
> these properties. Much like we do for DSI.

I understand this is not a simple case here, and this is why I left
RGB mode config in the HLCDC node in the first place.

Anyway, I agree that this rgb mode should not be defined in the hlcdc
node but rather in the slave device. I said slave device and not panel
device here because the device connected to the RGB connector is not
necessarily an LCD panel (i.e. atmel is connecting a raw RGB to HDMI
bridge on the RGB connector). And given that I definitely think an
interface bus architecture is better: this way we could configure RGB
mode no matter what kind of device is connected on this bus and we
could keep slave devices interface-agnostic.

This being said, I guess modeling interface (or connector) types as
busses is not that simple.

I really want to help here, so let me know what I can do.

Just a side note: you are saying that RGB mode is a panel property, and
this is not entirely true (it might depends on board design) :-). In
some HW designs, LSB bits of the RGB connector are either connected to
ground or to the first available MSB bit. This way you can use an LCD
panel supporting RGB888 mode with an display controller supporting lower
modes (RGB555 or RGB666).

Best Regards,

Boris

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-15 12:14                 ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-15 12:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 15 Jul 2014 12:52:54 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > Hi Thierry,
> > 
> > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > > On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > > > On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > > >> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > > >>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > >>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > > >>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > > >>>> display controller device.
> > > >>>> 
> > > >>>> The HLCDC block provides a single RGB output port, and only supports
> > > >>>> LCD panels connection to LCD panels for now.
> > > >>>> 
> > > >>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > > >>>> panel connected on this port (note that the HLCDC RGB connector
> > > >>>> implementation makes use of the DRM panel framework).
> > > >>>> 
> > > >>>> Connection to other external devices (DRM bridges) might be added
> > > >>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > > >>>> 
> > > >>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > > >>>> ---
> > > >>>> 
> > > >>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 +++++++++++
> > > >>>>  1 file changed, 59 insertions(+)
> > > >>>>  create mode 100644
> > > >>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > 
> > > > [snip]
> > > > 
> > > >>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>> +   The first cell is a phandle to a DRM panel device
> > > >>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>> following values:
> > > >>>> +   * 0: RGB444
> > > >>>> +   * 1: RGB565
> > > >>>> +   * 2: RGB666
> > > >>>> +   * 3: RGB888
> > > >>> 
> > > >>> These are properties of the panel and should be obtained from the
> > > >>> panel directly rather than an additional cell in this specifier.
> > > >> 
> > > >> Okay.
> > > >> What's the preferred way of doing this ?
> > > >> What about defining an rgb-mode property in the panel node.
> > > > 
> > > > You could do that, but it won't help you much, as the HLCDC driver must
> > > > not parse properties from the panel node. You should instead extend the
> > > > drm_panel API with a function to retrieve panel properties. The HLCDC
> > > > driver will then query the panel driver at runtime for the interface
> > > > type. The panel driver will get the information from hardcoded data in
> > > > the driver, from DT or possibly in some cases by querying the panel
> > > > hardware directly.
> > > 
> > > My preference for this would be that we either add this to some existing
> > > structure (struct drm_display_info seems like a good candidate) or if
> > > the number of parameters grows out of hands, then maybe even introduce a
> > > new type of device that's specific for the interface. DRM panels are an
> > > abstraction for panels, that is, interface-agnostic, and if we start
> > > exposing interface specific parameters things will start to become very
> > > unwieldy.
> > 
> > I agree with the goal of keeping drm_panel interface-agnostic. However, one 
> > way or another, interface parameters will need to be communicated between the 
> > panel driver and the controller driver. My preference, if we need to extend 
> > the number and/or scope of parameters beyond what drm_display_info could 
> > reasonably contain, would be to implement a new drm_panel operation to 
> > query/configure interface parameters, using a structure that contains the 
> > interface type and a union of type-specific structures. This would keep the 
> > API generic in the sense of not requiring explicit knowledge of all interfaces 
> > in the drivers, while offering the flexibility we need with a way to easily 
> > detect the interface type at runtime and react on unknown/unsupported types.
> 
> That's exactly what I was hoping could be avoided. If instead we modeled
> the interface type as a bus, we could for example have an lvds_bus along
> with an lvds_device and then use that as the natural place to store
> these properties. Much like we do for DSI.

I understand this is not a simple case here, and this is why I left
RGB mode config in the HLCDC node in the first place.

Anyway, I agree that this rgb mode should not be defined in the hlcdc
node but rather in the slave device. I said slave device and not panel
device here because the device connected to the RGB connector is not
necessarily an LCD panel (i.e. atmel is connecting a raw RGB to HDMI
bridge on the RGB connector). And given that I definitely think an
interface bus architecture is better: this way we could configure RGB
mode no matter what kind of device is connected on this bus and we
could keep slave devices interface-agnostic.

This being said, I guess modeling interface (or connector) types as
busses is not that simple.

I really want to help here, so let me know what I can do.

Just a side note: you are saying that RGB mode is a panel property, and
this is not entirely true (it might depends on board design) :-). In
some HW designs, LSB bits of the RGB connector are either connected to
ground or to the first available MSB bit. This way you can use an LCD
panel supporting RGB888 mode with an display controller supporting lower
modes (RGB555 or RGB666).

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 11:07                 ` Laurent Pinchart
@ 2014-07-16 13:05                   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-16 13:05 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Thierry Reding, Samuel Ortiz, Lee Jones, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

Hi Laurent,

On Tue, 15 Jul 2014 13:07:58 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Thierry,
> 
> On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> > On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > >> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > >>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > >>>>>> display controller device.
> > >>>>>> 
> > >>>>>> The HLCDC block provides a single RGB output port, and only
> > >>>>>> supports LCD panels connection to LCD panels for now.
> > >>>>>> 
> > >>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>>>> implementation makes use of the DRM panel framework).
> > >>>>>> 
> > >>>>>> Connection to other external devices (DRM bridges) might be added
> > >>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>>>> 
> > >>>>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > >>>>>> ---
> > >>>>>> 
> > >>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++
> > >>>>>>  1 file changed, 59 insertions(+)
> > >>>>>>  create mode 100644
> > >>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > >>> 
> > >>> [snip]
> > >>> 
> > >>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>> following values:
> > >>>>>> +   * 0: RGB444
> > >>>>>> +   * 1: RGB565
> > >>>>>> +   * 2: RGB666
> > >>>>>> +   * 3: RGB888
> > >>>>> 
> > >>>>> These are properties of the panel and should be obtained from the
> > >>>> panel directly rather than an additional cell in this specifier.
> > >>>> 
> > >>>> Okay.
> > >>>> What's the preferred way of doing this ?
> > >>>> What about defining an rgb-mode property in the panel node.
> > >>> 
> > >>> You could do that, but it won't help you much, as the HLCDC driver
> > >>> must not parse properties from the panel node. You should instead
> > >>> extend the drm_panel API with a function to retrieve panel properties.
> > >>> The HLCDC driver will then query the panel driver at runtime for the
> > >>> interface type. The panel driver will get the information from
> > >>> hardcoded data in the driver, from DT or possibly in some cases by
> > >>> querying the panel hardware directly.
> > >> 
> > >> My preference for this would be that we either add this to some existing
> > >> structure (struct drm_display_info seems like a good candidate) or if
> > >> the number of parameters grows out of hands, then maybe even introduce a
> > >> new type of device that's specific for the interface. DRM panels are an
> > >> abstraction for panels, that is, interface-agnostic, and if we start
> > >> exposing interface specific parameters things will start to become very
> > >> unwieldy.
> > > 
> > > I agree with the goal of keeping drm_panel interface-agnostic. However,
> > > one way or another, interface parameters will need to be communicated
> > > between the panel driver and the controller driver. My preference, if we
> > > need to extend the number and/or scope of parameters beyond what
> > > drm_display_info could reasonably contain, would be to implement a new
> > > drm_panel operation to query/configure interface parameters, using a
> > > structure that contains the interface type and a union of type-specific
> > > structures. This would keep the API generic in the sense of not requiring
> > > explicit knowledge of all interfaces in the drivers, while offering the
> > > flexibility we need with a way to easily detect the interface type at
> > > runtime and react on unknown/unsupported types.
> >
> > That's exactly what I was hoping could be avoided. If instead we modeled
> > the interface type as a bus, we could for example have an lvds_bus along
> > with an lvds_device and then use that as the natural place to store
> > these properties. Much like we do for DSI.
> 
> And I believe that's what we should avoid ;-) First of all, let's not forget 
> that Linux models control busses, not data busses. DSI is a special case as it 
> combines the control and data busses, but in the general case the same 
> implementation isn't possible. An LVDS panel controlled through I2C needs to 
> be an I2C device sitting on an I2C bus.
> 
> Then, I believe it would make all drivers simpler if we had a single object 
> type to deal with, with proper abstractions for bus types. A drm_panel that 
> can model panels regardless of the data bus type, with one operation that 
> conveys bus-specific information, makes storing the objects and communicating 
> with them simpler than having to deal with different kind of devices.
> 

Could you detail a bit what you mean by "single object type" ?

Is this about making a common abstraction class (by mean of
drm_xxx and drm_xxx_funcs) that could represent any display device
(drm_bridge, drm_panel, ...) ?

Best Regards,

Boris

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-16 13:05                   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-16 13:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Laurent,

On Tue, 15 Jul 2014 13:07:58 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Thierry,
> 
> On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> > On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > >> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > >>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides a
> > >>>>>> display controller device.
> > >>>>>> 
> > >>>>>> The HLCDC block provides a single RGB output port, and only
> > >>>>>> supports LCD panels connection to LCD panels for now.
> > >>>>>> 
> > >>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>>>> implementation makes use of the DRM panel framework).
> > >>>>>> 
> > >>>>>> Connection to other external devices (DRM bridges) might be added
> > >>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>>>> 
> > >>>>>> Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
> > >>>>>> ---
> > >>>>>> 
> > >>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++++
> > >>>>>>  1 file changed, 59 insertions(+)
> > >>>>>>  create mode 100644
> > >>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > >>> 
> > >>> [snip]
> > >>> 
> > >>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>> following values:
> > >>>>>> +   * 0: RGB444
> > >>>>>> +   * 1: RGB565
> > >>>>>> +   * 2: RGB666
> > >>>>>> +   * 3: RGB888
> > >>>>> 
> > >>>>> These are properties of the panel and should be obtained from the
> > >>>> panel directly rather than an additional cell in this specifier.
> > >>>> 
> > >>>> Okay.
> > >>>> What's the preferred way of doing this ?
> > >>>> What about defining an rgb-mode property in the panel node.
> > >>> 
> > >>> You could do that, but it won't help you much, as the HLCDC driver
> > >>> must not parse properties from the panel node. You should instead
> > >>> extend the drm_panel API with a function to retrieve panel properties.
> > >>> The HLCDC driver will then query the panel driver at runtime for the
> > >>> interface type. The panel driver will get the information from
> > >>> hardcoded data in the driver, from DT or possibly in some cases by
> > >>> querying the panel hardware directly.
> > >> 
> > >> My preference for this would be that we either add this to some existing
> > >> structure (struct drm_display_info seems like a good candidate) or if
> > >> the number of parameters grows out of hands, then maybe even introduce a
> > >> new type of device that's specific for the interface. DRM panels are an
> > >> abstraction for panels, that is, interface-agnostic, and if we start
> > >> exposing interface specific parameters things will start to become very
> > >> unwieldy.
> > > 
> > > I agree with the goal of keeping drm_panel interface-agnostic. However,
> > > one way or another, interface parameters will need to be communicated
> > > between the panel driver and the controller driver. My preference, if we
> > > need to extend the number and/or scope of parameters beyond what
> > > drm_display_info could reasonably contain, would be to implement a new
> > > drm_panel operation to query/configure interface parameters, using a
> > > structure that contains the interface type and a union of type-specific
> > > structures. This would keep the API generic in the sense of not requiring
> > > explicit knowledge of all interfaces in the drivers, while offering the
> > > flexibility we need with a way to easily detect the interface type at
> > > runtime and react on unknown/unsupported types.
> >
> > That's exactly what I was hoping could be avoided. If instead we modeled
> > the interface type as a bus, we could for example have an lvds_bus along
> > with an lvds_device and then use that as the natural place to store
> > these properties. Much like we do for DSI.
> 
> And I believe that's what we should avoid ;-) First of all, let's not forget 
> that Linux models control busses, not data busses. DSI is a special case as it 
> combines the control and data busses, but in the general case the same 
> implementation isn't possible. An LVDS panel controlled through I2C needs to 
> be an I2C device sitting on an I2C bus.
> 
> Then, I believe it would make all drivers simpler if we had a single object 
> type to deal with, with proper abstractions for bus types. A drm_panel that 
> can model panels regardless of the data bus type, with one operation that 
> conveys bus-specific information, makes storing the objects and communicating 
> with them simpler than having to deal with different kind of devices.
> 

Could you detail a bit what you mean by "single object type" ?

Is this about making a common abstraction class (by mean of
drm_xxx and drm_xxx_funcs) that could represent any display device
(drm_bridge, drm_panel, ...) ?

Best Regards,

Boris

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-16 13:05                   ` Boris BREZILLON
  (?)
@ 2014-07-16 13:20                     ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-16 13:20 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Thierry Reding, Samuel Ortiz, Lee Jones, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

Hi Boris,

On Wednesday 16 July 2014 15:05:22 Boris BREZILLON wrote:
> On Tue, 15 Jul 2014 13:07:58 +0200 Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> >> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> >>> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> >>>> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> >>>>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >>>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides
> >>>>>>>> a display controller device.
> >>>>>>>> 
> >>>>>>>> The HLCDC block provides a single RGB output port, and only
> >>>>>>>> supports LCD panels connection to LCD panels for now.
> >>>>>>>> 
> >>>>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>>>>>> panel connected on this port (note that the HLCDC RGB connector
> >>>>>>>> implementation makes use of the DRM panel framework).
> >>>>>>>> 
> >>>>>>>> Connection to other external devices (DRM bridges) might be added
> >>>>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>>>>>> 
> >>>>>>>> Signed-off-by: Boris BREZILLON
> >>>>>>>> <boris.brezillon@free-electrons.com>
> >>>>>>>> ---
> >>>>>>>> 
> >>>>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++
> >>>>>>>>  1 file changed, 59 insertions(+)
> >>>>>>>>  create mode 100644
> >>>>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> >>>>> 
> >>>>> [snip]
> >>>>> 
> >>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>>> following values:
> >>>>>>>> +   * 0: RGB444
> >>>>>>>> +   * 1: RGB565
> >>>>>>>> +   * 2: RGB666
> >>>>>>>> +   * 3: RGB888
> >>>>>>> 
> >>>>>>> These are properties of the panel and should be obtained from the
> >>>>>>> panel directly rather than an additional cell in this specifier.
> >>>>>> 
> >>>>>> Okay.
> >>>>>> What's the preferred way of doing this ?
> >>>>>> What about defining an rgb-mode property in the panel node.
> >>>>> 
> >>>>> You could do that, but it won't help you much, as the HLCDC driver
> >>>>> must not parse properties from the panel node. You should instead
> >>>>> extend the drm_panel API with a function to retrieve panel
> >>>>> properties. The HLCDC driver will then query the panel driver at
> >>>>> runtime for the interface type. The panel driver will get the
> >>>>> information from hardcoded data in the driver, from DT or possibly
> >>>>> in some cases by querying the panel hardware directly.
> >>>> 
> >>>> My preference for this would be that we either add this to some
> >>>> existing structure (struct drm_display_info seems like a good
> >>>> candidate) or if the number of parameters grows out of hands, then
> >>>> maybe even introduce a new type of device that's specific for the
> >>>> interface. DRM panels are an abstraction for panels, that is,
> >>>> interface-agnostic, and if we start exposing interface specific
> >>>> parameters things will start to become very unwieldy.
> >>> 
> >>> I agree with the goal of keeping drm_panel interface-agnostic.
> >>> However, one way or another, interface parameters will need to be
> >>> communicated between the panel driver and the controller driver. My
> >>> preference, if we need to extend the number and/or scope of parameters
> >>> beyond what drm_display_info could reasonably contain, would be to
> >>> implement a new drm_panel operation to query/configure interface
> >>> parameters, using a structure that contains the interface type and a
> >>> union of type-specific structures. This would keep the API generic in
> >>> the sense of not requiring explicit knowledge of all interfaces in the
> >>> drivers, while offering the flexibility we need with a way to easily
> >>> detect the interface type at runtime and react on unknown/unsupported
> >>> types.
> >> 
> >> That's exactly what I was hoping could be avoided. If instead we modeled
> >> the interface type as a bus, we could for example have an lvds_bus along
> >> with an lvds_device and then use that as the natural place to store
> >> these properties. Much like we do for DSI.
> > 
> > And I believe that's what we should avoid ;-) First of all, let's not
> > forget that Linux models control busses, not data busses. DSI is a
> > special case as it combines the control and data busses, but in the
> > general case the same implementation isn't possible. An LVDS panel
> > controlled through I2C needs to be an I2C device sitting on an I2C bus.
> > 
> > Then, I believe it would make all drivers simpler if we had a single
> > object type to deal with, with proper abstractions for bus types. A
> > drm_panel that can model panels regardless of the data bus type, with one
> > operation that conveys bus-specific information, makes storing the objects
> > and communicating with them simpler than having to deal with different
> > kind of devices.
>
> Could you detail a bit what you mean by "single object type" ?
> 
> Is this about making a common abstraction class (by mean of
> drm_xxx and drm_xxx_funcs) that could represent any display device
> (drm_bridge, drm_panel, ...) ?

Exactly :-) This is similar to what exists in V4L, with a v4l2_subdev object 
able to model any kind of IP core or external chip.

I don't think we will get there in one go, but I'd like to start by merging 
drm_encoder and drm_bridge on the kernel side. Both objects model the same 
hardware, a drm_encoder on one board could be a drm_bridge on another one. 
>From a userspace point of view drm_encoder won't go away, and we can't chain 
multiple encoders, so the change would be internal to the kernel only.

Then, as a next step, I believe using the same object to model panels would be 
a good idea, but there's no consensus on that.

-- 
Regards,

Laurent Pinchart


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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-16 13:20                     ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-16 13:20 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Thierry Reding, Samuel Ortiz, Lee Jones, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

Hi Boris,

On Wednesday 16 July 2014 15:05:22 Boris BREZILLON wrote:
> On Tue, 15 Jul 2014 13:07:58 +0200 Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> >> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> >>> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> >>>> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> >>>>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >>>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides
> >>>>>>>> a display controller device.
> >>>>>>>> 
> >>>>>>>> The HLCDC block provides a single RGB output port, and only
> >>>>>>>> supports LCD panels connection to LCD panels for now.
> >>>>>>>> 
> >>>>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>>>>>> panel connected on this port (note that the HLCDC RGB connector
> >>>>>>>> implementation makes use of the DRM panel framework).
> >>>>>>>> 
> >>>>>>>> Connection to other external devices (DRM bridges) might be added
> >>>>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>>>>>> 
> >>>>>>>> Signed-off-by: Boris BREZILLON
> >>>>>>>> <boris.brezillon@free-electrons.com>
> >>>>>>>> ---
> >>>>>>>> 
> >>>>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++
> >>>>>>>>  1 file changed, 59 insertions(+)
> >>>>>>>>  create mode 100644
> >>>>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> >>>>> 
> >>>>> [snip]
> >>>>> 
> >>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>>> following values:
> >>>>>>>> +   * 0: RGB444
> >>>>>>>> +   * 1: RGB565
> >>>>>>>> +   * 2: RGB666
> >>>>>>>> +   * 3: RGB888
> >>>>>>> 
> >>>>>>> These are properties of the panel and should be obtained from the
> >>>>>>> panel directly rather than an additional cell in this specifier.
> >>>>>> 
> >>>>>> Okay.
> >>>>>> What's the preferred way of doing this ?
> >>>>>> What about defining an rgb-mode property in the panel node.
> >>>>> 
> >>>>> You could do that, but it won't help you much, as the HLCDC driver
> >>>>> must not parse properties from the panel node. You should instead
> >>>>> extend the drm_panel API with a function to retrieve panel
> >>>>> properties. The HLCDC driver will then query the panel driver at
> >>>>> runtime for the interface type. The panel driver will get the
> >>>>> information from hardcoded data in the driver, from DT or possibly
> >>>>> in some cases by querying the panel hardware directly.
> >>>> 
> >>>> My preference for this would be that we either add this to some
> >>>> existing structure (struct drm_display_info seems like a good
> >>>> candidate) or if the number of parameters grows out of hands, then
> >>>> maybe even introduce a new type of device that's specific for the
> >>>> interface. DRM panels are an abstraction for panels, that is,
> >>>> interface-agnostic, and if we start exposing interface specific
> >>>> parameters things will start to become very unwieldy.
> >>> 
> >>> I agree with the goal of keeping drm_panel interface-agnostic.
> >>> However, one way or another, interface parameters will need to be
> >>> communicated between the panel driver and the controller driver. My
> >>> preference, if we need to extend the number and/or scope of parameters
> >>> beyond what drm_display_info could reasonably contain, would be to
> >>> implement a new drm_panel operation to query/configure interface
> >>> parameters, using a structure that contains the interface type and a
> >>> union of type-specific structures. This would keep the API generic in
> >>> the sense of not requiring explicit knowledge of all interfaces in the
> >>> drivers, while offering the flexibility we need with a way to easily
> >>> detect the interface type at runtime and react on unknown/unsupported
> >>> types.
> >> 
> >> That's exactly what I was hoping could be avoided. If instead we modeled
> >> the interface type as a bus, we could for example have an lvds_bus along
> >> with an lvds_device and then use that as the natural place to store
> >> these properties. Much like we do for DSI.
> > 
> > And I believe that's what we should avoid ;-) First of all, let's not
> > forget that Linux models control busses, not data busses. DSI is a
> > special case as it combines the control and data busses, but in the
> > general case the same implementation isn't possible. An LVDS panel
> > controlled through I2C needs to be an I2C device sitting on an I2C bus.
> > 
> > Then, I believe it would make all drivers simpler if we had a single
> > object type to deal with, with proper abstractions for bus types. A
> > drm_panel that can model panels regardless of the data bus type, with one
> > operation that conveys bus-specific information, makes storing the objects
> > and communicating with them simpler than having to deal with different
> > kind of devices.
>
> Could you detail a bit what you mean by "single object type" ?
> 
> Is this about making a common abstraction class (by mean of
> drm_xxx and drm_xxx_funcs) that could represent any display device
> (drm_bridge, drm_panel, ...) ?

Exactly :-) This is similar to what exists in V4L, with a v4l2_subdev object 
able to model any kind of IP core or external chip.

I don't think we will get there in one go, but I'd like to start by merging 
drm_encoder and drm_bridge on the kernel side. Both objects model the same 
hardware, a drm_encoder on one board could be a drm_bridge on another one. 
From a userspace point of view drm_encoder won't go away, and we can't chain 
multiple encoders, so the change would be internal to the kernel only.

Then, as a next step, I believe using the same object to model panels would be 
a good idea, but there's no consensus on that.

-- 
Regards,

Laurent Pinchart


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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-16 13:20                     ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-16 13:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Wednesday 16 July 2014 15:05:22 Boris BREZILLON wrote:
> On Tue, 15 Jul 2014 13:07:58 +0200 Laurent Pinchart wrote:
> > On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> >> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> >>> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> >>>> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> >>>>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> >>>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> >>>>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> >>>>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides
> >>>>>>>> a display controller device.
> >>>>>>>> 
> >>>>>>>> The HLCDC block provides a single RGB output port, and only
> >>>>>>>> supports LCD panels connection to LCD panels for now.
> >>>>>>>> 
> >>>>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> >>>>>>>> panel connected on this port (note that the HLCDC RGB connector
> >>>>>>>> implementation makes use of the DRM panel framework).
> >>>>>>>> 
> >>>>>>>> Connection to other external devices (DRM bridges) might be added
> >>>>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> >>>>>>>> 
> >>>>>>>> Signed-off-by: Boris BREZILLON
> >>>>>>>> <boris.brezillon@free-electrons.com>
> >>>>>>>> ---
> >>>>>>>> 
> >>>>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++
> >>>>>>>>  1 file changed, 59 insertions(+)
> >>>>>>>>  create mode 100644
> >>>>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> >>>>> 
> >>>>> [snip]
> >>>>> 
> >>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>>> following values:
> >>>>>>>> +   * 0: RGB444
> >>>>>>>> +   * 1: RGB565
> >>>>>>>> +   * 2: RGB666
> >>>>>>>> +   * 3: RGB888
> >>>>>>> 
> >>>>>>> These are properties of the panel and should be obtained from the
> >>>>>>> panel directly rather than an additional cell in this specifier.
> >>>>>> 
> >>>>>> Okay.
> >>>>>> What's the preferred way of doing this ?
> >>>>>> What about defining an rgb-mode property in the panel node.
> >>>>> 
> >>>>> You could do that, but it won't help you much, as the HLCDC driver
> >>>>> must not parse properties from the panel node. You should instead
> >>>>> extend the drm_panel API with a function to retrieve panel
> >>>>> properties. The HLCDC driver will then query the panel driver at
> >>>>> runtime for the interface type. The panel driver will get the
> >>>>> information from hardcoded data in the driver, from DT or possibly
> >>>>> in some cases by querying the panel hardware directly.
> >>>> 
> >>>> My preference for this would be that we either add this to some
> >>>> existing structure (struct drm_display_info seems like a good
> >>>> candidate) or if the number of parameters grows out of hands, then
> >>>> maybe even introduce a new type of device that's specific for the
> >>>> interface. DRM panels are an abstraction for panels, that is,
> >>>> interface-agnostic, and if we start exposing interface specific
> >>>> parameters things will start to become very unwieldy.
> >>> 
> >>> I agree with the goal of keeping drm_panel interface-agnostic.
> >>> However, one way or another, interface parameters will need to be
> >>> communicated between the panel driver and the controller driver. My
> >>> preference, if we need to extend the number and/or scope of parameters
> >>> beyond what drm_display_info could reasonably contain, would be to
> >>> implement a new drm_panel operation to query/configure interface
> >>> parameters, using a structure that contains the interface type and a
> >>> union of type-specific structures. This would keep the API generic in
> >>> the sense of not requiring explicit knowledge of all interfaces in the
> >>> drivers, while offering the flexibility we need with a way to easily
> >>> detect the interface type at runtime and react on unknown/unsupported
> >>> types.
> >> 
> >> That's exactly what I was hoping could be avoided. If instead we modeled
> >> the interface type as a bus, we could for example have an lvds_bus along
> >> with an lvds_device and then use that as the natural place to store
> >> these properties. Much like we do for DSI.
> > 
> > And I believe that's what we should avoid ;-) First of all, let's not
> > forget that Linux models control busses, not data busses. DSI is a
> > special case as it combines the control and data busses, but in the
> > general case the same implementation isn't possible. An LVDS panel
> > controlled through I2C needs to be an I2C device sitting on an I2C bus.
> > 
> > Then, I believe it would make all drivers simpler if we had a single
> > object type to deal with, with proper abstractions for bus types. A
> > drm_panel that can model panels regardless of the data bus type, with one
> > operation that conveys bus-specific information, makes storing the objects
> > and communicating with them simpler than having to deal with different
> > kind of devices.
>
> Could you detail a bit what you mean by "single object type" ?
> 
> Is this about making a common abstraction class (by mean of
> drm_xxx and drm_xxx_funcs) that could represent any display device
> (drm_bridge, drm_panel, ...) ?

Exactly :-) This is similar to what exists in V4L, with a v4l2_subdev object 
able to model any kind of IP core or external chip.

I don't think we will get there in one go, but I'd like to start by merging 
drm_encoder and drm_bridge on the kernel side. Both objects model the same 
hardware, a drm_encoder on one board could be a drm_bridge on another one. 
>From a userspace point of view drm_encoder won't go away, and we can't chain 
multiple encoders, so the change would be internal to the kernel only.

Then, as a next step, I believe using the same object to model panels would be 
a good idea, but there's no consensus on that.

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-16 13:20                     ` Laurent Pinchart
@ 2014-07-16 13:44                       ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-16 13:44 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

On Wed, 16 Jul 2014 15:20:59 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Wednesday 16 July 2014 15:05:22 Boris BREZILLON wrote:
> > On Tue, 15 Jul 2014 13:07:58 +0200 Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> > >> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > >>> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > >>>> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > >>>>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >>>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides
> > >>>>>>>> a display controller device.
> > >>>>>>>> 
> > >>>>>>>> The HLCDC block provides a single RGB output port, and only
> > >>>>>>>> supports LCD panels connection to LCD panels for now.
> > >>>>>>>> 
> > >>>>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>>>>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>>>>>> implementation makes use of the DRM panel framework).
> > >>>>>>>> 
> > >>>>>>>> Connection to other external devices (DRM bridges) might be added
> > >>>>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>>>>>> 
> > >>>>>>>> Signed-off-by: Boris BREZILLON
> > >>>>>>>> <boris.brezillon@free-electrons.com>
> > >>>>>>>> ---
> > >>>>>>>> 
> > >>>>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++
> > >>>>>>>>  1 file changed, 59 insertions(+)
> > >>>>>>>>  create mode 100644
> > >>>>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > >>>>> 
> > >>>>> [snip]
> > >>>>> 
> > >>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>>> following values:
> > >>>>>>>> +   * 0: RGB444
> > >>>>>>>> +   * 1: RGB565
> > >>>>>>>> +   * 2: RGB666
> > >>>>>>>> +   * 3: RGB888
> > >>>>>>> 
> > >>>>>>> These are properties of the panel and should be obtained from the
> > >>>>>>> panel directly rather than an additional cell in this specifier.
> > >>>>>> 
> > >>>>>> Okay.
> > >>>>>> What's the preferred way of doing this ?
> > >>>>>> What about defining an rgb-mode property in the panel node.
> > >>>>> 
> > >>>>> You could do that, but it won't help you much, as the HLCDC driver
> > >>>>> must not parse properties from the panel node. You should instead
> > >>>>> extend the drm_panel API with a function to retrieve panel
> > >>>>> properties. The HLCDC driver will then query the panel driver at
> > >>>>> runtime for the interface type. The panel driver will get the
> > >>>>> information from hardcoded data in the driver, from DT or possibly
> > >>>>> in some cases by querying the panel hardware directly.
> > >>>> 
> > >>>> My preference for this would be that we either add this to some
> > >>>> existing structure (struct drm_display_info seems like a good
> > >>>> candidate) or if the number of parameters grows out of hands, then
> > >>>> maybe even introduce a new type of device that's specific for the
> > >>>> interface. DRM panels are an abstraction for panels, that is,
> > >>>> interface-agnostic, and if we start exposing interface specific
> > >>>> parameters things will start to become very unwieldy.
> > >>> 
> > >>> I agree with the goal of keeping drm_panel interface-agnostic.
> > >>> However, one way or another, interface parameters will need to be
> > >>> communicated between the panel driver and the controller driver. My
> > >>> preference, if we need to extend the number and/or scope of parameters
> > >>> beyond what drm_display_info could reasonably contain, would be to
> > >>> implement a new drm_panel operation to query/configure interface
> > >>> parameters, using a structure that contains the interface type and a
> > >>> union of type-specific structures. This would keep the API generic in
> > >>> the sense of not requiring explicit knowledge of all interfaces in the
> > >>> drivers, while offering the flexibility we need with a way to easily
> > >>> detect the interface type at runtime and react on unknown/unsupported
> > >>> types.
> > >> 
> > >> That's exactly what I was hoping could be avoided. If instead we modeled
> > >> the interface type as a bus, we could for example have an lvds_bus along
> > >> with an lvds_device and then use that as the natural place to store
> > >> these properties. Much like we do for DSI.
> > > 
> > > And I believe that's what we should avoid ;-) First of all, let's not
> > > forget that Linux models control busses, not data busses. DSI is a
> > > special case as it combines the control and data busses, but in the
> > > general case the same implementation isn't possible. An LVDS panel
> > > controlled through I2C needs to be an I2C device sitting on an I2C bus.
> > > 
> > > Then, I believe it would make all drivers simpler if we had a single
> > > object type to deal with, with proper abstractions for bus types. A
> > > drm_panel that can model panels regardless of the data bus type, with one
> > > operation that conveys bus-specific information, makes storing the objects
> > > and communicating with them simpler than having to deal with different
> > > kind of devices.
> >
> > Could you detail a bit what you mean by "single object type" ?
> > 
> > Is this about making a common abstraction class (by mean of
> > drm_xxx and drm_xxx_funcs) that could represent any display device
> > (drm_bridge, drm_panel, ...) ?
> 
> Exactly :-) This is similar to what exists in V4L, with a v4l2_subdev object 
> able to model any kind of IP core or external chip.
> 
> I don't think we will get there in one go, but I'd like to start by merging 
> drm_encoder and drm_bridge on the kernel side. Both objects model the same 
> hardware, a drm_encoder on one board could be a drm_bridge on another one. 
> From a userspace point of view drm_encoder won't go away, and we can't chain 
> multiple encoders, so the change would be internal to the kernel only.
> 
> Then, as a next step, I believe using the same object to model panels would be 
> a good idea, but there's no consensus on that.
> 

I would be happy to help with that, but AFAICT, this is a huge work and
I'd like to get the HLCDC driver merged first ;-).

How about defining what DT bindings should look like (for the RGB/LVDS
output mode), and parsing this in atmel-hlcdc driver as a first step ?

Then we can define proper RGB/LVDS helper functions and the whole
drm_subdev abstraction you were talking about, and move the atmel-hlcdc
driver to this solution when it's ready.

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-16 13:44                       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-16 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 16 Jul 2014 15:20:59 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Wednesday 16 July 2014 15:05:22 Boris BREZILLON wrote:
> > On Tue, 15 Jul 2014 13:07:58 +0200 Laurent Pinchart wrote:
> > > On Tuesday 15 July 2014 12:52:54 Thierry Reding wrote:
> > >> On Tue, Jul 15, 2014 at 12:43:02PM +0200, Laurent Pinchart wrote:
> > >>> On Tuesday 15 July 2014 12:37:19 Thierry Reding wrote:
> > >>>> On Tue, Jul 15, 2014 at 12:20:02PM +0200, Laurent Pinchart wrote:
> > >>>>> On Tuesday 15 July 2014 12:06:19 Boris BREZILLON wrote:
> > >>>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > >>>>>>>> The Atmel HLCDC (HLCD Controller) IP available on some Atmel SoCs
> > >>>>>>>> (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family) provides
> > >>>>>>>> a display controller device.
> > >>>>>>>> 
> > >>>>>>>> The HLCDC block provides a single RGB output port, and only
> > >>>>>>>> supports LCD panels connection to LCD panels for now.
> > >>>>>>>> 
> > >>>>>>>> The atmel,panel property link the HLCDC RGB output with the LCD
> > >>>>>>>> panel connected on this port (note that the HLCDC RGB connector
> > >>>>>>>> implementation makes use of the DRM panel framework).
> > >>>>>>>> 
> > >>>>>>>> Connection to other external devices (DRM bridges) might be added
> > >>>>>>>> later by mean of a new atmel,xxx (atmel,bridge) property.
> > >>>>>>>> 
> > >>>>>>>> Signed-off-by: Boris BREZILLON
> > >>>>>>>> <boris.brezillon@free-electrons.com>
> > >>>>>>>> ---
> > >>>>>>>> 
> > >>>>>>>>  .../devicetree/bindings/drm/atmel-hlcdc-dc.txt     | 59 ++++++++
> > >>>>>>>>  1 file changed, 59 insertions(+)
> > >>>>>>>>  create mode 100644
> > >>>>>>>>  Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > >>>>> 
> > >>>>> [snip]
> > >>>>> 
> > >>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>>> following values:
> > >>>>>>>> +   * 0: RGB444
> > >>>>>>>> +   * 1: RGB565
> > >>>>>>>> +   * 2: RGB666
> > >>>>>>>> +   * 3: RGB888
> > >>>>>>> 
> > >>>>>>> These are properties of the panel and should be obtained from the
> > >>>>>>> panel directly rather than an additional cell in this specifier.
> > >>>>>> 
> > >>>>>> Okay.
> > >>>>>> What's the preferred way of doing this ?
> > >>>>>> What about defining an rgb-mode property in the panel node.
> > >>>>> 
> > >>>>> You could do that, but it won't help you much, as the HLCDC driver
> > >>>>> must not parse properties from the panel node. You should instead
> > >>>>> extend the drm_panel API with a function to retrieve panel
> > >>>>> properties. The HLCDC driver will then query the panel driver at
> > >>>>> runtime for the interface type. The panel driver will get the
> > >>>>> information from hardcoded data in the driver, from DT or possibly
> > >>>>> in some cases by querying the panel hardware directly.
> > >>>> 
> > >>>> My preference for this would be that we either add this to some
> > >>>> existing structure (struct drm_display_info seems like a good
> > >>>> candidate) or if the number of parameters grows out of hands, then
> > >>>> maybe even introduce a new type of device that's specific for the
> > >>>> interface. DRM panels are an abstraction for panels, that is,
> > >>>> interface-agnostic, and if we start exposing interface specific
> > >>>> parameters things will start to become very unwieldy.
> > >>> 
> > >>> I agree with the goal of keeping drm_panel interface-agnostic.
> > >>> However, one way or another, interface parameters will need to be
> > >>> communicated between the panel driver and the controller driver. My
> > >>> preference, if we need to extend the number and/or scope of parameters
> > >>> beyond what drm_display_info could reasonably contain, would be to
> > >>> implement a new drm_panel operation to query/configure interface
> > >>> parameters, using a structure that contains the interface type and a
> > >>> union of type-specific structures. This would keep the API generic in
> > >>> the sense of not requiring explicit knowledge of all interfaces in the
> > >>> drivers, while offering the flexibility we need with a way to easily
> > >>> detect the interface type at runtime and react on unknown/unsupported
> > >>> types.
> > >> 
> > >> That's exactly what I was hoping could be avoided. If instead we modeled
> > >> the interface type as a bus, we could for example have an lvds_bus along
> > >> with an lvds_device and then use that as the natural place to store
> > >> these properties. Much like we do for DSI.
> > > 
> > > And I believe that's what we should avoid ;-) First of all, let's not
> > > forget that Linux models control busses, not data busses. DSI is a
> > > special case as it combines the control and data busses, but in the
> > > general case the same implementation isn't possible. An LVDS panel
> > > controlled through I2C needs to be an I2C device sitting on an I2C bus.
> > > 
> > > Then, I believe it would make all drivers simpler if we had a single
> > > object type to deal with, with proper abstractions for bus types. A
> > > drm_panel that can model panels regardless of the data bus type, with one
> > > operation that conveys bus-specific information, makes storing the objects
> > > and communicating with them simpler than having to deal with different
> > > kind of devices.
> >
> > Could you detail a bit what you mean by "single object type" ?
> > 
> > Is this about making a common abstraction class (by mean of
> > drm_xxx and drm_xxx_funcs) that could represent any display device
> > (drm_bridge, drm_panel, ...) ?
> 
> Exactly :-) This is similar to what exists in V4L, with a v4l2_subdev object 
> able to model any kind of IP core or external chip.
> 
> I don't think we will get there in one go, but I'd like to start by merging 
> drm_encoder and drm_bridge on the kernel side. Both objects model the same 
> hardware, a drm_encoder on one board could be a drm_bridge on another one. 
> From a userspace point of view drm_encoder won't go away, and we can't chain 
> multiple encoders, so the change would be internal to the kernel only.
> 
> Then, as a next step, I believe using the same object to model panels would be 
> a good idea, but there's no consensus on that.
> 

I would be happy to help with that, but AFAICT, this is a huge work and
I'd like to get the HLCDC driver merged first ;-).

How about defining what DT bindings should look like (for the RGB/LVDS
output mode), and parsing this in atmel-hlcdc driver as a first step ?

Then we can define proper RGB/LVDS helper functions and the whole
drm_subdev abstraction you were talking about, and move the atmel-hlcdc
driver to this solution when it's ready.

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-15 10:31         ` Thierry Reding
@ 2014-07-18 14:51           ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-18 14:51 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Samuel Ortiz, Lee Jones, linux-pwm, David Airlie, dri-devel,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Laurent Pinchart, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Bo Shen, Thomas Petazzoni,
	linux-arm-kernel, Robert Nelson, Tim Niemeyer

Hi Thierry,

Oops, I missed this reply.

On Tue, 15 Jul 2014 12:31:37 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> [...]
> > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > [...]
> > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > 
> > > I think it's better to refer to these using relative filenames. When the
> > > device tree bindings are moved out of the kernel tree, they may no
> > > longer use the same hierarchy.
> > 
> > Sure.
> > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > mfd/atmel-hlcdc.txt ?
> 
> I think the former is more explicit.

Okay.

> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > 
> > > These are properties of the panel and should be obtained from the panel
> > > directly rather than an additional cell in this specifier.
> > 
> > Okay.
> > What's the preferred way of doing this ?
> > What about defining an rgb-mode property in the panel node.
> 
> There's .bpc in struct drm_display_info, I suspect that it could be used
> for this. Alternatively, maybe we could extend the list of color formats
> that go into drm_display_info.color_formats? RGB444 is already covered.

I don't think this color_formats field is intended to represent data
stream format going through the bus.
Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
subsampling rate) and not 12 bits signals (4 bits for each color).

Anyway I'll propose a patch series adding a new field to
drm_display_info to encode the mediabus format (as discussed with
Laurent and you).

> 
> Also, like Laurent said, this shouldn't go into the device tree, since
> it's already implied by the panel's compatible value, so we'd be
> duplicating information.

Again, this is not necessarily true (depending on your board design).
One can decide to connect an RGB888 panel on an RGB666 bus and connect
the missing pins to ground.

> 
> > BTW, have you received this series [1] adding support for the LCD panel
> > I'm testing this driver with.
> > 
> > [1] https://lkml.org/lkml/2014/6/5/612
> 
> I don't think I've seen it in my inbox, let me check my archives.
> 
> > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > 
> > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > vsync_end of the same structure.
> > 
> > I agree with HSPOL and VSPOL.
> > 
> > > 
> > > As for the others, maybe if you could explain what exactly they are we
> > > may be able to find a better fit.
> > 
> > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > Output Timing Generation" page 603), and I think you will get more
> > informations from these diagrams than if I try to explain what I
> > understood ;-).
> 
> These look like knobs to tune the signal in a very fine-grained manner.
> To be honest, maybe the best way to solve this would be by omitting them
> for now and choose some default that's likely to work on most devices.
> Does the panel that you use specify how it expects HSYNC to be timed vs.
> VSYNC?


No it doesn't, and I agree that we should leave these specific timing
tweaks unimplemented until we really need them.

Regards,

Boris


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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-18 14:51           ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-18 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

Oops, I missed this reply.

On Tue, 15 Jul 2014 12:31:37 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> [...]
> > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > [...]
> > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > 
> > > I think it's better to refer to these using relative filenames. When the
> > > device tree bindings are moved out of the kernel tree, they may no
> > > longer use the same hierarchy.
> > 
> > Sure.
> > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > mfd/atmel-hlcdc.txt ?
> 
> I think the former is more explicit.

Okay.

> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > 
> > > These are properties of the panel and should be obtained from the panel
> > > directly rather than an additional cell in this specifier.
> > 
> > Okay.
> > What's the preferred way of doing this ?
> > What about defining an rgb-mode property in the panel node.
> 
> There's .bpc in struct drm_display_info, I suspect that it could be used
> for this. Alternatively, maybe we could extend the list of color formats
> that go into drm_display_info.color_formats? RGB444 is already covered.

I don't think this color_formats field is intended to represent data
stream format going through the bus.
Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
subsampling rate) and not 12 bits signals (4 bits for each color).

Anyway I'll propose a patch series adding a new field to
drm_display_info to encode the mediabus format (as discussed with
Laurent and you).

> 
> Also, like Laurent said, this shouldn't go into the device tree, since
> it's already implied by the panel's compatible value, so we'd be
> duplicating information.

Again, this is not necessarily true (depending on your board design).
One can decide to connect an RGB888 panel on an RGB666 bus and connect
the missing pins to ground.

> 
> > BTW, have you received this series [1] adding support for the LCD panel
> > I'm testing this driver with.
> > 
> > [1] https://lkml.org/lkml/2014/6/5/612
> 
> I don't think I've seen it in my inbox, let me check my archives.
> 
> > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > 
> > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > vsync_end of the same structure.
> > 
> > I agree with HSPOL and VSPOL.
> > 
> > > 
> > > As for the others, maybe if you could explain what exactly they are we
> > > may be able to find a better fit.
> > 
> > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > Output Timing Generation" page 603), and I think you will get more
> > informations from these diagrams than if I try to explain what I
> > understood ;-).
> 
> These look like knobs to tune the signal in a very fine-grained manner.
> To be honest, maybe the best way to solve this would be by omitting them
> for now and choose some default that's likely to work on most devices.
> Does the panel that you use specify how it expects HSYNC to be timed vs.
> VSYNC?


No it doesn't, and I agree that we should leave these specific timing
tweaks unimplemented until we really need them.

Regards,

Boris


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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-18 14:51           ` Boris BREZILLON
@ 2014-07-18 15:43             ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-18 15:43 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Thierry Reding, Samuel Ortiz, Lee Jones, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Laurent Pinchart, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Bo Shen, Thomas Petazzoni,
	linux-arm-kernel, Robert Nelson

On Fri, 18 Jul 2014 16:51:52 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> Hi Thierry,
> 
> Oops, I missed this reply.
> 
> On Tue, 15 Jul 2014 12:31:37 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > [...]
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > [...]
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > 
> > > > I think it's better to refer to these using relative filenames. When the
> > > > device tree bindings are moved out of the kernel tree, they may no
> > > > longer use the same hierarchy.
> > > 
> > > Sure.
> > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > mfd/atmel-hlcdc.txt ?
> > 
> > I think the former is more explicit.
> 
> Okay.
> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > 
> > > > These are properties of the panel and should be obtained from the panel
> > > > directly rather than an additional cell in this specifier.
> > > 
> > > Okay.
> > > What's the preferred way of doing this ?
> > > What about defining an rgb-mode property in the panel node.
> > 
> > There's .bpc in struct drm_display_info, I suspect that it could be used
> > for this. Alternatively, maybe we could extend the list of color formats
> > that go into drm_display_info.color_formats? RGB444 is already covered.
> 

I forgot to ask about bpc meaning. If, as I think, it means "bits per
color" then it cannot be used to encode RGB565 where green color is
encoded on 6 bits and red and blue are encoded on 5 bits. 

> I don't think this color_formats field is intended to represent data
> stream format going through the bus.
> Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> subsampling rate) and not 12 bits signals (4 bits for each color).
> 
> Anyway I'll propose a patch series adding a new field to
> drm_display_info to encode the mediabus format (as discussed with
> Laurent and you).
> 
> > 
> > Also, like Laurent said, this shouldn't go into the device tree, since
> > it's already implied by the panel's compatible value, so we'd be
> > duplicating information.
> 
> Again, this is not necessarily true (depending on your board design).
> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> the missing pins to ground.
> 
> > 
> > > BTW, have you received this series [1] adding support for the LCD panel
> > > I'm testing this driver with.
> > > 
> > > [1] https://lkml.org/lkml/2014/6/5/612
> > 
> > I don't think I've seen it in my inbox, let me check my archives.
> > 
> > > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > > 
> > > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > > vsync_end of the same structure.
> > > 
> > > I agree with HSPOL and VSPOL.
> > > 
> > > > 
> > > > As for the others, maybe if you could explain what exactly they are we
> > > > may be able to find a better fit.
> > > 
> > > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > > Output Timing Generation" page 603), and I think you will get more
> > > informations from these diagrams than if I try to explain what I
> > > understood ;-).
> > 
> > These look like knobs to tune the signal in a very fine-grained manner.
> > To be honest, maybe the best way to solve this would be by omitting them
> > for now and choose some default that's likely to work on most devices.
> > Does the panel that you use specify how it expects HSYNC to be timed vs.
> > VSYNC?
> 
> 
> No it doesn't, and I agree that we should leave these specific timing
> tweaks unimplemented until we really need them.
> 
> Regards,
> 
> Boris
> 
> 



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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-18 15:43             ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-18 15:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 18 Jul 2014 16:51:52 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> Hi Thierry,
> 
> Oops, I missed this reply.
> 
> On Tue, 15 Jul 2014 12:31:37 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > [...]
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > [...]
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > 
> > > > I think it's better to refer to these using relative filenames. When the
> > > > device tree bindings are moved out of the kernel tree, they may no
> > > > longer use the same hierarchy.
> > > 
> > > Sure.
> > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > mfd/atmel-hlcdc.txt ?
> > 
> > I think the former is more explicit.
> 
> Okay.
> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > 
> > > > These are properties of the panel and should be obtained from the panel
> > > > directly rather than an additional cell in this specifier.
> > > 
> > > Okay.
> > > What's the preferred way of doing this ?
> > > What about defining an rgb-mode property in the panel node.
> > 
> > There's .bpc in struct drm_display_info, I suspect that it could be used
> > for this. Alternatively, maybe we could extend the list of color formats
> > that go into drm_display_info.color_formats? RGB444 is already covered.
> 

I forgot to ask about bpc meaning. If, as I think, it means "bits per
color" then it cannot be used to encode RGB565 where green color is
encoded on 6 bits and red and blue are encoded on 5 bits. 

> I don't think this color_formats field is intended to represent data
> stream format going through the bus.
> Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> subsampling rate) and not 12 bits signals (4 bits for each color).
> 
> Anyway I'll propose a patch series adding a new field to
> drm_display_info to encode the mediabus format (as discussed with
> Laurent and you).
> 
> > 
> > Also, like Laurent said, this shouldn't go into the device tree, since
> > it's already implied by the panel's compatible value, so we'd be
> > duplicating information.
> 
> Again, this is not necessarily true (depending on your board design).
> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> the missing pins to ground.
> 
> > 
> > > BTW, have you received this series [1] adding support for the LCD panel
> > > I'm testing this driver with.
> > > 
> > > [1] https://lkml.org/lkml/2014/6/5/612
> > 
> > I don't think I've seen it in my inbox, let me check my archives.
> > 
> > > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > > 
> > > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > > vsync_end of the same structure.
> > > 
> > > I agree with HSPOL and VSPOL.
> > > 
> > > > 
> > > > As for the others, maybe if you could explain what exactly they are we
> > > > may be able to find a better fit.
> > > 
> > > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > > Output Timing Generation" page 603), and I think you will get more
> > > informations from these diagrams than if I try to explain what I
> > > understood ;-).
> > 
> > These look like knobs to tune the signal in a very fine-grained manner.
> > To be honest, maybe the best way to solve this would be by omitting them
> > for now and choose some default that's likely to work on most devices.
> > Does the panel that you use specify how it expects HSYNC to be timed vs.
> > VSYNC?
> 
> 
> No it doesn't, and I agree that we should leave these specific timing
> tweaks unimplemented until we really need them.
> 
> Regards,
> 
> Boris
> 
> 



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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-18 15:43             ` Boris BREZILLON
@ 2014-07-21  8:59               ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21  8:59 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Samuel Ortiz, Lee Jones, linux-pwm, David Airlie, dri-devel,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Laurent Pinchart, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Bo Shen, Thomas Petazzoni,
	linux-arm-kernel, Robert Nelson, Tim Niemeyer

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

On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
[...]
> > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > +   * 0: RGB444
> > > > > > +   * 1: RGB565
> > > > > > +   * 2: RGB666
> > > > > > +   * 3: RGB888
> > > > > 
> > > > > These are properties of the panel and should be obtained from the panel
> > > > > directly rather than an additional cell in this specifier.
> > > > 
> > > > Okay.
> > > > What's the preferred way of doing this ?
> > > > What about defining an rgb-mode property in the panel node.
> > > 
> > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > for this. Alternatively, maybe we could extend the list of color formats
> > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > 
> 
> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> color" then it cannot be used to encode RGB565 where green color is
> encoded on 6 bits and red and blue are encoded on 5 bits. 

Yes, I agree that bps is not a good fit for what you need here.

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21  8:59               ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21  8:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
[...]
> > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > +   * 0: RGB444
> > > > > > +   * 1: RGB565
> > > > > > +   * 2: RGB666
> > > > > > +   * 3: RGB888
> > > > > 
> > > > > These are properties of the panel and should be obtained from the panel
> > > > > directly rather than an additional cell in this specifier.
> > > > 
> > > > Okay.
> > > > What's the preferred way of doing this ?
> > > > What about defining an rgb-mode property in the panel node.
> > > 
> > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > for this. Alternatively, maybe we could extend the list of color formats
> > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > 
> 
> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> color" then it cannot be used to encode RGB565 where green color is
> encoded on 6 bits and red and blue are encoded on 5 bits. 

Yes, I agree that bps is not a good fit for what you need here.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/afb8110f/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21  8:59               ` Thierry Reding
@ 2014-07-21  9:24                 ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21  9:24 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

On Mon, 21 Jul 2014 10:59:12 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> [...]
> > > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > > +   * 0: RGB444
> > > > > > > +   * 1: RGB565
> > > > > > > +   * 2: RGB666
> > > > > > > +   * 3: RGB888
> > > > > > 
> > > > > > These are properties of the panel and should be obtained from the panel
> > > > > > directly rather than an additional cell in this specifier.
> > > > > 
> > > > > Okay.
> > > > > What's the preferred way of doing this ?
> > > > > What about defining an rgb-mode property in the panel node.
> > > > 
> > > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > > for this. Alternatively, maybe we could extend the list of color formats
> > > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > > 
> > 
> > I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > color" then it cannot be used to encode RGB565 where green color is
> > encoded on 6 bits and red and blue are encoded on 5 bits. 
> 
> Yes, I agree that bps is not a good fit for what you need here.

Okay, then I think we can replace bpc and color_formats by a bus_formats
table containing all supported formats, and use an enum (something
similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
the available formats.

As this implies quite a few changes in crtc core and some drm drivers
(nouveau, i915 and radeon), I'd like to be sure this is what both of you
had in mind.

Best Regards,

Boris

[1]http://lxr.free-electrons.com/source/include/uapi/linux/v4l2-mediabus.h#L37

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21  9:24                 ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21  9:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 10:59:12 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> [...]
> > > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > > +   * 0: RGB444
> > > > > > > +   * 1: RGB565
> > > > > > > +   * 2: RGB666
> > > > > > > +   * 3: RGB888
> > > > > > 
> > > > > > These are properties of the panel and should be obtained from the panel
> > > > > > directly rather than an additional cell in this specifier.
> > > > > 
> > > > > Okay.
> > > > > What's the preferred way of doing this ?
> > > > > What about defining an rgb-mode property in the panel node.
> > > > 
> > > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > > for this. Alternatively, maybe we could extend the list of color formats
> > > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > > 
> > 
> > I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > color" then it cannot be used to encode RGB565 where green color is
> > encoded on 6 bits and red and blue are encoded on 5 bits. 
> 
> Yes, I agree that bps is not a good fit for what you need here.

Okay, then I think we can replace bpc and color_formats by a bus_formats
table containing all supported formats, and use an enum (something
similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
the available formats.

As this implies quite a few changes in crtc core and some drm drivers
(nouveau, i915 and radeon), I'd like to be sure this is what both of you
had in mind.

Best Regards,

Boris

[1]http://lxr.free-electrons.com/source/include/uapi/linux/v4l2-mediabus.h#L37

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21  9:24                 ` Boris BREZILLON
@ 2014-07-21  9:32                   ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21  9:32 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Boris,

On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > [...]
> > 
> >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>> following values:
> >>>>>>> +   * 0: RGB444
> >>>>>>> +   * 1: RGB565
> >>>>>>> +   * 2: RGB666
> >>>>>>> +   * 3: RGB888
> >>>>>> 
> >>>>>> These are properties of the panel and should be obtained from
> >>>>>> the panel directly rather than an additional cell in this specifier.
> >>>>> 
> >>>>> Okay.
> >>>>> What's the preferred way of doing this ?
> >>>>> What about defining an rgb-mode property in the panel node.
> >>>> 
> >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> >>>> used for this. Alternatively, maybe we could extend the list of color
> >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> >>>> covered.
> >> 
> >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> >> color" then it cannot be used to encode RGB565 where green color is
> >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > 
> > Yes, I agree that bps is not a good fit for what you need here.
> 
> Okay, then I think we can replace bpc and color_formats by a bus_formats
> table containing all supported formats, and use an enum (something
> similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> the available formats.
> 
> As this implies quite a few changes in crtc core and some drm drivers
> (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> had in mind.

I think it is, but just to make sure I understand you correctly, could you 
just show how the drm_display_info structure would look like ?

-- 
Regards,

Laurent Pinchart

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21  9:32                   ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21  9:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > [...]
> > 
> >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>> following values:
> >>>>>>> +   * 0: RGB444
> >>>>>>> +   * 1: RGB565
> >>>>>>> +   * 2: RGB666
> >>>>>>> +   * 3: RGB888
> >>>>>> 
> >>>>>> These are properties of the panel and should be obtained from
> >>>>>> the panel directly rather than an additional cell in this specifier.
> >>>>> 
> >>>>> Okay.
> >>>>> What's the preferred way of doing this ?
> >>>>> What about defining an rgb-mode property in the panel node.
> >>>> 
> >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> >>>> used for this. Alternatively, maybe we could extend the list of color
> >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> >>>> covered.
> >> 
> >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> >> color" then it cannot be used to encode RGB565 where green color is
> >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > 
> > Yes, I agree that bps is not a good fit for what you need here.
> 
> Okay, then I think we can replace bpc and color_formats by a bus_formats
> table containing all supported formats, and use an enum (something
> similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> the available formats.
> 
> As this implies quite a few changes in crtc core and some drm drivers
> (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> had in mind.

I think it is, but just to make sure I understand you correctly, could you 
just show how the drm_display_info structure would look like ?

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21  9:32                   ` Laurent Pinchart
@ 2014-07-21  9:57                     ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21  9:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

On Mon, 21 Jul 2014 11:32:55 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > [...]
> > > 
> > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>> following values:
> > >>>>>>> +   * 0: RGB444
> > >>>>>>> +   * 1: RGB565
> > >>>>>>> +   * 2: RGB666
> > >>>>>>> +   * 3: RGB888
> > >>>>>> 
> > >>>>>> These are properties of the panel and should be obtained from
> > >>>>>> the panel directly rather than an additional cell in this specifier.
> > >>>>> 
> > >>>>> Okay.
> > >>>>> What's the preferred way of doing this ?
> > >>>>> What about defining an rgb-mode property in the panel node.
> > >>>> 
> > >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> > >>>> used for this. Alternatively, maybe we could extend the list of color
> > >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> > >>>> covered.
> > >> 
> > >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > >> color" then it cannot be used to encode RGB565 where green color is
> > >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > > 
> > > Yes, I agree that bps is not a good fit for what you need here.
> > 
> > Okay, then I think we can replace bpc and color_formats by a bus_formats
> > table containing all supported formats, and use an enum (something
> > similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> > the available formats.
> > 
> > As this implies quite a few changes in crtc core and some drm drivers
> > (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> > had in mind.
> 
> I think it is, but just to make sure I understand you correctly, could you 
> just show how the drm_display_info structure would look like ?
> 

The new drm_display_info structure should look like this [2] (except
that color_formats and bpc have not be removed yet), and [1] is just
here to show how the video_bus_format enum would look like.

[1] http://code.bulix.org/rfd0yx-86557
[2] http://code.bulix.org/7n03b4-86556



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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21  9:57                     ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21  9:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 11:32:55 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > [...]
> > > 
> > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>> following values:
> > >>>>>>> +   * 0: RGB444
> > >>>>>>> +   * 1: RGB565
> > >>>>>>> +   * 2: RGB666
> > >>>>>>> +   * 3: RGB888
> > >>>>>> 
> > >>>>>> These are properties of the panel and should be obtained from
> > >>>>>> the panel directly rather than an additional cell in this specifier.
> > >>>>> 
> > >>>>> Okay.
> > >>>>> What's the preferred way of doing this ?
> > >>>>> What about defining an rgb-mode property in the panel node.
> > >>>> 
> > >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> > >>>> used for this. Alternatively, maybe we could extend the list of color
> > >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> > >>>> covered.
> > >> 
> > >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > >> color" then it cannot be used to encode RGB565 where green color is
> > >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > > 
> > > Yes, I agree that bps is not a good fit for what you need here.
> > 
> > Okay, then I think we can replace bpc and color_formats by a bus_formats
> > table containing all supported formats, and use an enum (something
> > similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> > the available formats.
> > 
> > As this implies quite a few changes in crtc core and some drm drivers
> > (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> > had in mind.
> 
> I think it is, but just to make sure I understand you correctly, could you 
> just show how the drm_display_info structure would look like ?
> 

The new drm_display_info structure should look like this [2] (except
that color_formats and bpc have not be removed yet), and [1] is just
here to show how the video_bus_format enum would look like.

[1] http://code.bulix.org/rfd0yx-86557
[2] http://code.bulix.org/7n03b4-86556



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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21  9:57                     ` Boris BREZILLON
@ 2014-07-21 12:12                       ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:12 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Laurent Pinchart, Samuel Ortiz, Lee Jones, linux-pwm,
	David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer

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

On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 11:32:55 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Boris,
> > 
> > On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > > [...]
> > > > 
> > > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>>>>> following values:
> > > >>>>>>> +   * 0: RGB444
> > > >>>>>>> +   * 1: RGB565
> > > >>>>>>> +   * 2: RGB666
> > > >>>>>>> +   * 3: RGB888
> > > >>>>>> 
> > > >>>>>> These are properties of the panel and should be obtained from
> > > >>>>>> the panel directly rather than an additional cell in this specifier.
> > > >>>>> 
> > > >>>>> Okay.
> > > >>>>> What's the preferred way of doing this ?
> > > >>>>> What about defining an rgb-mode property in the panel node.
> > > >>>> 
> > > >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> > > >>>> used for this. Alternatively, maybe we could extend the list of color
> > > >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> > > >>>> covered.
> > > >> 
> > > >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > > >> color" then it cannot be used to encode RGB565 where green color is
> > > >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > > > 
> > > > Yes, I agree that bps is not a good fit for what you need here.
> > > 
> > > Okay, then I think we can replace bpc and color_formats by a bus_formats
> > > table containing all supported formats, and use an enum (something
> > > similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> > > the available formats.
> > > 
> > > As this implies quite a few changes in crtc core and some drm drivers
> > > (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> > > had in mind.
> > 
> > I think it is, but just to make sure I understand you correctly, could you 
> > just show how the drm_display_info structure would look like ?
> > 
> 
> The new drm_display_info structure should look like this [2] (except
> that color_formats and bpc have not be removed yet), and [1] is just
> here to show how the video_bus_format enum would look like.
> 
> [1] http://code.bulix.org/rfd0yx-86557
> [2] http://code.bulix.org/7n03b4-86556

Quoting from your paste:

	+   const enum video_bus_format *bus_formats;
	+   int nbus_formats;

Do we really need more than one?

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:12                       ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 11:32:55 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Boris,
> > 
> > On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > > On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > > [...]
> > > > 
> > > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>>>>> following values:
> > > >>>>>>> +   * 0: RGB444
> > > >>>>>>> +   * 1: RGB565
> > > >>>>>>> +   * 2: RGB666
> > > >>>>>>> +   * 3: RGB888
> > > >>>>>> 
> > > >>>>>> These are properties of the panel and should be obtained from
> > > >>>>>> the panel directly rather than an additional cell in this specifier.
> > > >>>>> 
> > > >>>>> Okay.
> > > >>>>> What's the preferred way of doing this ?
> > > >>>>> What about defining an rgb-mode property in the panel node.
> > > >>>> 
> > > >>>> There's .bpc in struct drm_display_info, I suspect that it could be
> > > >>>> used for this. Alternatively, maybe we could extend the list of color
> > > >>>> formats that go into drm_display_info.color_formats? RGB444 is already
> > > >>>> covered.
> > > >> 
> > > >> I forgot to ask about bpc meaning. If, as I think, it means "bits per
> > > >> color" then it cannot be used to encode RGB565 where green color is
> > > >> encoded on 6 bits and red and blue are encoded on 5 bits.
> > > > 
> > > > Yes, I agree that bps is not a good fit for what you need here.
> > > 
> > > Okay, then I think we can replace bpc and color_formats by a bus_formats
> > > table containing all supported formats, and use an enum (something
> > > similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h [1]) to list
> > > the available formats.
> > > 
> > > As this implies quite a few changes in crtc core and some drm drivers
> > > (nouveau, i915 and radeon), I'd like to be sure this is what both of you
> > > had in mind.
> > 
> > I think it is, but just to make sure I understand you correctly, could you 
> > just show how the drm_display_info structure would look like ?
> > 
> 
> The new drm_display_info structure should look like this [2] (except
> that color_formats and bpc have not be removed yet), and [1] is just
> here to show how the video_bus_format enum would look like.
> 
> [1] http://code.bulix.org/rfd0yx-86557
> [2] http://code.bulix.org/7n03b4-86556

Quoting from your paste:

	+   const enum video_bus_format *bus_formats;
	+   int nbus_formats;

Do we really need more than one?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/309fb551/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-18 14:51           ` Boris BREZILLON
@ 2014-07-21 12:15             ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:15 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3069 bytes --]

On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> Hi Thierry,
> 
> Oops, I missed this reply.
> 
> On Tue, 15 Jul 2014 12:31:37 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > [...]
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > [...]
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > 
> > > > I think it's better to refer to these using relative filenames. When the
> > > > device tree bindings are moved out of the kernel tree, they may no
> > > > longer use the same hierarchy.
> > > 
> > > Sure.
> > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > mfd/atmel-hlcdc.txt ?
> > 
> > I think the former is more explicit.
> 
> Okay.
> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > 
> > > > These are properties of the panel and should be obtained from the panel
> > > > directly rather than an additional cell in this specifier.
> > > 
> > > Okay.
> > > What's the preferred way of doing this ?
> > > What about defining an rgb-mode property in the panel node.
> > 
> > There's .bpc in struct drm_display_info, I suspect that it could be used
> > for this. Alternatively, maybe we could extend the list of color formats
> > that go into drm_display_info.color_formats? RGB444 is already covered.
> 
> I don't think this color_formats field is intended to represent data
> stream format going through the bus.
> Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> subsampling rate) and not 12 bits signals (4 bits for each color).
> 
> Anyway I'll propose a patch series adding a new field to
> drm_display_info to encode the mediabus format (as discussed with
> Laurent and you).
> 
> > 
> > Also, like Laurent said, this shouldn't go into the device tree, since
> > it's already implied by the panel's compatible value, so we'd be
> > duplicating information.
> 
> Again, this is not necessarily true (depending on your board design).
> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> the missing pins to ground.

I think in that case the board design itself could be considered as an
RGB888 to RGB666 bridge, and I think that's what the device tree should
be describing rather than a panel with a variable number of input
formats.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:15             ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> Hi Thierry,
> 
> Oops, I missed this reply.
> 
> On Tue, 15 Jul 2014 12:31:37 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > [...]
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > [...]
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > 
> > > > I think it's better to refer to these using relative filenames. When the
> > > > device tree bindings are moved out of the kernel tree, they may no
> > > > longer use the same hierarchy.
> > > 
> > > Sure.
> > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > mfd/atmel-hlcdc.txt ?
> > 
> > I think the former is more explicit.
> 
> Okay.
> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > 
> > > > These are properties of the panel and should be obtained from the panel
> > > > directly rather than an additional cell in this specifier.
> > > 
> > > Okay.
> > > What's the preferred way of doing this ?
> > > What about defining an rgb-mode property in the panel node.
> > 
> > There's .bpc in struct drm_display_info, I suspect that it could be used
> > for this. Alternatively, maybe we could extend the list of color formats
> > that go into drm_display_info.color_formats? RGB444 is already covered.
> 
> I don't think this color_formats field is intended to represent data
> stream format going through the bus.
> Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> subsampling rate) and not 12 bits signals (4 bits for each color).
> 
> Anyway I'll propose a patch series adding a new field to
> drm_display_info to encode the mediabus format (as discussed with
> Laurent and you).
> 
> > 
> > Also, like Laurent said, this shouldn't go into the device tree, since
> > it's already implied by the panel's compatible value, so we'd be
> > duplicating information.
> 
> Again, this is not necessarily true (depending on your board design).
> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> the missing pins to ground.

I think in that case the board design itself could be considered as an
RGB888 to RGB666 bridge, and I think that's what the device tree should
be describing rather than a panel with a variable number of input
formats.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/c0a93c42/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:12                       ` Thierry Reding
@ 2014-07-21 12:16                         ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 12:16 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 2900 bytes --]

Hi Thierry,

On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> >>>> [...]
> >>>> 
> >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>>>>> following values:
> >>>>>>>>>> +   * 0: RGB444
> >>>>>>>>>> +   * 1: RGB565
> >>>>>>>>>> +   * 2: RGB666
> >>>>>>>>>> +   * 3: RGB888
> >>>>>>>>> 
> >>>>>>>>> These are properties of the panel and should be obtained from
> >>>>>>>>> the panel directly rather than an additional cell in this
> >>>>>>>>> specifier.
> >>>>>>>> 
> >>>>>>>> Okay.
> >>>>>>>> What's the preferred way of doing this ?
> >>>>>>>> What about defining an rgb-mode property in the panel node.
> >>>>>>> 
> >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> >>>>>>> be used for this. Alternatively, maybe we could extend the list
> >>>>>>> of color formats that go into drm_display_info.color_formats?
> >>>>>>> RGB444 is already covered.
> >>>>> 
> >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> >>>>> per color" then it cannot be used to encode RGB565 where green
> >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> >>>> 
> >>>> Yes, I agree that bps is not a good fit for what you need here.
> >>> 
> >>> Okay, then I think we can replace bpc and color_formats by a
> >>> bus_formats table containing all supported formats, and use an enum
> >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> >>> [1]) to list the available formats.
> >>> 
> >>> As this implies quite a few changes in crtc core and some drm drivers
> >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> >>> you had in mind.
> >> 
> >> I think it is, but just to make sure I understand you correctly, could
> >> you just show how the drm_display_info structure would look like ?
> > 
> > The new drm_display_info structure should look like this [2] (except
> > that color_formats and bpc have not be removed yet), and [1] is just
> > here to show how the video_bus_format enum would look like.
> > 
> > [1] http://code.bulix.org/rfd0yx-86557
> > [2] http://code.bulix.org/7n03b4-86556
> 
> Quoting from your paste:
> 
> 	+   const enum video_bus_format *bus_formats;
> 	+   int nbus_formats;
> 
> Do we really need more than one?

We do if we want to replace the color_formats and bpc fields.

-- 
Regards,

Laurent Pinchart

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:16                         ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> >>>> [...]
> >>>> 
> >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>>>>> following values:
> >>>>>>>>>> +   * 0: RGB444
> >>>>>>>>>> +   * 1: RGB565
> >>>>>>>>>> +   * 2: RGB666
> >>>>>>>>>> +   * 3: RGB888
> >>>>>>>>> 
> >>>>>>>>> These are properties of the panel and should be obtained from
> >>>>>>>>> the panel directly rather than an additional cell in this
> >>>>>>>>> specifier.
> >>>>>>>> 
> >>>>>>>> Okay.
> >>>>>>>> What's the preferred way of doing this ?
> >>>>>>>> What about defining an rgb-mode property in the panel node.
> >>>>>>> 
> >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> >>>>>>> be used for this. Alternatively, maybe we could extend the list
> >>>>>>> of color formats that go into drm_display_info.color_formats?
> >>>>>>> RGB444 is already covered.
> >>>>> 
> >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> >>>>> per color" then it cannot be used to encode RGB565 where green
> >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> >>>> 
> >>>> Yes, I agree that bps is not a good fit for what you need here.
> >>> 
> >>> Okay, then I think we can replace bpc and color_formats by a
> >>> bus_formats table containing all supported formats, and use an enum
> >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> >>> [1]) to list the available formats.
> >>> 
> >>> As this implies quite a few changes in crtc core and some drm drivers
> >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> >>> you had in mind.
> >> 
> >> I think it is, but just to make sure I understand you correctly, could
> >> you just show how the drm_display_info structure would look like ?
> > 
> > The new drm_display_info structure should look like this [2] (except
> > that color_formats and bpc have not be removed yet), and [1] is just
> > here to show how the video_bus_format enum would look like.
> > 
> > [1] http://code.bulix.org/rfd0yx-86557
> > [2] http://code.bulix.org/7n03b4-86556
> 
> Quoting from your paste:
> 
> 	+   const enum video_bus_format *bus_formats;
> 	+   int nbus_formats;
> 
> Do we really need more than one?

We do if we want to replace the color_formats and bpc fields.

-- 
Regards,

Laurent Pinchart
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/69e9ee35/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:15             ` Thierry Reding
@ 2014-07-21 12:33               ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 12:33 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Samuel Ortiz, Lee Jones, linux-pwm, David Airlie, dri-devel,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Laurent Pinchart, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Bo Shen, Thomas Petazzoni,
	linux-arm-kernel, Robert Nelson, Tim Niemeyer

On Mon, 21 Jul 2014 14:15:16 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > Hi Thierry,
> > 
> > Oops, I missed this reply.
> > 
> > On Tue, 15 Jul 2014 12:31:37 +0200
> > Thierry Reding <thierry.reding@gmail.com> wrote:
> > 
> > > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > [...]
> > > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > [...]
> > > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > > 
> > > > > I think it's better to refer to these using relative filenames. When the
> > > > > device tree bindings are moved out of the kernel tree, they may no
> > > > > longer use the same hierarchy.
> > > > 
> > > > Sure.
> > > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > > mfd/atmel-hlcdc.txt ?
> > > 
> > > I think the former is more explicit.
> > 
> > Okay.
> > 
> > > 
> > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > +   * 0: RGB444
> > > > > > +   * 1: RGB565
> > > > > > +   * 2: RGB666
> > > > > > +   * 3: RGB888
> > > > > 
> > > > > These are properties of the panel and should be obtained from the panel
> > > > > directly rather than an additional cell in this specifier.
> > > > 
> > > > Okay.
> > > > What's the preferred way of doing this ?
> > > > What about defining an rgb-mode property in the panel node.
> > > 
> > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > for this. Alternatively, maybe we could extend the list of color formats
> > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > 
> > I don't think this color_formats field is intended to represent data
> > stream format going through the bus.
> > Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> > subsampling rate) and not 12 bits signals (4 bits for each color).
> > 
> > Anyway I'll propose a patch series adding a new field to
> > drm_display_info to encode the mediabus format (as discussed with
> > Laurent and you).
> > 
> > > 
> > > Also, like Laurent said, this shouldn't go into the device tree, since
> > > it's already implied by the panel's compatible value, so we'd be
> > > duplicating information.
> > 
> > Again, this is not necessarily true (depending on your board design).
> > One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > the missing pins to ground.
> 
> I think in that case the board design itself could be considered as an
> RGB888 to RGB666 bridge, and I think that's what the device tree should
> be describing rather than a panel with a variable number of input
> formats.

So, you're suggesting to add an RGB to RGB drm_bridge driver (and
the appropriate DT bindings) to handle this case, right ?

I don't know much about drm bridges, but I'll take a look.

Anyway, at the moment I don't have such hardware (one connecting an
RGB888 panel on an RGB666 bus), I was just wondering how I could
represent it ;-).

Thanks,

Boris



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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:33               ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 14:15:16 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > Hi Thierry,
> > 
> > Oops, I missed this reply.
> > 
> > On Tue, 15 Jul 2014 12:31:37 +0200
> > Thierry Reding <thierry.reding@gmail.com> wrote:
> > 
> > > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > [...]
> > > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > [...]
> > > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > > 
> > > > > I think it's better to refer to these using relative filenames. When the
> > > > > device tree bindings are moved out of the kernel tree, they may no
> > > > > longer use the same hierarchy.
> > > > 
> > > > Sure.
> > > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > > mfd/atmel-hlcdc.txt ?
> > > 
> > > I think the former is more explicit.
> > 
> > Okay.
> > 
> > > 
> > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > +   * 0: RGB444
> > > > > > +   * 1: RGB565
> > > > > > +   * 2: RGB666
> > > > > > +   * 3: RGB888
> > > > > 
> > > > > These are properties of the panel and should be obtained from the panel
> > > > > directly rather than an additional cell in this specifier.
> > > > 
> > > > Okay.
> > > > What's the preferred way of doing this ?
> > > > What about defining an rgb-mode property in the panel node.
> > > 
> > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > for this. Alternatively, maybe we could extend the list of color formats
> > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > 
> > I don't think this color_formats field is intended to represent data
> > stream format going through the bus.
> > Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> > subsampling rate) and not 12 bits signals (4 bits for each color).
> > 
> > Anyway I'll propose a patch series adding a new field to
> > drm_display_info to encode the mediabus format (as discussed with
> > Laurent and you).
> > 
> > > 
> > > Also, like Laurent said, this shouldn't go into the device tree, since
> > > it's already implied by the panel's compatible value, so we'd be
> > > duplicating information.
> > 
> > Again, this is not necessarily true (depending on your board design).
> > One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > the missing pins to ground.
> 
> I think in that case the board design itself could be considered as an
> RGB888 to RGB666 bridge, and I think that's what the device tree should
> be describing rather than a panel with a variable number of input
> formats.

So, you're suggesting to add an RGB to RGB drm_bridge driver (and
the appropriate DT bindings) to handle this case, right ?

I don't know much about drm bridges, but I'll take a look.

Anyway, at the moment I don't have such hardware (one connecting an
RGB888 panel on an RGB666 bus), I was just wondering how I could
represent it ;-).

Thanks,

Boris



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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:16                         ` Laurent Pinchart
@ 2014-07-21 12:34                           ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 12:34 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

On Mon, 21 Jul 2014 14:16:42 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Thierry,
> 
> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > >>>> [...]
> > >>>> 
> > >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>>>>> following values:
> > >>>>>>>>>> +   * 0: RGB444
> > >>>>>>>>>> +   * 1: RGB565
> > >>>>>>>>>> +   * 2: RGB666
> > >>>>>>>>>> +   * 3: RGB888
> > >>>>>>>>> 
> > >>>>>>>>> These are properties of the panel and should be obtained from
> > >>>>>>>>> the panel directly rather than an additional cell in this
> > >>>>>>>>> specifier.
> > >>>>>>>> 
> > >>>>>>>> Okay.
> > >>>>>>>> What's the preferred way of doing this ?
> > >>>>>>>> What about defining an rgb-mode property in the panel node.
> > >>>>>>> 
> > >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> > >>>>>>> be used for this. Alternatively, maybe we could extend the list
> > >>>>>>> of color formats that go into drm_display_info.color_formats?
> > >>>>>>> RGB444 is already covered.
> > >>>>> 
> > >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> > >>>>> per color" then it cannot be used to encode RGB565 where green
> > >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> > >>>> 
> > >>>> Yes, I agree that bps is not a good fit for what you need here.
> > >>> 
> > >>> Okay, then I think we can replace bpc and color_formats by a
> > >>> bus_formats table containing all supported formats, and use an enum
> > >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> > >>> [1]) to list the available formats.
> > >>> 
> > >>> As this implies quite a few changes in crtc core and some drm drivers
> > >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> > >>> you had in mind.
> > >> 
> > >> I think it is, but just to make sure I understand you correctly, could
> > >> you just show how the drm_display_info structure would look like ?
> > > 
> > > The new drm_display_info structure should look like this [2] (except
> > > that color_formats and bpc have not be removed yet), and [1] is just
> > > here to show how the video_bus_format enum would look like.
> > > 
> > > [1] http://code.bulix.org/rfd0yx-86557
> > > [2] http://code.bulix.org/7n03b4-86556
> > 
> > Quoting from your paste:
> > 
> > 	+   const enum video_bus_format *bus_formats;
> > 	+   int nbus_formats;
> > 
> > Do we really need more than one?
> 
> We do if we want to replace the color_formats and bpc fields.
> 

Yes, that's what I was about to answer :-).


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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:34                           ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 12:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 14:16:42 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Thierry,
> 
> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > >>>> [...]
> > >>>> 
> > >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>>>>> following values:
> > >>>>>>>>>> +   * 0: RGB444
> > >>>>>>>>>> +   * 1: RGB565
> > >>>>>>>>>> +   * 2: RGB666
> > >>>>>>>>>> +   * 3: RGB888
> > >>>>>>>>> 
> > >>>>>>>>> These are properties of the panel and should be obtained from
> > >>>>>>>>> the panel directly rather than an additional cell in this
> > >>>>>>>>> specifier.
> > >>>>>>>> 
> > >>>>>>>> Okay.
> > >>>>>>>> What's the preferred way of doing this ?
> > >>>>>>>> What about defining an rgb-mode property in the panel node.
> > >>>>>>> 
> > >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> > >>>>>>> be used for this. Alternatively, maybe we could extend the list
> > >>>>>>> of color formats that go into drm_display_info.color_formats?
> > >>>>>>> RGB444 is already covered.
> > >>>>> 
> > >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> > >>>>> per color" then it cannot be used to encode RGB565 where green
> > >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> > >>>> 
> > >>>> Yes, I agree that bps is not a good fit for what you need here.
> > >>> 
> > >>> Okay, then I think we can replace bpc and color_formats by a
> > >>> bus_formats table containing all supported formats, and use an enum
> > >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> > >>> [1]) to list the available formats.
> > >>> 
> > >>> As this implies quite a few changes in crtc core and some drm drivers
> > >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> > >>> you had in mind.
> > >> 
> > >> I think it is, but just to make sure I understand you correctly, could
> > >> you just show how the drm_display_info structure would look like ?
> > > 
> > > The new drm_display_info structure should look like this [2] (except
> > > that color_formats and bpc have not be removed yet), and [1] is just
> > > here to show how the video_bus_format enum would look like.
> > > 
> > > [1] http://code.bulix.org/rfd0yx-86557
> > > [2] http://code.bulix.org/7n03b4-86556
> > 
> > Quoting from your paste:
> > 
> > 	+   const enum video_bus_format *bus_formats;
> > 	+   int nbus_formats;
> > 
> > Do we really need more than one?
> 
> We do if we want to replace the color_formats and bpc fields.
> 

Yes, that's what I was about to answer :-).


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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:34                           ` Boris BREZILLON
@ 2014-07-21 12:55                             ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:55 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3479 bytes --]

On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 14:16:42 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Thierry,
> > 
> > On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > > >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > >>>> [...]
> > > >>>> 
> > > >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> > > >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>>>>>>>> following values:
> > > >>>>>>>>>> +   * 0: RGB444
> > > >>>>>>>>>> +   * 1: RGB565
> > > >>>>>>>>>> +   * 2: RGB666
> > > >>>>>>>>>> +   * 3: RGB888
> > > >>>>>>>>> 
> > > >>>>>>>>> These are properties of the panel and should be obtained from
> > > >>>>>>>>> the panel directly rather than an additional cell in this
> > > >>>>>>>>> specifier.
> > > >>>>>>>> 
> > > >>>>>>>> Okay.
> > > >>>>>>>> What's the preferred way of doing this ?
> > > >>>>>>>> What about defining an rgb-mode property in the panel node.
> > > >>>>>>> 
> > > >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> > > >>>>>>> be used for this. Alternatively, maybe we could extend the list
> > > >>>>>>> of color formats that go into drm_display_info.color_formats?
> > > >>>>>>> RGB444 is already covered.
> > > >>>>> 
> > > >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> > > >>>>> per color" then it cannot be used to encode RGB565 where green
> > > >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> > > >>>> 
> > > >>>> Yes, I agree that bps is not a good fit for what you need here.
> > > >>> 
> > > >>> Okay, then I think we can replace bpc and color_formats by a
> > > >>> bus_formats table containing all supported formats, and use an enum
> > > >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> > > >>> [1]) to list the available formats.
> > > >>> 
> > > >>> As this implies quite a few changes in crtc core and some drm drivers
> > > >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> > > >>> you had in mind.
> > > >> 
> > > >> I think it is, but just to make sure I understand you correctly, could
> > > >> you just show how the drm_display_info structure would look like ?
> > > > 
> > > > The new drm_display_info structure should look like this [2] (except
> > > > that color_formats and bpc have not be removed yet), and [1] is just
> > > > here to show how the video_bus_format enum would look like.
> > > > 
> > > > [1] http://code.bulix.org/rfd0yx-86557
> > > > [2] http://code.bulix.org/7n03b4-86556
> > > 
> > > Quoting from your paste:
> > > 
> > > 	+   const enum video_bus_format *bus_formats;
> > > 	+   int nbus_formats;
> > > 
> > > Do we really need more than one?
> > 
> > We do if we want to replace the color_formats and bpc fields.
> > 
> 
> Yes, that's what I was about to answer :-).

Maybe we don't need to replace color_formats and bpc field immediately.
That could be done in a follow-up patch.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:55                             ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 14:16:42 +0200
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
> > Hi Thierry,
> > 
> > On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > > On Mon, 21 Jul 2014 11:32:55 +0200 Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 11:24:38 Boris BREZILLON wrote:
> > > >>> On Mon, 21 Jul 2014 10:59:12 +0200 Thierry Reding wrote:
> > > >>>> On Fri, Jul 18, 2014 at 05:43:34PM +0200, Boris BREZILLON wrote:
> > > >>>> [...]
> > > >>>> 
> > > >>>>>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > > >>>>>>>>>> +   The first cell is a phandle to a DRM panel device
> > > >>>>>>>>>> +   The second cell encodes the RGB mode, which can take the
> > > >>>>>>>>>> following values:
> > > >>>>>>>>>> +   * 0: RGB444
> > > >>>>>>>>>> +   * 1: RGB565
> > > >>>>>>>>>> +   * 2: RGB666
> > > >>>>>>>>>> +   * 3: RGB888
> > > >>>>>>>>> 
> > > >>>>>>>>> These are properties of the panel and should be obtained from
> > > >>>>>>>>> the panel directly rather than an additional cell in this
> > > >>>>>>>>> specifier.
> > > >>>>>>>> 
> > > >>>>>>>> Okay.
> > > >>>>>>>> What's the preferred way of doing this ?
> > > >>>>>>>> What about defining an rgb-mode property in the panel node.
> > > >>>>>>> 
> > > >>>>>>> There's .bpc in struct drm_display_info, I suspect that it could
> > > >>>>>>> be used for this. Alternatively, maybe we could extend the list
> > > >>>>>>> of color formats that go into drm_display_info.color_formats?
> > > >>>>>>> RGB444 is already covered.
> > > >>>>> 
> > > >>>>> I forgot to ask about bpc meaning. If, as I think, it means "bits
> > > >>>>> per color" then it cannot be used to encode RGB565 where green
> > > >>>>> color is encoded on 6 bits and red and blue are encoded on 5 bits.
> > > >>>> 
> > > >>>> Yes, I agree that bps is not a good fit for what you need here.
> > > >>> 
> > > >>> Okay, then I think we can replace bpc and color_formats by a
> > > >>> bus_formats table containing all supported formats, and use an enum
> > > >>> (something similar to v4l2_mbus_pixelcode defined in v4l2-mediabus.h
> > > >>> [1]) to list the available formats.
> > > >>> 
> > > >>> As this implies quite a few changes in crtc core and some drm drivers
> > > >>> (nouveau, i915 and radeon), I'd like to be sure this is what both of
> > > >>> you had in mind.
> > > >> 
> > > >> I think it is, but just to make sure I understand you correctly, could
> > > >> you just show how the drm_display_info structure would look like ?
> > > > 
> > > > The new drm_display_info structure should look like this [2] (except
> > > > that color_formats and bpc have not be removed yet), and [1] is just
> > > > here to show how the video_bus_format enum would look like.
> > > > 
> > > > [1] http://code.bulix.org/rfd0yx-86557
> > > > [2] http://code.bulix.org/7n03b4-86556
> > > 
> > > Quoting from your paste:
> > > 
> > > 	+   const enum video_bus_format *bus_formats;
> > > 	+   int nbus_formats;
> > > 
> > > Do we really need more than one?
> > 
> > We do if we want to replace the color_formats and bpc fields.
> > 
> 
> Yes, that's what I was about to answer :-).

Maybe we don't need to replace color_formats and bpc field immediately.
That could be done in a follow-up patch.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/a5e6d501/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:33               ` Boris BREZILLON
@ 2014-07-21 12:56                 ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:56 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3664 bytes --]

On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 14:15:16 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > > Hi Thierry,
> > > 
> > > Oops, I missed this reply.
> > > 
> > > On Tue, 15 Jul 2014 12:31:37 +0200
> > > Thierry Reding <thierry.reding@gmail.com> wrote:
> > > 
> > > > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > > [...]
> > > > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > > [...]
> > > > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > > > 
> > > > > > I think it's better to refer to these using relative filenames. When the
> > > > > > device tree bindings are moved out of the kernel tree, they may no
> > > > > > longer use the same hierarchy.
> > > > > 
> > > > > Sure.
> > > > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > > > mfd/atmel-hlcdc.txt ?
> > > > 
> > > > I think the former is more explicit.
> > > 
> > > Okay.
> > > 
> > > > 
> > > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > > +   * 0: RGB444
> > > > > > > +   * 1: RGB565
> > > > > > > +   * 2: RGB666
> > > > > > > +   * 3: RGB888
> > > > > > 
> > > > > > These are properties of the panel and should be obtained from the panel
> > > > > > directly rather than an additional cell in this specifier.
> > > > > 
> > > > > Okay.
> > > > > What's the preferred way of doing this ?
> > > > > What about defining an rgb-mode property in the panel node.
> > > > 
> > > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > > for this. Alternatively, maybe we could extend the list of color formats
> > > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > > 
> > > I don't think this color_formats field is intended to represent data
> > > stream format going through the bus.
> > > Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> > > subsampling rate) and not 12 bits signals (4 bits for each color).
> > > 
> > > Anyway I'll propose a patch series adding a new field to
> > > drm_display_info to encode the mediabus format (as discussed with
> > > Laurent and you).
> > > 
> > > > 
> > > > Also, like Laurent said, this shouldn't go into the device tree, since
> > > > it's already implied by the panel's compatible value, so we'd be
> > > > duplicating information.
> > > 
> > > Again, this is not necessarily true (depending on your board design).
> > > One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > > the missing pins to ground.
> > 
> > I think in that case the board design itself could be considered as an
> > RGB888 to RGB666 bridge, and I think that's what the device tree should
> > be describing rather than a panel with a variable number of input
> > formats.
> 
> So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> the appropriate DT bindings) to handle this case, right ?

Yes, exactly.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 12:56                 ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 14:15:16 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > > Hi Thierry,
> > > 
> > > Oops, I missed this reply.
> > > 
> > > On Tue, 15 Jul 2014 12:31:37 +0200
> > > Thierry Reding <thierry.reding@gmail.com> wrote:
> > > 
> > > > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > > > [...]
> > > > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > > > [...]
> > > > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > > > 
> > > > > > I think it's better to refer to these using relative filenames. When the
> > > > > > device tree bindings are moved out of the kernel tree, they may no
> > > > > > longer use the same hierarchy.
> > > > > 
> > > > > Sure.
> > > > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > > > mfd/atmel-hlcdc.txt ?
> > > > 
> > > > I think the former is more explicit.
> > > 
> > > Okay.
> > > 
> > > > 
> > > > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > > > +   The first cell is a phandle to a DRM panel device
> > > > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > > > +   * 0: RGB444
> > > > > > > +   * 1: RGB565
> > > > > > > +   * 2: RGB666
> > > > > > > +   * 3: RGB888
> > > > > > 
> > > > > > These are properties of the panel and should be obtained from the panel
> > > > > > directly rather than an additional cell in this specifier.
> > > > > 
> > > > > Okay.
> > > > > What's the preferred way of doing this ?
> > > > > What about defining an rgb-mode property in the panel node.
> > > > 
> > > > There's .bpc in struct drm_display_info, I suspect that it could be used
> > > > for this. Alternatively, maybe we could extend the list of color formats
> > > > that go into drm_display_info.color_formats? RGB444 is already covered.
> > > 
> > > I don't think this color_formats field is intended to represent data
> > > stream format going through the bus.
> > > Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> > > subsampling rate) and not 12 bits signals (4 bits for each color).
> > > 
> > > Anyway I'll propose a patch series adding a new field to
> > > drm_display_info to encode the mediabus format (as discussed with
> > > Laurent and you).
> > > 
> > > > 
> > > > Also, like Laurent said, this shouldn't go into the device tree, since
> > > > it's already implied by the panel's compatible value, so we'd be
> > > > duplicating information.
> > > 
> > > Again, this is not necessarily true (depending on your board design).
> > > One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > > the missing pins to ground.
> > 
> > I think in that case the board design itself could be considered as an
> > RGB888 to RGB666 bridge, and I think that's what the device tree should
> > be describing rather than a panel with a variable number of input
> > formats.
> 
> So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> the appropriate DT bindings) to handle this case, right ?

Yes, exactly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/1f75eb5f/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:55                             ` Thierry Reding
@ 2014-07-21 13:22                               ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:22 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


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

Hi Thierry,

On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:

[snip]

> >>>> The new drm_display_info structure should look like this [2] (except
> >>>> that color_formats and bpc have not be removed yet), and [1] is just
> >>>> here to show how the video_bus_format enum would look like.
> >>>> 
> >>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>> [2] http://code.bulix.org/7n03b4-86556
> >>> 
> >>> Quoting from your paste:
> >>> 	+   const enum video_bus_format *bus_formats;
> >>> 	+   int nbus_formats;
> >>> 
> >>> Do we really need more than one?
> >> 
> >> We do if we want to replace the color_formats and bpc fields.
> > 
> > Yes, that's what I was about to answer :-).
> 
> Maybe we don't need to replace color_formats and bpc field immediately.
> That could be done in a follow-up patch.

We don't need to replace them right now, but we should at least agree on how 
to replace them. Introducing a new field that would need to be replaced in the 
near future when removing color_formats and bpc would be a waste of time.

-- 
Regards,

Laurent Pinchart

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:22                               ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:

[snip]

> >>>> The new drm_display_info structure should look like this [2] (except
> >>>> that color_formats and bpc have not be removed yet), and [1] is just
> >>>> here to show how the video_bus_format enum would look like.
> >>>> 
> >>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>> [2] http://code.bulix.org/7n03b4-86556
> >>> 
> >>> Quoting from your paste:
> >>> 	+   const enum video_bus_format *bus_formats;
> >>> 	+   int nbus_formats;
> >>> 
> >>> Do we really need more than one?
> >> 
> >> We do if we want to replace the color_formats and bpc fields.
> > 
> > Yes, that's what I was about to answer :-).
> 
> Maybe we don't need to replace color_formats and bpc field immediately.
> That could be done in a follow-up patch.

We don't need to replace them right now, but we should at least agree on how 
to replace them. Introducing a new field that would need to be replaced in the 
near future when removing color_formats and bpc would be a waste of time.

-- 
Regards,

Laurent Pinchart
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/72642444/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 12:56                 ` Thierry Reding
@ 2014-07-21 13:26                   ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:26 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 2328 bytes --]

Hi Thierry,

On Monday 21 July 2014 14:56:26 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 14:15:16 +0200 Thierry Reding wrote:
> >> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> >>> On Tue, 15 Jul 2014 12:31:37 +0200 Thierry Reding wrote:
> >>>> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> >>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:

[snip]

> >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>> following values: +   * 0: RGB444
> >>>>>>> +   * 1: RGB565
> >>>>>>> +   * 2: RGB666
> >>>>>>> +   * 3: RGB888
> >>>>>> 
> >>>>>> These are properties of the panel and should be obtained from
> >>>>>> the panel directly rather than an additional cell in this
> >>>>>> specifier.
> >>>>> 
> >>>>> Okay.
> >>>>> What's the preferred way of doing this ?
> >>>>> What about defining an rgb-mode property in the panel node.

[snip]

> >>>> Also, like Laurent said, this shouldn't go into the device tree,
> >>>> since it's already implied by the panel's compatible value, so we'd
> >>>> be duplicating information.
> >>> 
> >>> Again, this is not necessarily true (depending on your board design).
> >>> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> >>> the missing pins to ground.
> >> 
> >> I think in that case the board design itself could be considered as an
> >> RGB888 to RGB666 bridge, and I think that's what the device tree should
> >> be describing rather than a panel with a variable number of input
> >> formats.
> > 
> > So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> > the appropriate DT bindings) to handle this case, right ?
> 
> Yes, exactly.

Wouldn't it be possible to implement RGB666 -> RGB888 support in a less 
complex way ? A standalone driver to describe signal routing seems like an 
overly complex solution to me. I would prefer making the routing a properly of 
the link instead of a separate device.

-- 
Regards,

Laurent Pinchart

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:26                   ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thierry,

On Monday 21 July 2014 14:56:26 Thierry Reding wrote:
> On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 14:15:16 +0200 Thierry Reding wrote:
> >> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> >>> On Tue, 15 Jul 2014 12:31:37 +0200 Thierry Reding wrote:
> >>>> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> >>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> >>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:

[snip]

> >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> >>>>>>> +   The first cell is a phandle to a DRM panel device
> >>>>>>> +   The second cell encodes the RGB mode, which can take the
> >>>>>>> following values: +   * 0: RGB444
> >>>>>>> +   * 1: RGB565
> >>>>>>> +   * 2: RGB666
> >>>>>>> +   * 3: RGB888
> >>>>>> 
> >>>>>> These are properties of the panel and should be obtained from
> >>>>>> the panel directly rather than an additional cell in this
> >>>>>> specifier.
> >>>>> 
> >>>>> Okay.
> >>>>> What's the preferred way of doing this ?
> >>>>> What about defining an rgb-mode property in the panel node.

[snip]

> >>>> Also, like Laurent said, this shouldn't go into the device tree,
> >>>> since it's already implied by the panel's compatible value, so we'd
> >>>> be duplicating information.
> >>> 
> >>> Again, this is not necessarily true (depending on your board design).
> >>> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> >>> the missing pins to ground.
> >> 
> >> I think in that case the board design itself could be considered as an
> >> RGB888 to RGB666 bridge, and I think that's what the device tree should
> >> be describing rather than a panel with a variable number of input
> >> formats.
> > 
> > So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> > the appropriate DT bindings) to handle this case, right ?
> 
> Yes, exactly.

Wouldn't it be possible to implement RGB666 -> RGB888 support in a less 
complex way ? A standalone driver to describe signal routing seems like an 
overly complex solution to me. I would prefer making the routing a properly of 
the link instead of a separate device.

-- 
Regards,

Laurent Pinchart
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/3e8f6277/attachment-0001.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:22                               ` Laurent Pinchart
@ 2014-07-21 13:30                                 ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:30 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 1866 bytes --]

On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> 
> [snip]
> 
> > >>>> The new drm_display_info structure should look like this [2] (except
> > >>>> that color_formats and bpc have not be removed yet), and [1] is just
> > >>>> here to show how the video_bus_format enum would look like.
> > >>>> 
> > >>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>> [2] http://code.bulix.org/7n03b4-86556
> > >>> 
> > >>> Quoting from your paste:
> > >>> 	+   const enum video_bus_format *bus_formats;
> > >>> 	+   int nbus_formats;
> > >>> 
> > >>> Do we really need more than one?
> > >> 
> > >> We do if we want to replace the color_formats and bpc fields.
> > > 
> > > Yes, that's what I was about to answer :-).
> > 
> > Maybe we don't need to replace color_formats and bpc field immediately.
> > That could be done in a follow-up patch.
> 
> We don't need to replace them right now, but we should at least agree on how 
> to replace them. Introducing a new field that would need to be replaced in the 
> near future when removing color_formats and bpc would be a waste of time.

Sure. One of the problems I see with replacing color_formats and bpc
with the above is that some of the bits within color_formats are set
when the EDID is parsed. That implies that if they are replaced with
an array of formats, the array would need to be reallocated during EDID
parsing. That sounds like ugliness.

But if you can find a nice way to make it work that'd be great.

Thierry

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:30                                 ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> 
> [snip]
> 
> > >>>> The new drm_display_info structure should look like this [2] (except
> > >>>> that color_formats and bpc have not be removed yet), and [1] is just
> > >>>> here to show how the video_bus_format enum would look like.
> > >>>> 
> > >>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>> [2] http://code.bulix.org/7n03b4-86556
> > >>> 
> > >>> Quoting from your paste:
> > >>> 	+   const enum video_bus_format *bus_formats;
> > >>> 	+   int nbus_formats;
> > >>> 
> > >>> Do we really need more than one?
> > >> 
> > >> We do if we want to replace the color_formats and bpc fields.
> > > 
> > > Yes, that's what I was about to answer :-).
> > 
> > Maybe we don't need to replace color_formats and bpc field immediately.
> > That could be done in a follow-up patch.
> 
> We don't need to replace them right now, but we should at least agree on how 
> to replace them. Introducing a new field that would need to be replaced in the 
> near future when removing color_formats and bpc would be a waste of time.

Sure. One of the problems I see with replacing color_formats and bpc
with the above is that some of the bits within color_formats are set
when the EDID is parsed. That implies that if they are replaced with
an array of formats, the array would need to be reallocated during EDID
parsing. That sounds like ugliness.

But if you can find a nice way to make it work that'd be great.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/46167207/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:26                   ` Laurent Pinchart
@ 2014-07-21 13:33                     ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:33 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Boris BREZILLON, Samuel Ortiz, Lee Jones,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, David Airlie,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Bo Shen, Thomas Petazzoni,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Robert Nelson,
	Tim Niemeyer

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

On Mon, Jul 21, 2014 at 03:26:12PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Monday 21 July 2014 14:56:26 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 14:15:16 +0200 Thierry Reding wrote:
> > >> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > >>> On Tue, 15 Jul 2014 12:31:37 +0200 Thierry Reding wrote:
> > >>>> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > >>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> 
> [snip]
> 
> > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>> following values: +   * 0: RGB444
> > >>>>>>> +   * 1: RGB565
> > >>>>>>> +   * 2: RGB666
> > >>>>>>> +   * 3: RGB888
> > >>>>>> 
> > >>>>>> These are properties of the panel and should be obtained from
> > >>>>>> the panel directly rather than an additional cell in this
> > >>>>>> specifier.
> > >>>>> 
> > >>>>> Okay.
> > >>>>> What's the preferred way of doing this ?
> > >>>>> What about defining an rgb-mode property in the panel node.
> 
> [snip]
> 
> > >>>> Also, like Laurent said, this shouldn't go into the device tree,
> > >>>> since it's already implied by the panel's compatible value, so we'd
> > >>>> be duplicating information.
> > >>> 
> > >>> Again, this is not necessarily true (depending on your board design).
> > >>> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > >>> the missing pins to ground.
> > >> 
> > >> I think in that case the board design itself could be considered as an
> > >> RGB888 to RGB666 bridge, and I think that's what the device tree should
> > >> be describing rather than a panel with a variable number of input
> > >> formats.
> > > 
> > > So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> > > the appropriate DT bindings) to handle this case, right ?
> > 
> > Yes, exactly.
> 
> Wouldn't it be possible to implement RGB666 -> RGB888 support in a less 
> complex way ? A standalone driver to describe signal routing seems like an 
> overly complex solution to me. I would prefer making the routing a properly of 
> the link instead of a separate device.

I don't think the above is overly complex. After all the panel expects
RGB888, so it makes no sense to make it "configurable" to anything else.
Similarly if the encoder or bridge provides RGB666 then that's a fixed
function, too. So to represent this combination accurately you'll need
some form of translation entity inbetween, and it may just as well be a
bridge than something custom for that particular link.

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:33                     ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:26:12PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
> 
> On Monday 21 July 2014 14:56:26 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 02:33:21PM +0200, Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 14:15:16 +0200 Thierry Reding wrote:
> > >> On Fri, Jul 18, 2014 at 04:51:52PM +0200, Boris BREZILLON wrote:
> > >>> On Tue, 15 Jul 2014 12:31:37 +0200 Thierry Reding wrote:
> > >>>> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > >>>>> On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> 
> [snip]
> 
> > >>>>>>> + - atmel,panel: Should contain a phandle with 2 parameters.
> > >>>>>>> +   The first cell is a phandle to a DRM panel device
> > >>>>>>> +   The second cell encodes the RGB mode, which can take the
> > >>>>>>> following values: +   * 0: RGB444
> > >>>>>>> +   * 1: RGB565
> > >>>>>>> +   * 2: RGB666
> > >>>>>>> +   * 3: RGB888
> > >>>>>> 
> > >>>>>> These are properties of the panel and should be obtained from
> > >>>>>> the panel directly rather than an additional cell in this
> > >>>>>> specifier.
> > >>>>> 
> > >>>>> Okay.
> > >>>>> What's the preferred way of doing this ?
> > >>>>> What about defining an rgb-mode property in the panel node.
> 
> [snip]
> 
> > >>>> Also, like Laurent said, this shouldn't go into the device tree,
> > >>>> since it's already implied by the panel's compatible value, so we'd
> > >>>> be duplicating information.
> > >>> 
> > >>> Again, this is not necessarily true (depending on your board design).
> > >>> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> > >>> the missing pins to ground.
> > >> 
> > >> I think in that case the board design itself could be considered as an
> > >> RGB888 to RGB666 bridge, and I think that's what the device tree should
> > >> be describing rather than a panel with a variable number of input
> > >> formats.
> > > 
> > > So, you're suggesting to add an RGB to RGB drm_bridge driver (and
> > > the appropriate DT bindings) to handle this case, right ?
> > 
> > Yes, exactly.
> 
> Wouldn't it be possible to implement RGB666 -> RGB888 support in a less 
> complex way ? A standalone driver to describe signal routing seems like an 
> overly complex solution to me. I would prefer making the routing a properly of 
> the link instead of a separate device.

I don't think the above is overly complex. After all the panel expects
RGB888, so it makes no sense to make it "configurable" to anything else.
Similarly if the encoder or bridge provides RGB666 then that's a fixed
function, too. So to represent this combination accurately you'll need
some form of translation entity inbetween, and it may just as well be a
bridge than something custom for that particular link.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/59b85ab0/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:30                                 ` Thierry Reding
@ 2014-07-21 13:43                                   ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 13:43 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

On Mon, 21 Jul 2014 15:30:35 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > Hi Thierry,
> > 
> > On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > 
> > [snip]
> > 
> > > >>>> The new drm_display_info structure should look like this [2] (except
> > > >>>> that color_formats and bpc have not be removed yet), and [1] is just
> > > >>>> here to show how the video_bus_format enum would look like.
> > > >>>> 
> > > >>>> [1] http://code.bulix.org/rfd0yx-86557
> > > >>>> [2] http://code.bulix.org/7n03b4-86556
> > > >>> 
> > > >>> Quoting from your paste:
> > > >>> 	+   const enum video_bus_format *bus_formats;
> > > >>> 	+   int nbus_formats;
> > > >>> 
> > > >>> Do we really need more than one?
> > > >> 
> > > >> We do if we want to replace the color_formats and bpc fields.
> > > > 
> > > > Yes, that's what I was about to answer :-).
> > > 
> > > Maybe we don't need to replace color_formats and bpc field immediately.
> > > That could be done in a follow-up patch.
> > 
> > We don't need to replace them right now, but we should at least agree on how 
> > to replace them. Introducing a new field that would need to be replaced in the 
> > near future when removing color_formats and bpc would be a waste of time.
> 
> Sure. One of the problems I see with replacing color_formats and bpc
> with the above is that some of the bits within color_formats are set
> when the EDID is parsed. That implies that if they are replaced with
> an array of formats, the array would need to be reallocated during EDID
> parsing. That sounds like ugliness.
> 
> But if you can find a nice way to make it work that'd be great.

How about using a list instead of an array ?
This way we can add elements to this list when parsing the EDID.

Or we can just define a maximum size for the bus_formats array when
retrieving this info from EDID. If I'm correct we have at most 18 bus
formats:
 - 3 color formats:
   * RGB 4:4:4
   * YCbCr 4:4:4
   * YCbCr 4:4:2
 - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color



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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:43                                   ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 15:30:35 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > Hi Thierry,
> > 
> > On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > > On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > >>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > 
> > [snip]
> > 
> > > >>>> The new drm_display_info structure should look like this [2] (except
> > > >>>> that color_formats and bpc have not be removed yet), and [1] is just
> > > >>>> here to show how the video_bus_format enum would look like.
> > > >>>> 
> > > >>>> [1] http://code.bulix.org/rfd0yx-86557
> > > >>>> [2] http://code.bulix.org/7n03b4-86556
> > > >>> 
> > > >>> Quoting from your paste:
> > > >>> 	+   const enum video_bus_format *bus_formats;
> > > >>> 	+   int nbus_formats;
> > > >>> 
> > > >>> Do we really need more than one?
> > > >> 
> > > >> We do if we want to replace the color_formats and bpc fields.
> > > > 
> > > > Yes, that's what I was about to answer :-).
> > > 
> > > Maybe we don't need to replace color_formats and bpc field immediately.
> > > That could be done in a follow-up patch.
> > 
> > We don't need to replace them right now, but we should at least agree on how 
> > to replace them. Introducing a new field that would need to be replaced in the 
> > near future when removing color_formats and bpc would be a waste of time.
> 
> Sure. One of the problems I see with replacing color_formats and bpc
> with the above is that some of the bits within color_formats are set
> when the EDID is parsed. That implies that if they are replaced with
> an array of formats, the array would need to be reallocated during EDID
> parsing. That sounds like ugliness.
> 
> But if you can find a nice way to make it work that'd be great.

How about using a list instead of an array ?
This way we can add elements to this list when parsing the EDID.

Or we can just define a maximum size for the bus_formats array when
retrieving this info from EDID. If I'm correct we have at most 18 bus
formats:
 - 3 color formats:
   * RGB 4:4:4
   * YCbCr 4:4:4
   * YCbCr 4:4:2
 - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color



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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:43                                   ` Boris BREZILLON
@ 2014-07-21 13:47                                     ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:47 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Boris,

On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> >>
> >> [snip]
> >> 
> >>>>>>> The new drm_display_info structure should look like this [2]
> >>>>>>> (except that color_formats and bpc have not be removed yet), and
> >>>>>>> [1] is just here to show how the video_bus_format enum would look
> >>>>>>> like.
> >>>>>>> 
> >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> >>>>>> 
> >>>>>> Quoting from your paste:
> >>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>> 	+   int nbus_formats;
> >>>>>> 
> >>>>>> Do we really need more than one?
> >>>>> 
> >>>>> We do if we want to replace the color_formats and bpc fields.
> >>>> 
> >>>> Yes, that's what I was about to answer :-).
> >>> 
> >>> Maybe we don't need to replace color_formats and bpc field
> >>> immediately. That could be done in a follow-up patch.
> >> 
> >> We don't need to replace them right now, but we should at least agree on
> >> how to replace them. Introducing a new field that would need to be
> >> replaced in the near future when removing color_formats and bpc would
> >> be a waste of time.
> >
> > Sure. One of the problems I see with replacing color_formats and bpc
> > with the above is that some of the bits within color_formats are set
> > when the EDID is parsed. That implies that if they are replaced with
> > an array of formats, the array would need to be reallocated during EDID
> > parsing. That sounds like ugliness.
> > 
> > But if you can find a nice way to make it work that'd be great.
> 
> How about using a list instead of an array ?
> This way we can add elements to this list when parsing the EDID.
> 
> Or we can just define a maximum size for the bus_formats array when
> retrieving this info from EDID. If I'm correct we have at most 18 bus
> formats:
>  - 3 color formats:
>    * RGB 4:4:4
>    * YCbCr 4:4:4
>    * YCbCr 4:4:2
>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color

bpc isn't a bitmask, so EDID supports up to three formats only.

The color_formats field is computed in the drm_add_display_info() function. 
You could easily turn it into a local variable and allocate and fill the 
formats array at the end of the function.

-- 
Regards,

Laurent Pinchart

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:47                                     ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> >>
> >> [snip]
> >> 
> >>>>>>> The new drm_display_info structure should look like this [2]
> >>>>>>> (except that color_formats and bpc have not be removed yet), and
> >>>>>>> [1] is just here to show how the video_bus_format enum would look
> >>>>>>> like.
> >>>>>>> 
> >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> >>>>>> 
> >>>>>> Quoting from your paste:
> >>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>> 	+   int nbus_formats;
> >>>>>> 
> >>>>>> Do we really need more than one?
> >>>>> 
> >>>>> We do if we want to replace the color_formats and bpc fields.
> >>>> 
> >>>> Yes, that's what I was about to answer :-).
> >>> 
> >>> Maybe we don't need to replace color_formats and bpc field
> >>> immediately. That could be done in a follow-up patch.
> >> 
> >> We don't need to replace them right now, but we should at least agree on
> >> how to replace them. Introducing a new field that would need to be
> >> replaced in the near future when removing color_formats and bpc would
> >> be a waste of time.
> >
> > Sure. One of the problems I see with replacing color_formats and bpc
> > with the above is that some of the bits within color_formats are set
> > when the EDID is parsed. That implies that if they are replaced with
> > an array of formats, the array would need to be reallocated during EDID
> > parsing. That sounds like ugliness.
> > 
> > But if you can find a nice way to make it work that'd be great.
> 
> How about using a list instead of an array ?
> This way we can add elements to this list when parsing the EDID.
> 
> Or we can just define a maximum size for the bus_formats array when
> retrieving this info from EDID. If I'm correct we have at most 18 bus
> formats:
>  - 3 color formats:
>    * RGB 4:4:4
>    * YCbCr 4:4:4
>    * YCbCr 4:4:2
>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color

bpc isn't a bitmask, so EDID supports up to three formats only.

The color_formats field is computed in the drm_add_display_info() function. 
You could easily turn it into a local variable and allocate and fill the 
formats array at the end of the function.

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:47                                     ` Laurent Pinchart
@ 2014-07-21 13:54                                       ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:54 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Boris BREZILLON, Samuel Ortiz, Lee Jones, linux-pwm,
	David Airlie, dri-devel, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni,
	Andrew Victor, Jean-Jacques Hiblot, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, devicetree, Bo Shen,
	Thomas Petazzoni, linux-arm-kernel, Robert Nelson, Tim Niemeyer

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

On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> Hi Boris,
> 
> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > >>
> > >> [snip]
> > >> 
> > >>>>>>> The new drm_display_info structure should look like this [2]
> > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > >>>>>>> like.
> > >>>>>>> 
> > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > >>>>>> 
> > >>>>>> Quoting from your paste:
> > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>> 	+   int nbus_formats;
> > >>>>>> 
> > >>>>>> Do we really need more than one?
> > >>>>> 
> > >>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>> 
> > >>>> Yes, that's what I was about to answer :-).
> > >>> 
> > >>> Maybe we don't need to replace color_formats and bpc field
> > >>> immediately. That could be done in a follow-up patch.
> > >> 
> > >> We don't need to replace them right now, but we should at least agree on
> > >> how to replace them. Introducing a new field that would need to be
> > >> replaced in the near future when removing color_formats and bpc would
> > >> be a waste of time.
> > >
> > > Sure. One of the problems I see with replacing color_formats and bpc
> > > with the above is that some of the bits within color_formats are set
> > > when the EDID is parsed. That implies that if they are replaced with
> > > an array of formats, the array would need to be reallocated during EDID
> > > parsing. That sounds like ugliness.
> > > 
> > > But if you can find a nice way to make it work that'd be great.
> > 
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> bpc isn't a bitmask, so EDID supports up to three formats only.
> 
> The color_formats field is computed in the drm_add_display_info() function. 
> You could easily turn it into a local variable and allocate and fill the 
> formats array at the end of the function.

But you also need to be careful to keep whatever formats the driver
might have set explicitly.

Thierry

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 13:54                                       ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 13:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> Hi Boris,
> 
> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > >>
> > >> [snip]
> > >> 
> > >>>>>>> The new drm_display_info structure should look like this [2]
> > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > >>>>>>> like.
> > >>>>>>> 
> > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > >>>>>> 
> > >>>>>> Quoting from your paste:
> > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>> 	+   int nbus_formats;
> > >>>>>> 
> > >>>>>> Do we really need more than one?
> > >>>>> 
> > >>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>> 
> > >>>> Yes, that's what I was about to answer :-).
> > >>> 
> > >>> Maybe we don't need to replace color_formats and bpc field
> > >>> immediately. That could be done in a follow-up patch.
> > >> 
> > >> We don't need to replace them right now, but we should at least agree on
> > >> how to replace them. Introducing a new field that would need to be
> > >> replaced in the near future when removing color_formats and bpc would
> > >> be a waste of time.
> > >
> > > Sure. One of the problems I see with replacing color_formats and bpc
> > > with the above is that some of the bits within color_formats are set
> > > when the EDID is parsed. That implies that if they are replaced with
> > > an array of formats, the array would need to be reallocated during EDID
> > > parsing. That sounds like ugliness.
> > > 
> > > But if you can find a nice way to make it work that'd be great.
> > 
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> bpc isn't a bitmask, so EDID supports up to three formats only.
> 
> The color_formats field is computed in the drm_add_display_info() function. 
> You could easily turn it into a local variable and allocate and fill the 
> formats array at the end of the function.

But you also need to be careful to keep whatever formats the driver
might have set explicitly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140721/2013db14/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:47                                     ` Laurent Pinchart
@ 2014-07-21 14:18                                       ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 14:18 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Thierry Reding, Samuel Ortiz, Lee Jones, linux-pwm, David Airlie,
	dri-devel, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Andrew Victor, Jean-Jacques Hiblot,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree, Bo Shen, Thomas Petazzoni, linux-arm-kernel,
	Robert Nelson, Tim Niemeyer

On Mon, 21 Jul 2014 15:47:52 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > >>
> > >> [snip]
> > >> 
> > >>>>>>> The new drm_display_info structure should look like this [2]
> > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > >>>>>>> like.
> > >>>>>>> 
> > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > >>>>>> 
> > >>>>>> Quoting from your paste:
> > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>> 	+   int nbus_formats;
> > >>>>>> 
> > >>>>>> Do we really need more than one?
> > >>>>> 
> > >>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>> 
> > >>>> Yes, that's what I was about to answer :-).
> > >>> 
> > >>> Maybe we don't need to replace color_formats and bpc field
> > >>> immediately. That could be done in a follow-up patch.
> > >> 
> > >> We don't need to replace them right now, but we should at least agree on
> > >> how to replace them. Introducing a new field that would need to be
> > >> replaced in the near future when removing color_formats and bpc would
> > >> be a waste of time.
> > >
> > > Sure. One of the problems I see with replacing color_formats and bpc
> > > with the above is that some of the bits within color_formats are set
> > > when the EDID is parsed. That implies that if they are replaced with
> > > an array of formats, the array would need to be reallocated during EDID
> > > parsing. That sounds like ugliness.
> > > 
> > > But if you can find a nice way to make it work that'd be great.
> > 
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> bpc isn't a bitmask, so EDID supports up to three formats only.

Yes, bpc only contains a single value for now, and it fits the
DRM_EDID_DIGITAL_DEPTH field [1] (an enum defining the supported pixel
depth).
ITOH, DRM_EDID_HDMI_DC_XX [2] (which are referenced in the new
drm_assign_hdmi_deep_color_info function) are just bitmasks and thus a
display might support several color depth.

As a result, I wonder if we shouldn't start supporting several
color depths (as we do for color formats).

[1]http://lxr.free-electrons.com/source/drivers/gpu/drm/drm_edid.c#L3436
[2]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_edid.c?id=refs/tags/v3.16-rc6#n3440


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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 14:18                                       ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 15:47:52 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > >>
> > >> [snip]
> > >> 
> > >>>>>>> The new drm_display_info structure should look like this [2]
> > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > >>>>>>> like.
> > >>>>>>> 
> > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > >>>>>> 
> > >>>>>> Quoting from your paste:
> > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>> 	+   int nbus_formats;
> > >>>>>> 
> > >>>>>> Do we really need more than one?
> > >>>>> 
> > >>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>> 
> > >>>> Yes, that's what I was about to answer :-).
> > >>> 
> > >>> Maybe we don't need to replace color_formats and bpc field
> > >>> immediately. That could be done in a follow-up patch.
> > >> 
> > >> We don't need to replace them right now, but we should at least agree on
> > >> how to replace them. Introducing a new field that would need to be
> > >> replaced in the near future when removing color_formats and bpc would
> > >> be a waste of time.
> > >
> > > Sure. One of the problems I see with replacing color_formats and bpc
> > > with the above is that some of the bits within color_formats are set
> > > when the EDID is parsed. That implies that if they are replaced with
> > > an array of formats, the array would need to be reallocated during EDID
> > > parsing. That sounds like ugliness.
> > > 
> > > But if you can find a nice way to make it work that'd be great.
> > 
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> bpc isn't a bitmask, so EDID supports up to three formats only.

Yes, bpc only contains a single value for now, and it fits the
DRM_EDID_DIGITAL_DEPTH field [1] (an enum defining the supported pixel
depth).
ITOH, DRM_EDID_HDMI_DC_XX [2] (which are referenced in the new
drm_assign_hdmi_deep_color_info function) are just bitmasks and thus a
display might support several color depth.

As a result, I wonder if we shouldn't start supporting several
color depths (as we do for color formats).

[1]http://lxr.free-electrons.com/source/drivers/gpu/drm/drm_edid.c#L3436
[2]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_edid.c?id=refs/tags/v3.16-rc6#n3440


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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:54                                       ` Thierry Reding
@ 2014-07-21 14:21                                         ` Boris BREZILLON
  -1 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 14:21 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, linux-pwm, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala

On Mon, 21 Jul 2014 15:54:12 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> > Hi Boris,
> > 
> > On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > >>
> > > >> [snip]
> > > >> 
> > > >>>>>>> The new drm_display_info structure should look like this [2]
> > > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > > >>>>>>> like.
> > > >>>>>>> 
> > > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > > >>>>>> 
> > > >>>>>> Quoting from your paste:
> > > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > > >>>>>> 	+   int nbus_formats;
> > > >>>>>> 
> > > >>>>>> Do we really need more than one?
> > > >>>>> 
> > > >>>>> We do if we want to replace the color_formats and bpc fields.
> > > >>>> 
> > > >>>> Yes, that's what I was about to answer :-).
> > > >>> 
> > > >>> Maybe we don't need to replace color_formats and bpc field
> > > >>> immediately. That could be done in a follow-up patch.
> > > >> 
> > > >> We don't need to replace them right now, but we should at least agree on
> > > >> how to replace them. Introducing a new field that would need to be
> > > >> replaced in the near future when removing color_formats and bpc would
> > > >> be a waste of time.
> > > >
> > > > Sure. One of the problems I see with replacing color_formats and bpc
> > > > with the above is that some of the bits within color_formats are set
> > > > when the EDID is parsed. That implies that if they are replaced with
> > > > an array of formats, the array would need to be reallocated during EDID
> > > > parsing. That sounds like ugliness.
> > > > 
> > > > But if you can find a nice way to make it work that'd be great.
> > > 
> > > How about using a list instead of an array ?
> > > This way we can add elements to this list when parsing the EDID.
> > > 
> > > Or we can just define a maximum size for the bus_formats array when
> > > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > > formats:
> > >  - 3 color formats:
> > >    * RGB 4:4:4
> > >    * YCbCr 4:4:4
> > >    * YCbCr 4:4:2
> > >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > 
> > bpc isn't a bitmask, so EDID supports up to three formats only.
> > 
> > The color_formats field is computed in the drm_add_display_info() function. 
> > You could easily turn it into a local variable and allocate and fill the 
> > formats array at the end of the function.
> 
> But you also need to be careful to keep whatever formats the driver
> might have set explicitly.

Okay, in this case, using a list is a better idea, don't you think ?

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

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 14:21                                         ` Boris BREZILLON
  0 siblings, 0 replies; 149+ messages in thread
From: Boris BREZILLON @ 2014-07-21 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul 2014 15:54:12 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> > Hi Boris,
> > 
> > On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > > On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > > > On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > > >> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > > >>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > > >>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > > >>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> > > >>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> > > >>
> > > >> [snip]
> > > >> 
> > > >>>>>>> The new drm_display_info structure should look like this [2]
> > > >>>>>>> (except that color_formats and bpc have not be removed yet), and
> > > >>>>>>> [1] is just here to show how the video_bus_format enum would look
> > > >>>>>>> like.
> > > >>>>>>> 
> > > >>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> > > >>>>>>> [2] http://code.bulix.org/7n03b4-86556
> > > >>>>>> 
> > > >>>>>> Quoting from your paste:
> > > >>>>>> 	+   const enum video_bus_format *bus_formats;
> > > >>>>>> 	+   int nbus_formats;
> > > >>>>>> 
> > > >>>>>> Do we really need more than one?
> > > >>>>> 
> > > >>>>> We do if we want to replace the color_formats and bpc fields.
> > > >>>> 
> > > >>>> Yes, that's what I was about to answer :-).
> > > >>> 
> > > >>> Maybe we don't need to replace color_formats and bpc field
> > > >>> immediately. That could be done in a follow-up patch.
> > > >> 
> > > >> We don't need to replace them right now, but we should at least agree on
> > > >> how to replace them. Introducing a new field that would need to be
> > > >> replaced in the near future when removing color_formats and bpc would
> > > >> be a waste of time.
> > > >
> > > > Sure. One of the problems I see with replacing color_formats and bpc
> > > > with the above is that some of the bits within color_formats are set
> > > > when the EDID is parsed. That implies that if they are replaced with
> > > > an array of formats, the array would need to be reallocated during EDID
> > > > parsing. That sounds like ugliness.
> > > > 
> > > > But if you can find a nice way to make it work that'd be great.
> > > 
> > > How about using a list instead of an array ?
> > > This way we can add elements to this list when parsing the EDID.
> > > 
> > > Or we can just define a maximum size for the bus_formats array when
> > > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > > formats:
> > >  - 3 color formats:
> > >    * RGB 4:4:4
> > >    * YCbCr 4:4:4
> > >    * YCbCr 4:4:2
> > >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > 
> > bpc isn't a bitmask, so EDID supports up to three formats only.
> > 
> > The color_formats field is computed in the drm_add_display_info() function. 
> > You could easily turn it into a local variable and allocate and fill the 
> > formats array at the end of the function.
> 
> But you also need to be careful to keep whatever formats the driver
> might have set explicitly.

Okay, in this case, using a list is a better idea, don't you think ?

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

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 13:43                                   ` Boris BREZILLON
@ 2014-07-21 17:06                                     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 149+ messages in thread
From: Russell King - ARM Linux @ 2014-07-21 17:06 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Thierry Reding, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
	David Airlie, Nicolas Ferre,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Alexandre Belloni,
	Laurent Pinchart, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, Pawel Moll, Ian Campbell,
	Rob Herring, Robert Nelson, Andrew Victor,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni

On Mon, Jul 21, 2014 at 03:43:13PM +0200, Boris BREZILLON wrote:
> How about using a list instead of an array ?
> This way we can add elements to this list when parsing the EDID.
> 
> Or we can just define a maximum size for the bus_formats array when
> retrieving this info from EDID. If I'm correct we have at most 18 bus
> formats:
>  - 3 color formats:
>    * RGB 4:4:4
>    * YCbCr 4:4:4
>    * YCbCr 4:4:2
>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color

This starts to worry me.  What are we trying to do here - are we trying
to encode the connection between the CRTC and the encoder, the encoder
and the connector, or the connector and the device?

The encoder to connector and connector to device is mostly a function of
the interface spec itself (for example, many HDMI encoders take either a
RGB or YUV input and can convert it to the HDMI specified colourspaces for
transmission over the connector.)

If you want to do encoder to connector, what about VGA or some other
analogue signalling such as TV composite?  It's easy to take this too
far...

Surely the only one which matters is the CRTC to the encoder - that's
certainly true of all the setups I've come across so far.  As for that
interface, CRTCs I've seen can produce a /wide/ range of different
representations.

Some CRTCs (eg, AMBA CLCD) produce R, G, B signals scrunched down on to
the LSB bits of a LCD data bus (so RGB888 uses 24 bits, RGB444 would
use the LSB 12 bits of those 24 - rather than outputting the R4 bits on
a subset of the R8 bits.)

What about RGB565 - where you have differing number of bits for the
green channel from red/blue?

Then you have red/blue colour swapping at the CRTC (and similar for YUV)
such as on Dove / Armada.

Then there are some encoders have the ability to almost arbitarily map
their input pins according to whatever you choose (eg, TDA998x).

This problem isn't as quite as simple as "this is what EDID gives us"
and "these are the number of bits representing a colour".

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 17:06                                     ` Russell King - ARM Linux
  0 siblings, 0 replies; 149+ messages in thread
From: Russell King - ARM Linux @ 2014-07-21 17:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 03:43:13PM +0200, Boris BREZILLON wrote:
> How about using a list instead of an array ?
> This way we can add elements to this list when parsing the EDID.
> 
> Or we can just define a maximum size for the bus_formats array when
> retrieving this info from EDID. If I'm correct we have at most 18 bus
> formats:
>  - 3 color formats:
>    * RGB 4:4:4
>    * YCbCr 4:4:4
>    * YCbCr 4:4:2
>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color

This starts to worry me.  What are we trying to do here - are we trying
to encode the connection between the CRTC and the encoder, the encoder
and the connector, or the connector and the device?

The encoder to connector and connector to device is mostly a function of
the interface spec itself (for example, many HDMI encoders take either a
RGB or YUV input and can convert it to the HDMI specified colourspaces for
transmission over the connector.)

If you want to do encoder to connector, what about VGA or some other
analogue signalling such as TV composite?  It's easy to take this too
far...

Surely the only one which matters is the CRTC to the encoder - that's
certainly true of all the setups I've come across so far.  As for that
interface, CRTCs I've seen can produce a /wide/ range of different
representations.

Some CRTCs (eg, AMBA CLCD) produce R, G, B signals scrunched down on to
the LSB bits of a LCD data bus (so RGB888 uses 24 bits, RGB444 would
use the LSB 12 bits of those 24 - rather than outputting the R4 bits on
a subset of the R8 bits.)

What about RGB565 - where you have differing number of bits for the
green channel from red/blue?

Then you have red/blue colour swapping at the CRTC (and similar for YUV)
such as on Dove / Armada.

Then there are some encoders have the ability to almost arbitarily map
their input pins according to whatever you choose (eg, TDA998x).

This problem isn't as quite as simple as "this is what EDID gives us"
and "these are the number of bits representing a colour".

-- 
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 14:21                                         ` Boris BREZILLON
@ 2014-07-21 18:30                                           ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 18:30 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Boris and Thierry,

On Monday 21 July 2014 16:21:36 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:54:12 +0200 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> >> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> >>> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> >>>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >>>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:

[snip]

> >>>>>>>>> Quoting from your paste:
> >>>>>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>>>>> 	+   int nbus_formats;
> >>>>>>>>> 
> >>>>>>>>> Do we really need more than one?
> >>>>>>>> 
> >>>>>>>> We do if we want to replace the color_formats and bpc fields.
> >>>>>>> 
> >>>>>>> Yes, that's what I was about to answer :-).
> >>>>>> 
> >>>>>> Maybe we don't need to replace color_formats and bpc field
> >>>>>> immediately. That could be done in a follow-up patch.
> >>>>> 
> >>>>> We don't need to replace them right now, but we should at least
> >>>>> agree on how to replace them. Introducing a new field that would
> >>>>> need to be replaced in the near future when removing color_formats
> >>>>> and bpc would be a waste of time.
> >>>> 
> >>>> Sure. One of the problems I see with replacing color_formats and bpc
> >>>> with the above is that some of the bits within color_formats are set
> >>>> when the EDID is parsed. That implies that if they are replaced with
> >>>> an array of formats, the array would need to be reallocated during
> >>>> EDID parsing. That sounds like ugliness.
> >>>> 
> >>>> But if you can find a nice way to make it work that'd be great.
> >>> 
> >>> How about using a list instead of an array ?
> >>> This way we can add elements to this list when parsing the EDID.
> >>> 
> >>> Or we can just define a maximum size for the bus_formats array when
> >>> retrieving this info from EDID. If I'm correct we have at most 18 bus
> >>> 
> >>> formats:
> >>>  - 3 color formats:
> >>>    * RGB 4:4:4
> >>>    * YCbCr 4:4:4
> >>>    * YCbCr 4:4:2
> >>>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> >> 
> >> bpc isn't a bitmask, so EDID supports up to three formats only.
> >> 
> >> The color_formats field is computed in the drm_add_display_info()
> >> function. You could easily turn it into a local variable and allocate
> >> and fill the formats array at the end of the function.
> > 
> > But you also need to be careful to keep whatever formats the driver might
> > have set explicitly.

Do we have drivers that explicitly add formats to the formats parsed from EDID 
data ? If so, what's the use case ?

> Okay, in this case, using a list is a better idea, don't you think ?

I'd prefer an array if possible, as that would be easier to use for drivers.

In any case, we need to define who allocates and frees the array or the list 
elements, how and when.

-- 
Regards,

Laurent Pinchart

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 18:30                                           ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris and Thierry,

On Monday 21 July 2014 16:21:36 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:54:12 +0200 Thierry Reding wrote:
> > On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> >> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> >>> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> >>>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >>>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:

[snip]

> >>>>>>>>> Quoting from your paste:
> >>>>>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>>>>> 	+   int nbus_formats;
> >>>>>>>>> 
> >>>>>>>>> Do we really need more than one?
> >>>>>>>> 
> >>>>>>>> We do if we want to replace the color_formats and bpc fields.
> >>>>>>> 
> >>>>>>> Yes, that's what I was about to answer :-).
> >>>>>> 
> >>>>>> Maybe we don't need to replace color_formats and bpc field
> >>>>>> immediately. That could be done in a follow-up patch.
> >>>>> 
> >>>>> We don't need to replace them right now, but we should at least
> >>>>> agree on how to replace them. Introducing a new field that would
> >>>>> need to be replaced in the near future when removing color_formats
> >>>>> and bpc would be a waste of time.
> >>>> 
> >>>> Sure. One of the problems I see with replacing color_formats and bpc
> >>>> with the above is that some of the bits within color_formats are set
> >>>> when the EDID is parsed. That implies that if they are replaced with
> >>>> an array of formats, the array would need to be reallocated during
> >>>> EDID parsing. That sounds like ugliness.
> >>>> 
> >>>> But if you can find a nice way to make it work that'd be great.
> >>> 
> >>> How about using a list instead of an array ?
> >>> This way we can add elements to this list when parsing the EDID.
> >>> 
> >>> Or we can just define a maximum size for the bus_formats array when
> >>> retrieving this info from EDID. If I'm correct we have at most 18 bus
> >>> 
> >>> formats:
> >>>  - 3 color formats:
> >>>    * RGB 4:4:4
> >>>    * YCbCr 4:4:4
> >>>    * YCbCr 4:4:2
> >>>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> >> 
> >> bpc isn't a bitmask, so EDID supports up to three formats only.
> >> 
> >> The color_formats field is computed in the drm_add_display_info()
> >> function. You could easily turn it into a local variable and allocate
> >> and fill the formats array at the end of the function.
> > 
> > But you also need to be careful to keep whatever formats the driver might
> > have set explicitly.

Do we have drivers that explicitly add formats to the formats parsed from EDID 
data ? If so, what's the use case ?

> Okay, in this case, using a list is a better idea, don't you think ?

I'd prefer an array if possible, as that would be easier to use for drivers.

In any case, we need to define who allocates and frees the array or the list 
elements, how and when.

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 14:18                                       ` Boris BREZILLON
@ 2014-07-21 18:32                                         ` Laurent Pinchart
  -1 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 18:32 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala

Hi Boris,

On Monday 21 July 2014 16:18:10 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:47:52 +0200 Laurent Pinchart wrote:
> > On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> >> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>>>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> >>>> [snip]
> >>>> 
> >>>>>>>>> The new drm_display_info structure should look like this [2]
> >>>>>>>>> (except that color_formats and bpc have not be removed yet), and
> >>>>>>>>> [1] is just here to show how the video_bus_format enum would
> >>>>>>>>> look like.
> >>>>>>>>> 
> >>>>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>>>>>>> [2] http://code.bulix.org/7n03b4-86556
> >>>>>>>> 
> >>>>>>>> Quoting from your paste:
> >>>>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>>>> 	+   int nbus_formats;
> >>>>>>>> 
> >>>>>>>> Do we really need more than one?
> >>>>>>> 
> >>>>>>> We do if we want to replace the color_formats and bpc fields.
> >>>>>> 
> >>>>>> Yes, that's what I was about to answer :-).
> >>>>> 
> >>>>> Maybe we don't need to replace color_formats and bpc field
> >>>>> immediately. That could be done in a follow-up patch.
> >>>> 
> >>>> We don't need to replace them right now, but we should at least agree
> >>>> on how to replace them. Introducing a new field that would need to be
> >>>> replaced in the near future when removing color_formats and bpc would
> >>>> be a waste of time.
> >>> 
> >>> Sure. One of the problems I see with replacing color_formats and bpc
> >>> with the above is that some of the bits within color_formats are set
> >>> when the EDID is parsed. That implies that if they are replaced with
> >>> an array of formats, the array would need to be reallocated during
> >>> EDID parsing. That sounds like ugliness.
> >>> 
> >>> But if you can find a nice way to make it work that'd be great.
> >> 
> >> How about using a list instead of an array ?
> >> This way we can add elements to this list when parsing the EDID.
> >> 
> >> Or we can just define a maximum size for the bus_formats array when
> >> retrieving this info from EDID. If I'm correct we have at most 18 bus
> >> 
> >> formats:
> >>  - 3 color formats:
> >>    * RGB 4:4:4
> >>    * YCbCr 4:4:4
> >>    * YCbCr 4:4:2
> >>  
> >>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > 
> > bpc isn't a bitmask, so EDID supports up to three formats only.
> 
> Yes, bpc only contains a single value for now, and it fits the
> DRM_EDID_DIGITAL_DEPTH field [1] (an enum defining the supported pixel
> depth).
> ITOH, DRM_EDID_HDMI_DC_XX [2] (which are referenced in the new
> drm_assign_hdmi_deep_color_info function) are just bitmasks and thus a
> display might support several color depth.
> 
> As a result, I wonder if we shouldn't start supporting several color depths
> (as we do for color formats)

If there's a use case for that, sure. It wouldn't be difficult, given that a 
bus format defines both the color format and the depths.

> [1]http://lxr.free-electrons.com/source/drivers/gpu/drm/drm_edid.c#L3436
> [2]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/driv
> ers/gpu/drm/drm_edid.c?id=refs/tags/v3.16-rc6#n3440

-- 
Regards,

Laurent Pinchart

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 18:32                                         ` Laurent Pinchart
  0 siblings, 0 replies; 149+ messages in thread
From: Laurent Pinchart @ 2014-07-21 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Boris,

On Monday 21 July 2014 16:18:10 Boris BREZILLON wrote:
> On Mon, 21 Jul 2014 15:47:52 +0200 Laurent Pinchart wrote:
> > On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> >> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> >>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> >>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> >>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> >>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> >>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> >>>>>>>> On Mon, Jul 21, 2014 at 11:57:37AM +0200, Boris BREZILLON wrote:
> >>>> [snip]
> >>>> 
> >>>>>>>>> The new drm_display_info structure should look like this [2]
> >>>>>>>>> (except that color_formats and bpc have not be removed yet), and
> >>>>>>>>> [1] is just here to show how the video_bus_format enum would
> >>>>>>>>> look like.
> >>>>>>>>> 
> >>>>>>>>> [1] http://code.bulix.org/rfd0yx-86557
> >>>>>>>>> [2] http://code.bulix.org/7n03b4-86556
> >>>>>>>> 
> >>>>>>>> Quoting from your paste:
> >>>>>>>> 	+   const enum video_bus_format *bus_formats;
> >>>>>>>> 	+   int nbus_formats;
> >>>>>>>> 
> >>>>>>>> Do we really need more than one?
> >>>>>>> 
> >>>>>>> We do if we want to replace the color_formats and bpc fields.
> >>>>>> 
> >>>>>> Yes, that's what I was about to answer :-).
> >>>>> 
> >>>>> Maybe we don't need to replace color_formats and bpc field
> >>>>> immediately. That could be done in a follow-up patch.
> >>>> 
> >>>> We don't need to replace them right now, but we should at least agree
> >>>> on how to replace them. Introducing a new field that would need to be
> >>>> replaced in the near future when removing color_formats and bpc would
> >>>> be a waste of time.
> >>> 
> >>> Sure. One of the problems I see with replacing color_formats and bpc
> >>> with the above is that some of the bits within color_formats are set
> >>> when the EDID is parsed. That implies that if they are replaced with
> >>> an array of formats, the array would need to be reallocated during
> >>> EDID parsing. That sounds like ugliness.
> >>> 
> >>> But if you can find a nice way to make it work that'd be great.
> >> 
> >> How about using a list instead of an array ?
> >> This way we can add elements to this list when parsing the EDID.
> >> 
> >> Or we can just define a maximum size for the bus_formats array when
> >> retrieving this info from EDID. If I'm correct we have at most 18 bus
> >> 
> >> formats:
> >>  - 3 color formats:
> >>    * RGB 4:4:4
> >>    * YCbCr 4:4:4
> >>    * YCbCr 4:4:2
> >>  
> >>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > 
> > bpc isn't a bitmask, so EDID supports up to three formats only.
> 
> Yes, bpc only contains a single value for now, and it fits the
> DRM_EDID_DIGITAL_DEPTH field [1] (an enum defining the supported pixel
> depth).
> ITOH, DRM_EDID_HDMI_DC_XX [2] (which are referenced in the new
> drm_assign_hdmi_deep_color_info function) are just bitmasks and thus a
> display might support several color depth.
> 
> As a result, I wonder if we shouldn't start supporting several color depths
> (as we do for color formats)

If there's a use case for that, sure. It wouldn't be difficult, given that a 
bus format defines both the color format and the depths.

> [1]http://lxr.free-electrons.com/source/drivers/gpu/drm/drm_edid.c#L3436
> [2]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/driv
> ers/gpu/drm/drm_edid.c?id=refs/tags/v3.16-rc6#n3440

-- 
Regards,

Laurent Pinchart

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 18:30                                           ` Laurent Pinchart
@ 2014-07-21 22:04                                             ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 22:04 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, devicetree, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Bo Shen, Lee Jones, Jean-Jacques Hiblot,
	Samuel Ortiz, Tim Niemeyer, Jean-Christophe Plagniol-Villard,
	linux-pwm, Pawel Moll, Ian Campbell, Rob Herring, Andrew Victor,
	linux-arm-kernel, Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3406 bytes --]

On Mon, Jul 21, 2014 at 08:30:31PM +0200, Laurent Pinchart wrote:
> Hi Boris and Thierry,
> 
> On Monday 21 July 2014 16:21:36 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:54:12 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > >>> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > >>>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> 
> [snip]
> 
> > >>>>>>>>> Quoting from your paste:
> > >>>>>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>>>>> 	+   int nbus_formats;
> > >>>>>>>>> 
> > >>>>>>>>> Do we really need more than one?
> > >>>>>>>> 
> > >>>>>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>>>>> 
> > >>>>>>> Yes, that's what I was about to answer :-).
> > >>>>>> 
> > >>>>>> Maybe we don't need to replace color_formats and bpc field
> > >>>>>> immediately. That could be done in a follow-up patch.
> > >>>>> 
> > >>>>> We don't need to replace them right now, but we should at least
> > >>>>> agree on how to replace them. Introducing a new field that would
> > >>>>> need to be replaced in the near future when removing color_formats
> > >>>>> and bpc would be a waste of time.
> > >>>> 
> > >>>> Sure. One of the problems I see with replacing color_formats and bpc
> > >>>> with the above is that some of the bits within color_formats are set
> > >>>> when the EDID is parsed. That implies that if they are replaced with
> > >>>> an array of formats, the array would need to be reallocated during
> > >>>> EDID parsing. That sounds like ugliness.
> > >>>> 
> > >>>> But if you can find a nice way to make it work that'd be great.
> > >>> 
> > >>> How about using a list instead of an array ?
> > >>> This way we can add elements to this list when parsing the EDID.
> > >>> 
> > >>> Or we can just define a maximum size for the bus_formats array when
> > >>> retrieving this info from EDID. If I'm correct we have at most 18 bus
> > >>> 
> > >>> formats:
> > >>>  - 3 color formats:
> > >>>    * RGB 4:4:4
> > >>>    * YCbCr 4:4:4
> > >>>    * YCbCr 4:4:2
> > >>>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > >> 
> > >> bpc isn't a bitmask, so EDID supports up to three formats only.
> > >> 
> > >> The color_formats field is computed in the drm_add_display_info()
> > >> function. You could easily turn it into a local variable and allocate
> > >> and fill the formats array at the end of the function.
> > > 
> > > But you also need to be careful to keep whatever formats the driver might
> > > have set explicitly.
> 
> Do we have drivers that explicitly add formats to the formats parsed from EDID 
> data ? If so, what's the use case ?

Drivers could specifically add them if there's no EDID or if the EDID
is known to be broken. If the former this is probably irrelevant. In the
latter maybe a better option would be to ignore the EDID-probed ones
rather than use the union of those provided by the driver and EDID.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 22:04                                             ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 22:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 08:30:31PM +0200, Laurent Pinchart wrote:
> Hi Boris and Thierry,
> 
> On Monday 21 July 2014 16:21:36 Boris BREZILLON wrote:
> > On Mon, 21 Jul 2014 15:54:12 +0200 Thierry Reding wrote:
> > > On Mon, Jul 21, 2014 at 03:47:52PM +0200, Laurent Pinchart wrote:
> > >> On Monday 21 July 2014 15:43:13 Boris BREZILLON wrote:
> > >>> On Mon, 21 Jul 2014 15:30:35 +0200 Thierry Reding wrote:
> > >>>> On Mon, Jul 21, 2014 at 03:22:05PM +0200, Laurent Pinchart wrote:
> > >>>>> On Monday 21 July 2014 14:55:23 Thierry Reding wrote:
> > >>>>>> On Mon, Jul 21, 2014 at 02:34:28PM +0200, Boris BREZILLON wrote:
> > >>>>>>> On Mon, 21 Jul 2014 14:16:42 +0200 Laurent Pinchart wrote:
> > >>>>>>>> On Monday 21 July 2014 14:12:47 Thierry Reding wrote:
> 
> [snip]
> 
> > >>>>>>>>> Quoting from your paste:
> > >>>>>>>>> 	+   const enum video_bus_format *bus_formats;
> > >>>>>>>>> 	+   int nbus_formats;
> > >>>>>>>>> 
> > >>>>>>>>> Do we really need more than one?
> > >>>>>>>> 
> > >>>>>>>> We do if we want to replace the color_formats and bpc fields.
> > >>>>>>> 
> > >>>>>>> Yes, that's what I was about to answer :-).
> > >>>>>> 
> > >>>>>> Maybe we don't need to replace color_formats and bpc field
> > >>>>>> immediately. That could be done in a follow-up patch.
> > >>>>> 
> > >>>>> We don't need to replace them right now, but we should at least
> > >>>>> agree on how to replace them. Introducing a new field that would
> > >>>>> need to be replaced in the near future when removing color_formats
> > >>>>> and bpc would be a waste of time.
> > >>>> 
> > >>>> Sure. One of the problems I see with replacing color_formats and bpc
> > >>>> with the above is that some of the bits within color_formats are set
> > >>>> when the EDID is parsed. That implies that if they are replaced with
> > >>>> an array of formats, the array would need to be reallocated during
> > >>>> EDID parsing. That sounds like ugliness.
> > >>>> 
> > >>>> But if you can find a nice way to make it work that'd be great.
> > >>> 
> > >>> How about using a list instead of an array ?
> > >>> This way we can add elements to this list when parsing the EDID.
> > >>> 
> > >>> Or we can just define a maximum size for the bus_formats array when
> > >>> retrieving this info from EDID. If I'm correct we have at most 18 bus
> > >>> 
> > >>> formats:
> > >>>  - 3 color formats:
> > >>>    * RGB 4:4:4
> > >>>    * YCbCr 4:4:4
> > >>>    * YCbCr 4:4:2
> > >>>  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> > >> 
> > >> bpc isn't a bitmask, so EDID supports up to three formats only.
> > >> 
> > >> The color_formats field is computed in the drm_add_display_info()
> > >> function. You could easily turn it into a local variable and allocate
> > >> and fill the formats array at the end of the function.
> > > 
> > > But you also need to be careful to keep whatever formats the driver might
> > > have set explicitly.
> 
> Do we have drivers that explicitly add formats to the formats parsed from EDID 
> data ? If so, what's the use case ?

Drivers could specifically add them if there's no EDID or if the EDID
is known to be broken. If the former this is probably irrelevant. In the
latter maybe a better option would be to ignore the EDID-probed ones
rather than use the union of those provided by the driver and EDID.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140722/4735739e/attachment.sig>

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

* Re: [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
  2014-07-21 17:06                                     ` Russell King - ARM Linux
@ 2014-07-21 22:17                                       ` Thierry Reding
  -1 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 22:17 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, linux-pwm, Nicolas Ferre, dri-devel,
	Alexandre Belloni, Laurent Pinchart, Bo Shen, Lee Jones,
	Jean-Jacques Hiblot, Samuel Ortiz, Tim Niemeyer,
	Jean-Christophe Plagniol-Villard, devicetree, Pawel Moll,
	Ian Campbell, Rob Herring, Andrew Victor, linux-arm-kernel,
	Thomas Petazzoni, Kumar Gala


[-- Attachment #1.1: Type: text/plain, Size: 3429 bytes --]

On Mon, Jul 21, 2014 at 06:06:30PM +0100, Russell King - ARM Linux wrote:
> On Mon, Jul 21, 2014 at 03:43:13PM +0200, Boris BREZILLON wrote:
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> This starts to worry me.  What are we trying to do here - are we trying
> to encode the connection between the CRTC and the encoder, the encoder
> and the connector, or the connector and the device?

This is about the bus format of the panel device. That would make it the
latter.

> The encoder to connector and connector to device is mostly a function of
> the interface spec itself (for example, many HDMI encoders take either a
> RGB or YUV input and can convert it to the HDMI specified colourspaces for
> transmission over the connector.)

The discussion here started because we currently have no way to store
information about the interface for raw RGB. That means currently all
drivers need to hardcode assumptions about the mode. The idea was to
make this information available via a field in drm_display_info so that
drivers could reconfigure depending on what the attached panel expects.

This doesn't only apply to panels, though, the issue is the same when a
bridge (RGB/LVDS for example) is connected to the encoder.

> If you want to do encoder to connector, what about VGA or some other
> analogue signalling such as TV composite?  It's easy to take this too
> far...
> 
> Surely the only one which matters is the CRTC to the encoder - that's
> certainly true of all the setups I've come across so far.  As for that
> interface, CRTCs I've seen can produce a /wide/ range of different
> representations.
> 
> Some CRTCs (eg, AMBA CLCD) produce R, G, B signals scrunched down on to
> the LSB bits of a LCD data bus (so RGB888 uses 24 bits, RGB444 would
> use the LSB 12 bits of those 24 - rather than outputting the R4 bits on
> a subset of the R8 bits.)
> 
> What about RGB565 - where you have differing number of bits for the
> green channel from red/blue?
> 
> Then you have red/blue colour swapping at the CRTC (and similar for YUV)
> such as on Dove / Armada.
> 
> Then there are some encoders have the ability to almost arbitarily map
> their input pins according to whatever you choose (eg, TDA998x).
> 
> This problem isn't as quite as simple as "this is what EDID gives us"
> and "these are the number of bits representing a colour".

I think what we need is a way to pass information from whatever device
is behind the encoder (be it a bridge or a panel) to the encoder. And
likely we'll need a similar (or the same) way to pass that information
from bridge to bridge or from bridge to panel.

That way the encoder can ask the bridge (or panel) about the format it
requires and reconfigure itself accordingly. This should be able to work
with an arbitrary bridge -> [bridge... ->] panel chain where each
element in the chain can reconfigure depending on what the next element
requires (or fail if it can't work, which should really never happen).

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
@ 2014-07-21 22:17                                       ` Thierry Reding
  0 siblings, 0 replies; 149+ messages in thread
From: Thierry Reding @ 2014-07-21 22:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 21, 2014 at 06:06:30PM +0100, Russell King - ARM Linux wrote:
> On Mon, Jul 21, 2014 at 03:43:13PM +0200, Boris BREZILLON wrote:
> > How about using a list instead of an array ?
> > This way we can add elements to this list when parsing the EDID.
> > 
> > Or we can just define a maximum size for the bus_formats array when
> > retrieving this info from EDID. If I'm correct we have at most 18 bus
> > formats:
> >  - 3 color formats:
> >    * RGB 4:4:4
> >    * YCbCr 4:4:4
> >    * YCbCr 4:4:2
> >  - 6 color depths: 6, 8, 10, 12, 14 and 16 bits per color
> 
> This starts to worry me.  What are we trying to do here - are we trying
> to encode the connection between the CRTC and the encoder, the encoder
> and the connector, or the connector and the device?

This is about the bus format of the panel device. That would make it the
latter.

> The encoder to connector and connector to device is mostly a function of
> the interface spec itself (for example, many HDMI encoders take either a
> RGB or YUV input and can convert it to the HDMI specified colourspaces for
> transmission over the connector.)

The discussion here started because we currently have no way to store
information about the interface for raw RGB. That means currently all
drivers need to hardcode assumptions about the mode. The idea was to
make this information available via a field in drm_display_info so that
drivers could reconfigure depending on what the attached panel expects.

This doesn't only apply to panels, though, the issue is the same when a
bridge (RGB/LVDS for example) is connected to the encoder.

> If you want to do encoder to connector, what about VGA or some other
> analogue signalling such as TV composite?  It's easy to take this too
> far...
> 
> Surely the only one which matters is the CRTC to the encoder - that's
> certainly true of all the setups I've come across so far.  As for that
> interface, CRTCs I've seen can produce a /wide/ range of different
> representations.
> 
> Some CRTCs (eg, AMBA CLCD) produce R, G, B signals scrunched down on to
> the LSB bits of a LCD data bus (so RGB888 uses 24 bits, RGB444 would
> use the LSB 12 bits of those 24 - rather than outputting the R4 bits on
> a subset of the R8 bits.)
> 
> What about RGB565 - where you have differing number of bits for the
> green channel from red/blue?
> 
> Then you have red/blue colour swapping at the CRTC (and similar for YUV)
> such as on Dove / Armada.
> 
> Then there are some encoders have the ability to almost arbitarily map
> their input pins according to whatever you choose (eg, TDA998x).
> 
> This problem isn't as quite as simple as "this is what EDID gives us"
> and "these are the number of bits representing a colour".

I think what we need is a way to pass information from whatever device
is behind the encoder (be it a bridge or a panel) to the encoder. And
likely we'll need a similar (or the same) way to pass that information
from bridge to bridge or from bridge to panel.

That way the encoder can ask the bridge (or panel) about the format it
requires and reconfigure itself accordingly. This should be able to work
with an arbitrary bridge -> [bridge... ->] panel chain where each
element in the chain can reconfigure depending on what the next element
requires (or fail if it can't work, which should really never happen).

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140722/42d90e28/attachment-0001.sig>

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

end of thread, other threads:[~2014-07-21 22:17 UTC | newest]

Thread overview: 149+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-07 16:42 [RESEND PATCH v3 00/11] drm: add support for Atmel HLCDC Display Controller Boris BREZILLON
2014-07-07 16:42 ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 01/11] mfd: add atmel-hlcdc driver Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 02/11] mfd: add documentation for atmel-hlcdc DT bindings Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 03/11] pwm: add support for atmel-hlcdc-pwm device Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 04/11] pwm: add DT bindings documentation for atmel-hlcdc-pwm driver Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-08  3:45   ` Rob Clark
2014-07-08  7:23     ` Boris BREZILLON
2014-07-08  7:23       ` Boris BREZILLON
2014-07-08 12:49       ` Rob Clark
2014-07-08 12:49         ` Rob Clark
2014-07-08 14:37         ` Boris BREZILLON
2014-07-08 14:37           ` Boris BREZILLON
2014-07-08 15:41           ` Rob Clark
2014-07-08 15:41             ` Rob Clark
2014-07-08 17:08             ` Boris BREZILLON
2014-07-08 17:08               ` Boris BREZILLON
2014-07-08 23:51               ` Matt Roper
2014-07-08 23:51                 ` Matt Roper
2014-07-09  7:14                 ` Boris BREZILLON
2014-07-09  7:14                   ` Boris BREZILLON
2014-07-09 14:02                   ` Daniel Vetter
2014-07-09 14:02                     ` Daniel Vetter
2014-07-09  8:18     ` Boris BREZILLON
2014-07-09  8:18       ` Boris BREZILLON
2014-07-09 11:53       ` Rob Clark
2014-07-09 11:53         ` Rob Clark
2014-07-11 15:17         ` [RFC PATCH] drm: rework flip-work helpers to avoid calling func when the FIFO is full Boris BREZILLON
2014-07-11 15:41           ` Rob Clark
2014-07-11 15:47             ` Boris BREZILLON
2014-07-11 15:57               ` Boris BREZILLON
2014-07-11 16:05               ` Rob Clark
2014-07-12 18:16   ` [RESEND PATCH v3 05/11] drm: add Atmel HLCDC Display Controller support Boris BREZILLON
2014-07-12 18:16     ` Boris BREZILLON
2014-07-12 18:37     ` Rob Clark
2014-07-12 18:37       ` Rob Clark
2014-07-15 11:26       ` Boris BREZILLON
2014-07-15 11:26         ` Boris BREZILLON
2014-07-07 16:42 ` [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver Boris BREZILLON
2014-07-07 16:42   ` Boris BREZILLON
2014-07-10 11:16   ` Laurent Pinchart
2014-07-10 11:16     ` Laurent Pinchart
2014-07-10 12:56     ` Boris BREZILLON
2014-07-10 12:56       ` Boris BREZILLON
2014-07-11 10:37       ` Laurent Pinchart
2014-07-11 10:37         ` Laurent Pinchart
2014-07-11 12:00         ` Boris BREZILLON
2014-07-11 12:00           ` Boris BREZILLON
2014-07-11 12:19           ` Boris BREZILLON
2014-07-11 12:19             ` Boris BREZILLON
2014-07-14 10:18           ` Thierry Reding
2014-07-14 10:18             ` Thierry Reding
2014-07-15 11:45             ` Boris BREZILLON
2014-07-15 11:45               ` Boris BREZILLON
2014-07-14 10:05   ` Thierry Reding
2014-07-14 10:05     ` Thierry Reding
2014-07-15 10:06     ` Boris BREZILLON
2014-07-15 10:06       ` Boris BREZILLON
2014-07-15 10:20       ` Laurent Pinchart
2014-07-15 10:20         ` Laurent Pinchart
2014-07-15 10:37         ` Thierry Reding
2014-07-15 10:37           ` Thierry Reding
2014-07-15 10:43           ` Laurent Pinchart
2014-07-15 10:43             ` Laurent Pinchart
2014-07-15 10:52             ` Thierry Reding
2014-07-15 10:52               ` Thierry Reding
2014-07-15 11:07               ` Laurent Pinchart
2014-07-15 11:07                 ` Laurent Pinchart
2014-07-16 13:05                 ` Boris BREZILLON
2014-07-16 13:05                   ` Boris BREZILLON
2014-07-16 13:20                   ` Laurent Pinchart
2014-07-16 13:20                     ` Laurent Pinchart
2014-07-16 13:20                     ` Laurent Pinchart
2014-07-16 13:44                     ` Boris BREZILLON
2014-07-16 13:44                       ` Boris BREZILLON
2014-07-15 12:14               ` Boris BREZILLON
2014-07-15 12:14                 ` Boris BREZILLON
2014-07-15 10:31       ` Thierry Reding
2014-07-15 10:31         ` Thierry Reding
2014-07-18 14:51         ` Boris BREZILLON
2014-07-18 14:51           ` Boris BREZILLON
2014-07-18 15:43           ` Boris BREZILLON
2014-07-18 15:43             ` Boris BREZILLON
2014-07-21  8:59             ` Thierry Reding
2014-07-21  8:59               ` Thierry Reding
2014-07-21  9:24               ` Boris BREZILLON
2014-07-21  9:24                 ` Boris BREZILLON
2014-07-21  9:32                 ` Laurent Pinchart
2014-07-21  9:32                   ` Laurent Pinchart
2014-07-21  9:57                   ` Boris BREZILLON
2014-07-21  9:57                     ` Boris BREZILLON
2014-07-21 12:12                     ` Thierry Reding
2014-07-21 12:12                       ` Thierry Reding
2014-07-21 12:16                       ` Laurent Pinchart
2014-07-21 12:16                         ` Laurent Pinchart
2014-07-21 12:34                         ` Boris BREZILLON
2014-07-21 12:34                           ` Boris BREZILLON
2014-07-21 12:55                           ` Thierry Reding
2014-07-21 12:55                             ` Thierry Reding
2014-07-21 13:22                             ` Laurent Pinchart
2014-07-21 13:22                               ` Laurent Pinchart
2014-07-21 13:30                               ` Thierry Reding
2014-07-21 13:30                                 ` Thierry Reding
2014-07-21 13:43                                 ` Boris BREZILLON
2014-07-21 13:43                                   ` Boris BREZILLON
2014-07-21 13:47                                   ` Laurent Pinchart
2014-07-21 13:47                                     ` Laurent Pinchart
2014-07-21 13:54                                     ` Thierry Reding
2014-07-21 13:54                                       ` Thierry Reding
2014-07-21 14:21                                       ` Boris BREZILLON
2014-07-21 14:21                                         ` Boris BREZILLON
2014-07-21 18:30                                         ` Laurent Pinchart
2014-07-21 18:30                                           ` Laurent Pinchart
2014-07-21 22:04                                           ` Thierry Reding
2014-07-21 22:04                                             ` Thierry Reding
2014-07-21 14:18                                     ` Boris BREZILLON
2014-07-21 14:18                                       ` Boris BREZILLON
2014-07-21 18:32                                       ` Laurent Pinchart
2014-07-21 18:32                                         ` Laurent Pinchart
2014-07-21 17:06                                   ` Russell King - ARM Linux
2014-07-21 17:06                                     ` Russell King - ARM Linux
2014-07-21 22:17                                     ` Thierry Reding
2014-07-21 22:17                                       ` Thierry Reding
2014-07-21 12:15           ` Thierry Reding
2014-07-21 12:15             ` Thierry Reding
2014-07-21 12:33             ` Boris BREZILLON
2014-07-21 12:33               ` Boris BREZILLON
2014-07-21 12:56               ` Thierry Reding
2014-07-21 12:56                 ` Thierry Reding
2014-07-21 13:26                 ` Laurent Pinchart
2014-07-21 13:26                   ` Laurent Pinchart
2014-07-21 13:33                   ` Thierry Reding
2014-07-21 13:33                     ` Thierry Reding
2014-07-07 16:43 ` [RESEND PATCH v3 07/11] ARM: AT91/dt: split sama5d3 lcd pin definitions to match RGB mode configs Boris BREZILLON
2014-07-07 16:43   ` Boris BREZILLON
2014-07-07 16:43 ` [RESEND PATCH v3 08/11] ARM: AT91/dt: add alternative pin muxing for sama5d3 lcd pins Boris BREZILLON
2014-07-07 16:43   ` Boris BREZILLON
2014-07-07 16:43 ` [RESEND PATCH v3 09/11] ARM: at91/dt: define the HLCDC node available on sama5d3 SoCs Boris BREZILLON
2014-07-07 16:43   ` Boris BREZILLON
2014-07-07 16:43 ` [RESEND PATCH v3 10/11] ARM: at91/dt: add LCD panel description to sama5d3xdm.dtsi Boris BREZILLON
2014-07-07 16:43   ` Boris BREZILLON
2014-07-07 16:43 ` [RESEND PATCH v3 11/11] ARM: at91/dt: enable the LCD panel on sama5d3xek boards Boris BREZILLON
2014-07-07 16:43   ` Boris BREZILLON

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.