dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver
@ 2018-01-12 23:14 Laurent Pinchart
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
                   ` (9 more replies)
  0 siblings, 10 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov, devicetree

Hello,

This patch series addresses a design mistake that dates back from the initial
DU support. Support for the LVDS encoders, which are IP cores separate from
the DU, was bundled in the DU driver. Worse, both the DU and LVDS were
described through a single DT node.

To fix the, patches 01/12 and 02/12 define new DT bindings for the LVDS
encoders, and deprecate their description inside the DU bindings. To retain
backward compatibility with existing DT, patch 03/12 then patches the device
tree at runtime to convert the legacy bindings to the new ones.

With the DT side addressed, patch 04/12 then converts the LVDS support code to
a separate bridge driver. After a small fix to the Porter board device tree in
patch 05/12, patches 06/12 to 12/12 then update all the device tree sources to
the new DU and LVDS encoders bindings.

I decided to go for live DT patching in patch 03/12 because implementing
support for both the legacy and new bindings in the driver would have been
very intrusive, and prevented further cleanups. I'm in a way both proud and 
ashamed of that patch that I would call a neat and dirty hack. It was fun to
write perhaps in a similar way that one would enjoy researching and developing
proof-of-concepts for security holes: they're good and bad at the same time.

Anyway, with this philosophical considerations aside, there were a few
shortcomings in the OF API that I worked around with local code in the driver.
If anyone is interested in performing similar live DT patching I think we
could move some of the code to the OF core. For instance I was surprised
to not find a device node lookup by path function that would start at a
given node instead of the root of the live device tree, and had to write
rcar_du_of_find_node_by_path(). Utility functions to add or modify properties
or to rename nodes could similarly be added.

Compared to v1, this series update the r8a7792 and r8a7794 device tree sources
and incorporate review feedback as described by the changelogs of individual
patches.

Laurent Pinchart (12):
  dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
  dt-bindings: display: renesas: Deprecate LVDS support in the DU
    bindings
  drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  drm: rcar-du: Convert LVDS encoder code to bridge driver
  ARM: dts: porter: Fix HDMI output routing
  ARM: dts: r8a7790: Convert to new LVDS DT bindings
  ARM: dts: r8a7791: Convert to new LVDS DT bindings
  ARM: dts: r8a7792: Convert to new DU DT bindings
  ARM: dts: r8a7793: Convert to new LVDS DT bindings
  ARM: dts: r8a7794: Convert to new DU DT bindings
  arm64: dts: renesas: r8a7795: Convert to new LVDS DT bindings
  arm64: dts: renesas: r8a7796: Convert to new LVDS DT bindings

 .../bindings/display/bridge/renesas,lvds.txt       |  56 +++
 .../devicetree/bindings/display/renesas,du.txt     |  31 +-
 MAINTAINERS                                        |   1 +
 arch/arm/boot/dts/r8a7790-lager.dts                |  22 +-
 arch/arm/boot/dts/r8a7790.dtsi                     |  60 ++-
 arch/arm/boot/dts/r8a7791-koelsch.dts              |  10 +-
 arch/arm/boot/dts/r8a7791-porter.dts               |  18 +-
 arch/arm/boot/dts/r8a7791.dtsi                     |  34 +-
 arch/arm/boot/dts/r8a7792.dtsi                     |   1 -
 arch/arm/boot/dts/r8a7793-gose.dts                 |  10 +-
 arch/arm/boot/dts/r8a7793.dtsi                     |  34 +-
 arch/arm/boot/dts/r8a7794.dtsi                     |   1 -
 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |   3 +-
 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts     |   3 +-
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |   3 +-
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |   3 +-
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           |  34 +-
 arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts     |   3 +-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |   3 +-
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           |  34 +-
 drivers/gpu/drm/rcar-du/Kconfig                    |   6 +-
 drivers/gpu/drm/rcar-du/Makefile                   |   6 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.c              |  21 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   5 -
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c          | 175 +------
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |  12 -
 drivers/gpu/drm/rcar-du/rcar_du_kms.c              |  14 +-
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c          |  93 ----
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h          |  24 -
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c          | 264 ----------
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h          |  64 ---
 drivers/gpu/drm/rcar-du/rcar_du_of.c               | 451 +++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  16 +
 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts        |  82 ++++
 drivers/gpu/drm/rcar-du/rcar_lvds.c                | 546 +++++++++++++++++++++
 35 files changed, 1421 insertions(+), 722 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_lvds.c

-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
@ 2018-01-12 23:14   ` Laurent Pinchart
  2018-01-19 22:47     ` Rob Herring
  2018-01-12 23:14   ` [PATCH v2 02/12] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings Laurent Pinchart
  2018-01-12 23:14   ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
  2 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The Renesas R-Car Gen2 and Gen3 SoCs have internal LVDS encoders. Add
corresponding device tree bindings.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
---
Changes since v1:

- Move the SoC name before the IP name in compatible strings
- Rename parallel input to parallel RGB input
- Fixed "renesas,r8a7743-lvds" description
- Document the resets property
- Fixed typo
---
 .../bindings/display/bridge/renesas,lvds.txt       | 56 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt

diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
new file mode 100644
index 000000000000..2b19ce51ec07
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
@@ -0,0 +1,56 @@
+Renesas R-Car LVDS Encoder
+==========================
+
+These DT bindings describe the LVDS encoder embedded in the Renesas R-Car
+Gen2, R-Car Gen3 and RZ/G SoCs.
+
+Required properties:
+
+- compatible : Shall contain one of
+  - "renesas,r8a7743-lvds" for R8A7743 (RZ/G1M) compatible LVDS encoders
+  - "renesas,r8a7790-lvds" for R8A7790 (R-Car H2) compatible LVDS encoders
+  - "renesas,r8a7791-lvds" for R8A7791 (R-Car M2-W) compatible LVDS encoders
+  - "renesas,r8a7793-lvds" for R8A7791 (R-Car M2-N) compatible LVDS encoders
+  - "renesas,r8a7795-lvds" for R8A7795 (R-Car H3) compatible LVDS encoders
+  - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders
+
+- reg: Base address and length for the memory-mapped registers
+- clocks: A phandle + clock-specifier pair for the functional clock
+- resets: A phandle + reset specifier for the module reset
+
+Required nodes:
+
+The LVDS encoder has two video ports. Their connections are modelled using the
+OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 corresponds to the parallel RGB input
+- Video port 1 corresponds to the LVDS output
+
+Each port shall have a single endpoint.
+
+
+Example:
+
+	lvds0: lvds@feb90000 {
+		compatible = "renesas,r8a7790-lvds";
+		reg = <0 0xfeb90000 0 0x1c>;
+		clocks = <&cpg CPG_MOD 726>;
+		resets = <&cpg 726>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lvds0_in: endpoint {
+					remote-endpoint = <&du_out_lvds0>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				lvds0_out: endpoint {
+				};
+			};
+		};
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index 40aea858c7ea..5609a7f5ac4d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4725,6 +4725,7 @@ F:	drivers/gpu/drm/rcar-du/
 F:	drivers/gpu/drm/shmobile/
 F:	include/linux/platform_data/shmob_drm.h
 F:	Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
+F:	Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
 F:	Documentation/devicetree/bindings/display/renesas,du.txt
 
 DRM DRIVERS FOR ROCKCHIP
-- 
Regards,

Laurent Pinchart

--
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 related	[flat|nested] 38+ messages in thread

* [PATCH v2 02/12] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
  2018-01-12 23:14   ` [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
@ 2018-01-12 23:14   ` Laurent Pinchart
  2018-01-12 23:14   ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
  2 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The internal LVDS encoders now have their own DT bindings, representing
them as part of the DU is deprecated.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
---
Changes since v1:

- Remove the LVDS reg range from the example
- Remove the reg-names property
---
 .../devicetree/bindings/display/renesas,du.txt     | 31 ++++++++--------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt
index cd48aba3bc8c..e79cf9b0ad38 100644
--- a/Documentation/devicetree/bindings/display/renesas,du.txt
+++ b/Documentation/devicetree/bindings/display/renesas,du.txt
@@ -14,12 +14,7 @@ Required Properties:
     - "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU
     - "renesas,du-r8a7796" for R8A7796 (R-Car M3-W) compatible DU
 
-  - reg: A list of base address and length of each memory resource, one for
-    each entry in the reg-names property.
-  - reg-names: Name of the memory resources. The DU requires one memory
-    resource for the DU core (named "du") and one memory resource for each
-    LVDS encoder (named "lvds.x" with "x" being the LVDS controller numerical
-    index).
+  - reg: the memory-mapped I/O registers base address and length
 
   - interrupt-parent: phandle of the parent interrupt controller.
   - interrupts: Interrupt specifiers for the DU interrupts.
@@ -29,14 +24,13 @@ Required Properties:
   - clock-names: Name of the clocks. This property is model-dependent.
     - R8A7779 uses a single functional clock. The clock doesn't need to be
       named.
-    - All other DU instances use one functional clock per channel and one
-      clock per LVDS encoder (if available). The functional clocks must be
-      named "du.x" with "x" being the channel numerical index. The LVDS clocks
-      must be named "lvds.x" with "x" being the LVDS encoder numerical index.
-    - In addition to the functional and encoder clocks, all DU versions also
-      support externally supplied pixel clocks. Those clocks are optional.
-      When supplied they must be named "dclkin.x" with "x" being the input
-      clock numerical index.
+    - All other DU instances use one functional clock per channel The
+      functional clocks must be named "du.x" with "x" being the channel
+      numerical index.
+    - In addition to the functional clocks, all DU versions also support
+      externally supplied pixel clocks. Those clocks are optional. When
+      supplied they must be named "dclkin.x" with "x" being the input clock
+      numerical index.
 
   - vsps: A list of phandle and channel index tuples to the VSPs that handle
     the memory interfaces for the DU channels. The phandle identifies the VSP
@@ -69,9 +63,7 @@ Example: R8A7795 (R-Car H3) ES2.0 DU
 
 	du: display@feb00000 {
 		compatible = "renesas,du-r8a7795";
-		reg = <0 0xfeb00000 0 0x80000>,
-		      <0 0xfeb90000 0 0x14>;
-		reg-names = "du", "lvds.0";
+		reg = <0 0xfeb00000 0 0x80000>;
 		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
@@ -79,9 +71,8 @@ Example: R8A7795 (R-Car H3) ES2.0 DU
 		clocks = <&cpg CPG_MOD 724>,
 			 <&cpg CPG_MOD 723>,
 			 <&cpg CPG_MOD 722>,
-			 <&cpg CPG_MOD 721>,
-			 <&cpg CPG_MOD 727>;
-		clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
+			 <&cpg CPG_MOD 721>;
+		clock-names = "du.0", "du.1", "du.2", "du.3";
 		vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
 
 		ports {
-- 
Regards,

Laurent Pinchart

--
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 related	[flat|nested] 38+ messages in thread

* [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
  2018-01-12 23:14   ` [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
  2018-01-12 23:14   ` [PATCH v2 02/12] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings Laurent Pinchart
@ 2018-01-12 23:14   ` Laurent Pinchart
  2018-01-15 17:09     ` Rob Herring
  2018-01-21  9:35     ` Sergei Shtylyov
  2 siblings, 2 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The internal LVDS encoders now have their own DT bindings. Before
switching the driver infrastructure to those new bindings, implement
backward-compatibility through live DT patching.

Patching is disabled and will be enabled along with support for the new
DT bindings in the DU driver.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
---
Changes since v1:

- Select OF_FLATTREE
- Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
- Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
- Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
- Pass void begin and end pointers to rcar_du_of_get_overlay()
- Use of_get_parent() instead of accessing the parent pointer directly
- Find the LVDS endpoints nodes based on the LVDS node instead of the
  root of the overlay
- Update to the <soc>-lvds compatible string format
---
 drivers/gpu/drm/rcar-du/Kconfig             |   2 +
 drivers/gpu/drm/rcar-du/Makefile            |   3 +-
 drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
 5 files changed, 553 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 5d0b4b7119af..3f83352a7313 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
 	bool "R-Car DU LVDS Encoder Support"
 	depends on DRM_RCAR_DU
 	select DRM_PANEL
+	select OF_FLATTREE
+	select OF_OVERLAY
 	help
 	  Enable support for the R-Car Display Unit embedded LVDS encoders.
 
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 0cf5c11030e8..8ed569a0f462 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -5,10 +5,11 @@ rcar-du-drm-y := rcar_du_crtc.o \
 		 rcar_du_group.o \
 		 rcar_du_kms.o \
 		 rcar_du_lvdscon.o \
+		 rcar_du_of.o \
 		 rcar_du_plane.o
 
 rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o
-
+rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of_lvds.dtb.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c b/drivers/gpu/drm/rcar-du/rcar_du_of.c
new file mode 100644
index 000000000000..2bf91201fc93
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of.c - Legacy DT bindings compatibility
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
+ *
+ * Based on work from Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+
+#ifdef CONFIG_DRM_RCAR_LVDS
+
+struct rcar_du_of_overlay {
+	struct device_node *np;
+	void *data;
+	void *mem;
+};
+
+static void __init rcar_du_of_free_overlay(struct rcar_du_of_overlay *overlay)
+{
+	of_node_put(overlay->np);
+	kfree(overlay->data);
+	kfree(overlay->mem);
+}
+
+static int __init rcar_du_of_get_overlay(struct rcar_du_of_overlay *overlay,
+					 void *begin, void *end)
+{
+	const size_t size = end - begin;
+
+	memset(overlay, 0, sizeof(*overlay));
+
+	if (!size)
+		return -EINVAL;
+
+	overlay->data = kmemdup(begin, size, GFP_KERNEL);
+	if (!overlay->data)
+		return -ENOMEM;
+
+	overlay->mem = of_fdt_unflatten_tree(overlay->data, NULL, &overlay->np);
+	if (!overlay->mem) {
+		rcar_du_of_free_overlay(overlay);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static struct device_node __init *
+rcar_du_of_find_node_by_path(struct device_node *parent, const char *path)
+{
+	parent = of_node_get(parent);
+	if (!parent)
+		return NULL;
+
+	while (parent && *path == '/') {
+		struct device_node *child = NULL;
+		struct device_node *node;
+		const char *next;
+		size_t len;
+
+		/* Skip the initial '/' delimiter and find the next one. */
+		path++;
+		next = strchrnul(path, '/');
+		len = next - path;
+		if (!len)
+			goto error;
+
+		for_each_child_of_node(parent, node) {
+			const char *name = kbasename(node->full_name);
+
+			if (strncmp(path, name, len) == 0 &&
+			    strlen(name) == len) {
+				child = node;
+				break;
+			}
+		}
+
+		if (!child)
+			goto error;
+
+		of_node_put(parent);
+		parent = child;
+		path = next;
+	}
+
+	return parent;
+
+error:
+	of_node_put(parent);
+	return NULL;
+}
+
+static int __init rcar_du_of_add_property(struct device_node *np,
+					  const char *name, const void *value,
+					  size_t length)
+{
+	struct property *prop;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	prop->name = kstrdup(name, GFP_KERNEL);
+	prop->value = kmemdup(value, length, GFP_KERNEL);
+	prop->length = length;
+
+	if (!prop->name || !prop->value) {
+		kfree(prop->name);
+		kfree(prop->value);
+		kfree(prop);
+		return -ENOMEM;
+	}
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->next = np->properties;
+	np->properties = prop;
+
+	return 0;
+}
+
+/* Free properties allocated dynamically by rcar_du_of_add_property(). */
+static void __init rcar_du_of_free_properties(struct device_node *np)
+{
+	while (np->properties) {
+		struct property *prop = np->properties;
+
+		np->properties = prop->next;
+
+		if (OF_IS_DYNAMIC(prop)) {
+			kfree(prop->name);
+			kfree(prop->value);
+			kfree(prop);
+		}
+	}
+}
+
+static int __init rcar_du_of_update_target_path(struct device_node *du,
+						struct device_node *remote,
+						struct device_node *np)
+{
+	struct device_node *target = NULL;
+	struct property **prev;
+	struct property *prop;
+	char *path;
+	int ret;
+
+	for (prop = np->properties, prev = &prop; prop != NULL;
+	     prev = &prop->next, prop = prop->next) {
+		if (of_prop_cmp(prop->name, "target-path"))
+			continue;
+
+		if (!of_prop_cmp(prop->value, "soc")) {
+			target = of_get_parent(du);
+			break;
+		}
+		if (!of_prop_cmp(prop->value, "du")) {
+			target = of_node_get(du);
+			break;
+		}
+		if (!of_prop_cmp(prop->value, "lvds-sink")) {
+			target = of_graph_get_port_parent(remote);
+			break;
+		}
+
+		return -EINVAL;
+	}
+
+	if (!target)
+		return -EINVAL;
+
+	path = kasprintf(GFP_KERNEL, "%pOF", target);
+	of_node_put(target);
+	if (!path)
+		return -ENOMEM;
+
+	/*
+	 * Remove the existing target-path property that has not been
+	 * dynamically allocated and replace it with a new dynamic one to
+	 * ensure that the value will be properly freed.
+	 */
+	*prev = prop->next;
+	ret = rcar_du_of_add_property(np, "target-path", path,
+				      strlen(path) + 1);
+	if (ret < 0) {
+		kfree(path);
+		return ret;
+	}
+
+	return 0;
+}
+
+extern char __dtb_rcar_du_of_lvds_begin[];
+extern char __dtb_rcar_du_of_lvds_end[];
+
+static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
+					     unsigned int port_id,
+					     const struct resource *res,
+					     const __be32 *reg,
+					     const struct of_phandle_args *clkspec,
+					     struct device_node *local,
+					     struct device_node *remote)
+{
+	struct rcar_du_of_overlay overlay;
+	struct device_node *du_port_fixup;
+	struct device_node *du_port;
+	struct device_node *lvds_endpoints[2];
+	struct device_node *lvds;
+	struct device_node *fragment;
+	struct device_node *bus;
+	struct property *prop;
+	const char *compatible;
+	const char *soc_suffix;
+	unsigned int psize;
+	unsigned int i;
+	__be32 value[4];
+	char name[23];
+	int ovcs_id;
+	int ret;
+
+	/* Skip if the LVDS node already exists. */
+	sprintf(name, "lvds@%llx", (u64)res->start);
+	bus = of_get_parent(du);
+	lvds = of_get_child_by_name(bus, name);
+	of_node_put(bus);
+	if (lvds) {
+		of_node_put(lvds);
+		return;
+	}
+
+	/* Parse the overlay. */
+	ret = rcar_du_of_get_overlay(&overlay, __dtb_rcar_du_of_lvds_begin,
+				     __dtb_rcar_du_of_lvds_end);
+	if (ret < 0)
+		return;
+
+	/*
+	 * Patch the LVDS and DU port nodes names and the associated fixup
+	 * entries.
+	 */
+	lvds = rcar_du_of_find_node_by_path(overlay.np,
+		"/fragment@0/__overlay__/lvds");
+	lvds_endpoints[0] = rcar_du_of_find_node_by_path(lvds,
+		"/ports/port@0/endpoint");
+	lvds_endpoints[1] = rcar_du_of_find_node_by_path(lvds,
+		"/ports/port@1/endpoint");
+	du_port = rcar_du_of_find_node_by_path(overlay.np,
+		"/fragment@1/__overlay__/ports/port@0");
+	du_port_fixup = rcar_du_of_find_node_by_path(overlay.np,
+		"/__local_fixups__/fragment@1/__overlay__/ports/port@0");
+	if (!lvds || !lvds_endpoints[0] || !lvds_endpoints[1] ||
+	    !du_port || !du_port_fixup)
+		goto out_put_nodes;
+
+	lvds->full_name = kstrdup(name, GFP_KERNEL);
+
+	sprintf(name, "port@%u", port_id);
+	du_port->full_name = kstrdup(name, GFP_KERNEL);
+	du_port_fixup->full_name = kstrdup(name, GFP_KERNEL);
+
+	if (!lvds->full_name || !du_port->full_name ||
+	    !du_port_fixup->full_name)
+		goto out_free_names;
+
+	/* Patch the target paths in all fragments. */
+	for_each_child_of_node(overlay.np, fragment) {
+		if (strncmp("fragment@", of_node_full_name(fragment), 9))
+			continue;
+
+		ret = rcar_du_of_update_target_path(du, remote, fragment);
+		if (ret < 0) {
+			of_node_put(fragment);
+			goto out_free_properties;
+		}
+	}
+
+	/*
+	 * Create a compatible string for the LVDS node using the SoC model
+	 * from the DU node.
+	 */
+	ret = of_property_read_string(du, "compatible", &compatible);
+	if (ret < 0)
+		goto out_free_properties;
+
+	soc_suffix = strchr(compatible, '-');
+	if (!soc_suffix || strlen(soc_suffix) > 10)
+		goto out_free_properties;
+
+	psize = sprintf(name, "renesas,%s-lvds", soc_suffix + 1) + 1;
+	ret = rcar_du_of_add_property(lvds, "compatible", name, psize);
+	if (ret < 0)
+		goto out_free_properties;
+
+	/* Copy the LVDS reg and clocks properties from the DU node. */
+	psize = (of_n_addr_cells(du) + of_n_size_cells(du)) * 4;
+	ret = rcar_du_of_add_property(lvds, "reg", reg, psize);
+	if (ret < 0)
+		goto out_free_properties;
+
+	if (clkspec->args_count >= ARRAY_SIZE(value) - 1)
+		goto out_free_properties;
+
+	value[0] = cpu_to_be32(clkspec->np->phandle);
+	for (i = 0; i < clkspec->args_count; ++i)
+		value[i + 1] = cpu_to_be32(clkspec->args[i]);
+
+	psize = (clkspec->args_count + 1) * 4;
+	ret = rcar_du_of_add_property(lvds, "clocks", value, psize);
+	if (ret < 0)
+		goto out_free_properties;
+
+	/*
+	 * Insert the node in the OF graph: patch the LVDS ports remote-endpoint
+	 * properties to point to the endpoints of the sibling nodes in the
+	 * graph.
+	 */
+	prop = of_find_property(lvds_endpoints[0], "remote-endpoint", NULL);
+	if (!prop)
+		goto out_free_properties;
+
+	*(__be32 *)prop->value = cpu_to_be32(local->phandle);
+
+	prop = of_find_property(lvds_endpoints[1], "remote-endpoint", NULL);
+	if (!prop)
+		goto out_free_properties;
+
+	*(__be32 *)prop->value = cpu_to_be32(remote->phandle);
+
+	/* Apply the overlay, this will resolve phandles. */
+	ovcs_id = 0;
+	ret = of_overlay_apply(overlay.np, &ovcs_id);
+
+	/* We're done, free all allocated memory. */
+out_free_properties:
+	rcar_du_of_free_properties(lvds);
+	rcar_du_of_free_properties(du_port);
+	rcar_du_of_free_properties(du_port_fixup);
+out_free_names:
+	kfree(lvds->full_name);
+	kfree(du_port->full_name);
+	kfree(du_port_fixup->full_name);
+out_put_nodes:
+	of_node_put(lvds);
+	of_node_put(lvds_endpoints[0]);
+	of_node_put(lvds_endpoints[1]);
+	of_node_put(du_port);
+	of_node_put(du_port_fixup);
+
+	rcar_du_of_free_overlay(&overlay);
+}
+
+static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
+{
+	const struct rcar_du_device_info *info;
+	const struct of_device_id *match;
+	struct device_node *du;
+	unsigned int i;
+	int ret;
+
+	/* Get the DU node and exit if not present or disabled. */
+	du = of_find_matching_node_and_match(NULL, of_ids, &match);
+	if (!du || !of_device_is_available(du))
+		goto done;
+
+	info = match->data;
+
+	/* Patch every LVDS encoder. */
+	for (i = 0; i < info->num_lvds; ++i) {
+		struct of_phandle_args clkspec;
+		struct device_node *local, *remote;
+		struct resource res;
+		unsigned int port_id;
+		const __be32 *reg;
+		char name[7];
+		int index;
+
+		/*
+		 * Retrieve the register specifier, the clock specifier and the
+		 * local and remote endpoints of the LVDS link.
+		 */
+		sprintf(name, "lvds.%u", i);
+		index = of_property_match_string(du, "reg-names", name);
+		if (index < 0)
+			continue;
+
+		reg = of_get_address(du, index, NULL, NULL);
+		if (!reg)
+			continue;
+
+		ret = of_address_to_resource(du, index, &res);
+		if (ret < 0)
+			continue;
+
+		index = of_property_match_string(du, "clock-names", name);
+		if (index < 0)
+			continue;
+
+		ret = of_parse_phandle_with_args(du, "clocks", "#clock-cells",
+						 index, &clkspec);
+		if (ret < 0)
+			continue;
+
+		port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
+
+		local = of_graph_get_endpoint_by_regs(du, port_id, 0);
+		if (!local) {
+			of_node_put(clkspec.np);
+			continue;
+		}
+
+		remote = of_graph_get_remote_endpoint(local);
+		if (!remote) {
+			of_node_put(local);
+			of_node_put(clkspec.np);
+			continue;
+		}
+
+		/* Patch the LVDS encoder. */
+		rcar_du_of_lvds_patch_one(du, port_id, &res, reg, &clkspec,
+					  local, remote);
+
+		of_node_put(clkspec.np);
+		of_node_put(remote);
+		of_node_put(local);
+	}
+
+done:
+	of_node_put(du);
+}
+#else
+static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
+{
+}
+#endif /* CONFIG_DRM_RCAR_LVDS */
+
+void __init rcar_du_of_init(const struct of_device_id *of_ids)
+{
+	rcar_du_of_lvds_patch(of_ids);
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h b/drivers/gpu/drm/rcar-du/rcar_du_of.h
new file mode 100644
index 000000000000..7105eaef58c6
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of.h - Legacy DT bindings compatibility
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
+ */
+#ifndef __RCAR_DU_OF_H__
+#define __RCAR_DU_OF_H__
+
+#include <linux/init.h>
+
+struct of_device_id;
+
+void __init rcar_du_of_init(const struct of_device_id *of_ids);
+
+#endif /* __RCAR_DU_OF_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
new file mode 100644
index 000000000000..bc75c7a1c3bd
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds.dts - Legacy LVDS DT bindings conversion
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
+ *
+ * Based on work from Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/*
+ * The target-paths, lvds node name, DU port number and LVDS remote endpoints
+ * will be patched dynamically at runtime.
+ */
+
+/dts-v1/;
+/ {
+	fragment@0 {
+		target-path = "soc";
+		__overlay__ {
+			lvds {
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds_input: endpoint {
+							remote-endpoint = <0>;
+						};
+					};
+
+					port@1 {
+						reg = <1>;
+						lvds_output: endpoint {
+							remote-endpoint = <0>;
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "du";
+		__overlay__ {
+			ports {
+				port@0 {
+					endpoint {
+						remote-endpoint = <&lvds_input>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target-path = "lvds-sink";
+		__overlay__ {
+			remote-endpoint = <&lvds_output>;
+		};
+	};
+
+	__local_fixups__ {
+		fragment@1 {
+			__overlay__ {
+				ports {
+					port@0 {
+						endpoint {
+							remote-endpoint	= <0>;
+						};
+					};
+				};
+			};
+		};
+		fragment@2 {
+			__overlay__ {
+				remote-endpoint	= <0>;
+			};
+		};
+	};
+};
-- 
Regards,

Laurent Pinchart

--
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 related	[flat|nested] 38+ messages in thread

* [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-15  8:30   ` Geert Uytterhoeven
  2018-01-15 20:25   ` Sergei Shtylyov
  2018-01-12 23:14 ` [PATCH v2 05/12] ARM: dts: porter: Fix HDMI output routing Laurent Pinchart
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The LVDS encoders used to be described in DT as part of the DU. They now
have their own DT node, linked to the DU using the OF graph bindings.
This allows moving internal LVDS encoder support to a separate driver
modelled as a DRM bridge. Backward compatibility is retained as legacy
DT is patched live to move to the new bindings.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
- Update to the <soc>-lvds compatible string format
---
 drivers/gpu/drm/rcar-du/Kconfig           |   4 +-
 drivers/gpu/drm/rcar-du/Makefile          |   3 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.c     |  21 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h     |   5 -
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 175 +---------
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  12 -
 drivers/gpu/drm/rcar-du/rcar_du_kms.c     |  14 +-
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c |  93 -----
 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h |  24 --
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 264 ---------------
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h |  64 ----
 drivers/gpu/drm/rcar-du/rcar_lvds.c       | 546 ++++++++++++++++++++++++++++++
 12 files changed, 583 insertions(+), 642 deletions(-)
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
 delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_lvds.c

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 3f83352a7313..edde8d4b87a3 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -19,8 +19,8 @@ config DRM_RCAR_DW_HDMI
 	  Enable support for R-Car Gen3 internal HDMI encoder.
 
 config DRM_RCAR_LVDS
-	bool "R-Car DU LVDS Encoder Support"
-	depends on DRM_RCAR_DU
+	tristate "R-Car DU LVDS Encoder Support"
+	depends on DRM && DRM_BRIDGE && OF
 	select DRM_PANEL
 	select OF_FLATTREE
 	select OF_OVERLAY
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 8ed569a0f462..247df6a3c81d 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -4,13 +4,12 @@ rcar-du-drm-y := rcar_du_crtc.o \
 		 rcar_du_encoder.o \
 		 rcar_du_group.o \
 		 rcar_du_kms.o \
-		 rcar_du_lvdscon.o \
 		 rcar_du_of.o \
 		 rcar_du_plane.o
 
-rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of_lvds.dtb.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
 obj-$(CONFIG_DRM_RCAR_DW_HDMI)		+= rcar_dw_hdmi.o
+obj-$(CONFIG_DRM_RCAR_LVDS)		+= rcar_lvds.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 6e02c762a557..06a3fbdd728a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -29,6 +29,7 @@
 
 #include "rcar_du_drv.h"
 #include "rcar_du_kms.h"
+#include "rcar_du_of.h"
 #include "rcar_du_regs.h"
 
 /* -----------------------------------------------------------------------------
@@ -74,7 +75,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
 			.port = 1,
 		},
 	},
-	.num_lvds = 0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
@@ -95,14 +95,13 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
 			.port = 1,
 		},
 	},
-	.num_lvds = 0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
 	.gen = 2,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
-	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
+	.quirks = RCAR_DU_QUIRK_ALIGN_128B,
 	.num_crtcs = 3,
 	.routes = {
 		/*
@@ -164,7 +163,6 @@ static const struct rcar_du_device_info rcar_du_r8a7792_info = {
 			.port = 1,
 		},
 	},
-	.num_lvds = 0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
@@ -186,7 +184,6 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = {
 			.port = 1,
 		},
 	},
-	.num_lvds = 0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
@@ -434,7 +431,19 @@ static struct platform_driver rcar_du_platform_driver = {
 	},
 };
 
-module_platform_driver(rcar_du_platform_driver);
+static int __init rcar_du_init(void)
+{
+	rcar_du_of_init(rcar_du_of_table);
+
+	return platform_driver_register(&rcar_du_platform_driver);
+}
+module_init(rcar_du_init);
+
+static void __exit rcar_du_exit(void)
+{
+	platform_driver_unregister(&rcar_du_platform_driver);
+}
+module_exit(rcar_du_exit);
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index f400fde65a0c..5c7ec15818c7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -26,14 +26,12 @@ struct device;
 struct drm_device;
 struct drm_fbdev_cma;
 struct rcar_du_device;
-struct rcar_du_lvdsenc;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
 #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
 #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
 
 #define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
-#define RCAR_DU_QUIRK_LVDS_LANES	(1 << 1)	/* LVDS lanes 1 and 3 inverted */
 
 /*
  * struct rcar_du_output_routing - Output routing specification
@@ -70,7 +68,6 @@ struct rcar_du_device_info {
 
 #define RCAR_DU_MAX_CRTCS		4
 #define RCAR_DU_MAX_GROUPS		DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2)
-#define RCAR_DU_MAX_LVDS		2
 #define RCAR_DU_MAX_VSPS		4
 
 struct rcar_du_device {
@@ -96,8 +93,6 @@ struct rcar_du_device {
 
 	unsigned int dpad0_source;
 	unsigned int vspd1_sink;
-
-	struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
 };
 
 static inline bool rcar_du_has(struct rcar_du_device *rcdu,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index ba8d2804c1d1..f9c933d3bae6 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -21,134 +21,22 @@
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_kms.h"
-#include "rcar_du_lvdscon.h"
-#include "rcar_du_lvdsenc.h"
 
 /* -----------------------------------------------------------------------------
  * Encoder
  */
 
-static void rcar_du_encoder_disable(struct drm_encoder *encoder)
-{
-	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-
-	if (renc->connector && renc->connector->panel) {
-		drm_panel_disable(renc->connector->panel);
-		drm_panel_unprepare(renc->connector->panel);
-	}
-
-	if (renc->lvds)
-		rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false);
-}
-
-static void rcar_du_encoder_enable(struct drm_encoder *encoder)
-{
-	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-
-	if (renc->lvds)
-		rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true);
-
-	if (renc->connector && renc->connector->panel) {
-		drm_panel_prepare(renc->connector->panel);
-		drm_panel_enable(renc->connector->panel);
-	}
-}
-
-static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
-	const struct drm_display_mode *mode = &crtc_state->mode;
-	struct drm_connector *connector = conn_state->connector;
-	struct drm_device *dev = encoder->dev;
-
-	/*
-	 * Only panel-related encoder types require validation here, everything
-	 * else is handled by the bridge drivers.
-	 */
-	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-		const struct drm_display_mode *panel_mode;
-
-		if (list_empty(&connector->modes)) {
-			dev_dbg(dev->dev, "encoder: empty modes list\n");
-			return -EINVAL;
-		}
-
-		panel_mode = list_first_entry(&connector->modes,
-					      struct drm_display_mode, head);
-
-		/* We're not allowed to modify the resolution. */
-		if (mode->hdisplay != panel_mode->hdisplay ||
-		    mode->vdisplay != panel_mode->vdisplay)
-			return -EINVAL;
-
-		/*
-		 * The flat panel mode is fixed, just copy it to the adjusted
-		 * mode.
-		 */
-		drm_mode_copy(adjusted_mode, panel_mode);
-	}
-
-	if (renc->lvds)
-		rcar_du_lvdsenc_atomic_check(renc->lvds, adjusted_mode);
-
-	return 0;
-}
-
 static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
 				     struct drm_crtc_state *crtc_state,
 				     struct drm_connector_state *conn_state)
 {
 	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
-	struct drm_display_info *info = &conn_state->connector->display_info;
-	enum rcar_lvds_mode mode;
 
 	rcar_du_crtc_route_output(crtc_state->crtc, renc->output);
-
-	if (!renc->lvds) {
-		/*
-		 * The DU driver creates connectors only for the outputs of the
-		 * internal LVDS encoders.
-		 */
-		renc->connector = NULL;
-		return;
-	}
-
-	renc->connector = to_rcar_connector(conn_state->connector);
-
-	if (!info->num_bus_formats || !info->bus_formats) {
-		dev_err(encoder->dev->dev, "no LVDS bus format reported\n");
-		return;
-	}
-
-	switch (info->bus_formats[0]) {
-	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
-	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
-		mode = RCAR_LVDS_MODE_JEIDA;
-		break;
-	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
-		mode = RCAR_LVDS_MODE_VESA;
-		break;
-	default:
-		dev_err(encoder->dev->dev,
-			"unsupported LVDS bus format 0x%04x\n",
-			info->bus_formats[0]);
-		return;
-	}
-
-	if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
-		mode |= RCAR_LVDS_MODE_MIRROR;
-
-	rcar_du_lvdsenc_set_mode(renc->lvds, mode);
 }
 
 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
 	.atomic_mode_set = rcar_du_encoder_mode_set,
-	.disable = rcar_du_encoder_disable,
-	.enable = rcar_du_encoder_enable,
-	.atomic_check = rcar_du_encoder_atomic_check,
 };
 
 static const struct drm_encoder_funcs encoder_funcs = {
@@ -172,33 +60,14 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 	renc->output = output;
 	encoder = rcar_encoder_to_drm_encoder(renc);
 
-	switch (output) {
-	case RCAR_DU_OUTPUT_LVDS0:
-		renc->lvds = rcdu->lvds[0];
-		break;
+	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
+		enc_node, output);
 
-	case RCAR_DU_OUTPUT_LVDS1:
-		renc->lvds = rcdu->lvds[1];
-		break;
-
-	default:
-		break;
-	}
-
-	if (enc_node) {
-		dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
-			enc_node, output);
-
-		/* Locate the DRM bridge from the encoder DT node. */
-		bridge = of_drm_find_bridge(enc_node);
-		if (!bridge) {
-			ret = -EPROBE_DEFER;
-			goto done;
-		}
-	} else {
-		dev_dbg(rcdu->dev,
-			"initializing internal encoder for output %u\n",
-			output);
+	/* Locate the DRM bridge from the encoder DT node. */
+	bridge = of_drm_find_bridge(enc_node);
+	if (!bridge) {
+		ret = -EPROBE_DEFER;
+		goto done;
 	}
 
 	ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
@@ -208,28 +77,14 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 
 	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
 
-	if (bridge) {
-		/*
-		 * Attach the bridge to the encoder. The bridge will create the
-		 * connector.
-		 */
-		ret = drm_bridge_attach(encoder, bridge, NULL);
-		if (ret) {
-			drm_encoder_cleanup(encoder);
-			return ret;
-		}
-	} else {
-		/* There's no bridge, create the connector manually. */
-		switch (output) {
-		case RCAR_DU_OUTPUT_LVDS0:
-		case RCAR_DU_OUTPUT_LVDS1:
-			ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
-			break;
-
-		default:
-			ret = -EINVAL;
-			break;
-		}
+	/*
+	 * Attach the bridge to the encoder. The bridge will create the
+	 * connector.
+	 */
+	ret = drm_bridge_attach(encoder, bridge, NULL);
+	if (ret) {
+		drm_encoder_cleanup(encoder);
+		return ret;
 	}
 
 done:
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 5422fa4df272..2d2abcacd169 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -19,13 +19,10 @@
 
 struct drm_panel;
 struct rcar_du_device;
-struct rcar_du_lvdsenc;
 
 struct rcar_du_encoder {
 	struct drm_encoder base;
 	enum rcar_du_output output;
-	struct rcar_du_connector *connector;
-	struct rcar_du_lvdsenc *lvds;
 };
 
 #define to_rcar_encoder(e) \
@@ -33,15 +30,6 @@ struct rcar_du_encoder {
 
 #define rcar_encoder_to_drm_encoder(e)	(&(e)->base)
 
-struct rcar_du_connector {
-	struct drm_connector connector;
-	struct rcar_du_encoder *encoder;
-	struct drm_panel *panel;
-};
-
-#define to_rcar_connector(c) \
-	container_of(c, struct rcar_du_connector, connector)
-
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 			 enum rcar_du_output output,
 			 struct device_node *enc_node,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 566d1a948c8f..0329b354bfa0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -27,7 +27,6 @@
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_kms.h"
-#include "rcar_du_lvdsenc.h"
 #include "rcar_du_regs.h"
 #include "rcar_du_vsp.h"
 
@@ -341,11 +340,10 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 	of_node_put(entity_ep_node);
 
 	if (!encoder) {
-		/*
-		 * If no encoder has been found the entity must be the
-		 * connector.
-		 */
-		connector = entity;
+		dev_warn(rcdu->dev,
+			 "no encoder found for endpoint %pOF, skipping\n",
+			 ep->local_node);
+		return -ENODEV;
 	}
 
 	ret = rcar_du_encoder_init(rcdu, output, encoder, connector);
@@ -595,10 +593,6 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
 	}
 
 	/* Initialize the encoders. */
-	ret = rcar_du_lvdsenc_init(rcdu);
-	if (ret < 0)
-		return ret;
-
 	ret = rcar_du_encoders_init(rcdu);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
deleted file mode 100644
index e96f2df0c305..000000000000
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * rcar_du_lvdscon.c  --  R-Car Display Unit LVDS Connector
- *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
- *
- * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_panel.h>
-
-#include <video/display_timing.h>
-#include <video/of_display_timing.h>
-#include <video/videomode.h>
-
-#include "rcar_du_drv.h"
-#include "rcar_du_encoder.h"
-#include "rcar_du_kms.h"
-#include "rcar_du_lvdscon.h"
-
-static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector)
-{
-	struct rcar_du_connector *rcon = to_rcar_connector(connector);
-
-	return drm_panel_get_modes(rcon->panel);
-}
-
-static const struct drm_connector_helper_funcs connector_helper_funcs = {
-	.get_modes = rcar_du_lvds_connector_get_modes,
-};
-
-static void rcar_du_lvds_connector_destroy(struct drm_connector *connector)
-{
-	struct rcar_du_connector *rcon = to_rcar_connector(connector);
-
-	drm_panel_detach(rcon->panel);
-	drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs connector_funcs = {
-	.reset = drm_atomic_helper_connector_reset,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = rcar_du_lvds_connector_destroy,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
-				struct rcar_du_encoder *renc,
-				const struct device_node *np)
-{
-	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
-	struct rcar_du_connector *rcon;
-	struct drm_connector *connector;
-	int ret;
-
-	rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);
-	if (rcon == NULL)
-		return -ENOMEM;
-
-	connector = &rcon->connector;
-
-	rcon->panel = of_drm_find_panel(np);
-	if (!rcon->panel)
-		return -EPROBE_DEFER;
-
-	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
-				 DRM_MODE_CONNECTOR_LVDS);
-	if (ret < 0)
-		return ret;
-
-	drm_connector_helper_add(connector, &connector_helper_funcs);
-
-	ret = drm_mode_connector_attach_encoder(connector, encoder);
-	if (ret < 0)
-		return ret;
-
-	ret = drm_panel_attach(rcon->panel, connector);
-	if (ret < 0)
-		return ret;
-
-	rcon->encoder = renc;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
deleted file mode 100644
index 639071dd235c..000000000000
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * rcar_du_lvdscon.h  --  R-Car Display Unit LVDS Connector
- *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
- *
- * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __RCAR_DU_LVDSCON_H__
-#define __RCAR_DU_LVDSCON_H__
-
-struct rcar_du_device;
-struct rcar_du_encoder;
-
-int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
-				struct rcar_du_encoder *renc,
-				const struct device_node *np);
-
-#endif /* __RCAR_DU_LVDSCON_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
deleted file mode 100644
index b37c255c3d93..000000000000
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * rcar_du_lvdsenc.c  --  R-Car Display Unit LVDS Encoder
- *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
- *
- * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "rcar_du_drv.h"
-#include "rcar_du_encoder.h"
-#include "rcar_du_lvdsenc.h"
-#include "rcar_lvds_regs.h"
-
-struct rcar_du_lvdsenc {
-	struct rcar_du_device *dev;
-
-	unsigned int index;
-	void __iomem *mmio;
-	struct clk *clock;
-	bool enabled;
-
-	enum rcar_lvds_input input;
-	enum rcar_lvds_mode mode;
-};
-
-static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
-{
-	iowrite32(data, lvds->mmio + reg);
-}
-
-static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
-				       struct rcar_du_crtc *rcrtc)
-{
-	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
-	unsigned int freq = mode->clock;
-	u32 lvdcr0;
-	u32 pllcr;
-
-	/* PLL clock configuration */
-	if (freq < 39000)
-		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
-	else if (freq < 61000)
-		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
-	else if (freq < 121000)
-		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
-	else
-		pllcr = LVDPLLCR_PLLDLYCNT_150M;
-
-	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
-
-	/* Turn all the channels on. */
-	rcar_lvds_write(lvds, LVDCR1,
-			LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
-			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
-
-	/*
-	 * Set the  LVDS mode, select the input, enable LVDS operation,
-	 * and turn bias circuitry on.
-	 */
-	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN;
-	if (rcrtc->index == 2)
-		lvdcr0 |= LVDCR0_DUSEL;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-
-	/*
-	 * Turn the PLL on, wait for the startup delay, and turn the output
-	 * on.
-	 */
-	lvdcr0 |= LVDCR0_PLLON;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-
-	usleep_range(100, 150);
-
-	lvdcr0 |= LVDCR0_LVRES;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-}
-
-static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
-				       struct rcar_du_crtc *rcrtc)
-{
-	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
-	unsigned int freq = mode->clock;
-	u32 lvdcr0;
-	u32 pllcr;
-
-	/* PLL clock configuration */
-	if (freq < 42000)
-		pllcr = LVDPLLCR_PLLDIVCNT_42M;
-	else if (freq < 85000)
-		pllcr = LVDPLLCR_PLLDIVCNT_85M;
-	else if (freq < 128000)
-		pllcr = LVDPLLCR_PLLDIVCNT_128M;
-	else
-		pllcr = LVDPLLCR_PLLDIVCNT_148M;
-
-	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
-
-	/* Turn all the channels on. */
-	rcar_lvds_write(lvds, LVDCR1,
-			LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
-			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
-
-	/*
-	 * Turn the PLL on, set it to LVDS normal mode, wait for the startup
-	 * delay and turn the output on.
-	 */
-	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-
-	lvdcr0 |= LVDCR0_PWD;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-
-	usleep_range(100, 150);
-
-	lvdcr0 |= LVDCR0_LVRES;
-	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-}
-
-static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
-				 struct rcar_du_crtc *rcrtc)
-{
-	u32 lvdhcr;
-	int ret;
-
-	if (lvds->enabled)
-		return 0;
-
-	ret = clk_prepare_enable(lvds->clock);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * Hardcode the channels and control signals routing for now.
-	 *
-	 * HSYNC -> CTRL0
-	 * VSYNC -> CTRL1
-	 * DISP  -> CTRL2
-	 * 0     -> CTRL3
-	 */
-	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
-			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
-			LVDCTRCR_CTR0SEL_HSYNC);
-
-	if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
-	else
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
-
-	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
-
-	/* Perform generation-specific initialization. */
-	if (lvds->dev->info->gen < 3)
-		rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
-	else
-		rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
-
-	lvds->enabled = true;
-
-	return 0;
-}
-
-static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
-{
-	if (!lvds->enabled)
-		return;
-
-	rcar_lvds_write(lvds, LVDCR0, 0);
-	rcar_lvds_write(lvds, LVDCR1, 0);
-
-	clk_disable_unprepare(lvds->clock);
-
-	lvds->enabled = false;
-}
-
-int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
-			   bool enable)
-{
-	if (!enable) {
-		rcar_du_lvdsenc_stop(lvds);
-		return 0;
-	} else if (crtc) {
-		struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
-		return rcar_du_lvdsenc_start(lvds, rcrtc);
-	} else
-		return -EINVAL;
-}
-
-void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
-				  struct drm_display_mode *mode)
-{
-	/*
-	 * The internal LVDS encoder has a restricted clock frequency operating
-	 * range (31MHz to 148.5MHz). Clamp the clock accordingly.
-	 */
-	mode->clock = clamp(mode->clock, 31000, 148500);
-}
-
-void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
-			      enum rcar_lvds_mode mode)
-{
-	lvds->mode = mode;
-}
-
-static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
-					 struct platform_device *pdev)
-{
-	struct resource *mem;
-	char name[7];
-
-	sprintf(name, "lvds.%u", lvds->index);
-
-	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-	lvds->mmio = devm_ioremap_resource(&pdev->dev, mem);
-	if (IS_ERR(lvds->mmio))
-		return PTR_ERR(lvds->mmio);
-
-	lvds->clock = devm_clk_get(&pdev->dev, name);
-	if (IS_ERR(lvds->clock)) {
-		dev_err(&pdev->dev, "failed to get clock for %s\n", name);
-		return PTR_ERR(lvds->clock);
-	}
-
-	return 0;
-}
-
-int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
-{
-	struct platform_device *pdev = to_platform_device(rcdu->dev);
-	struct rcar_du_lvdsenc *lvds;
-	unsigned int i;
-	int ret;
-
-	for (i = 0; i < rcdu->info->num_lvds; ++i) {
-		lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
-		if (lvds == NULL)
-			return -ENOMEM;
-
-		lvds->dev = rcdu;
-		lvds->index = i;
-		lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
-		lvds->enabled = false;
-
-		ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
-		if (ret < 0)
-			return ret;
-
-		rcdu->lvds[i] = lvds;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
deleted file mode 100644
index 7218ac89333e..000000000000
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * rcar_du_lvdsenc.h  --  R-Car Display Unit LVDS Encoder
- *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
- *
- * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __RCAR_DU_LVDSENC_H__
-#define __RCAR_DU_LVDSENC_H__
-
-#include <linux/io.h>
-#include <linux/module.h>
-
-struct rcar_drm_crtc;
-struct rcar_du_lvdsenc;
-
-enum rcar_lvds_input {
-	RCAR_LVDS_INPUT_DU0,
-	RCAR_LVDS_INPUT_DU1,
-	RCAR_LVDS_INPUT_DU2,
-};
-
-/* Keep in sync with the LVDCR0.LVMD hardware register values. */
-enum rcar_lvds_mode {
-	RCAR_LVDS_MODE_JEIDA = 0,
-	RCAR_LVDS_MODE_MIRROR = 1,
-	RCAR_LVDS_MODE_VESA = 4,
-};
-
-#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
-int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu);
-void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
-			      enum rcar_lvds_mode mode);
-int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
-			   struct drm_crtc *crtc, bool enable);
-void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
-				  struct drm_display_mode *mode);
-#else
-static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
-{
-	return 0;
-}
-static inline void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
-					    enum rcar_lvds_mode mode)
-{
-}
-static inline int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
-					 struct drm_crtc *crtc, bool enable)
-{
-	return 0;
-}
-static inline void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
-						struct drm_display_mode *mode)
-{
-}
-#endif
-
-#endif /* __RCAR_DU_LVDSENC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
new file mode 100644
index 000000000000..68c1c168e8bf
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_lvds.c  --  R-Car LVDS Encoder
+ *
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "rcar_lvds_regs.h"
+
+/* Keep in sync with the LVDCR0.LVMD hardware register values. */
+enum rcar_lvds_mode {
+	RCAR_LVDS_MODE_JEIDA = 0,
+	RCAR_LVDS_MODE_MIRROR = 1,
+	RCAR_LVDS_MODE_VESA = 4,
+};
+
+#define RCAR_LVDS_QUIRK_LANES	(1 << 0)	/* LVDS lanes 1 and 3 inverted */
+
+struct rcar_lvds_device_info {
+	unsigned int gen;
+	unsigned int quirks;
+};
+
+struct rcar_lvds {
+	struct device *dev;
+	const struct rcar_lvds_device_info *info;
+
+	struct drm_bridge bridge;
+
+	struct drm_bridge *next_bridge;
+	struct drm_connector connector;
+	struct drm_panel *panel;
+
+	void __iomem *mmio;
+	struct clk *clock;
+	bool enabled;
+
+	struct drm_display_mode display_mode;
+	enum rcar_lvds_mode mode;
+};
+
+#define bridge_to_rcar_lvds(bridge) \
+	container_of(bridge, struct rcar_lvds, bridge)
+
+#define connector_to_rcar_lvds(connector) \
+	container_of(connector, struct rcar_lvds, connector)
+
+static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
+{
+	iowrite32(data, lvds->mmio + reg);
+}
+
+/* -----------------------------------------------------------------------------
+ * Connector & Panel
+ */
+
+static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
+{
+	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
+
+	return drm_panel_get_modes(lvds->panel);
+}
+
+static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
+					    struct drm_connector_state *state)
+{
+	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
+	const struct drm_display_mode *panel_mode;
+	struct drm_crtc_state *crtc_state;
+
+	if (list_empty(&connector->modes)) {
+		dev_dbg(lvds->dev, "connector: empty modes list\n");
+		return -EINVAL;
+	}
+
+	panel_mode = list_first_entry(&connector->modes,
+				      struct drm_display_mode, head);
+
+	/* We're not allowed to modify the resolution. */
+	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
+	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
+		return -EINVAL;
+
+	/* The flat panel mode is fixed, just copy it to the adjusted mode. */
+	drm_mode_copy(&crtc_state->adjusted_mode, panel_mode);
+
+	return 0;
+}
+
+static const struct drm_connector_helper_funcs rcar_lvds_conn_helper_funcs = {
+	.get_modes = rcar_lvds_connector_get_modes,
+	.atomic_check = rcar_lvds_connector_atomic_check,
+};
+
+static const struct drm_connector_funcs rcar_lvds_conn_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * Bridge
+ */
+
+static void rcar_lvds_enable_gen2(struct rcar_lvds *lvds)
+{
+	const struct drm_display_mode *mode = &lvds->display_mode;
+	/*
+	 * FIXME: We should really retrieve this through the state, but how do
+	 * we get a state pointer?
+	 */
+	struct drm_crtc *crtc = lvds->bridge.encoder->crtc;
+	unsigned int freq = mode->clock;
+	u32 lvdcr0;
+	u32 pllcr;
+
+	/* PLL clock configuration */
+	if (freq < 39000)
+		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
+	else if (freq < 61000)
+		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
+	else if (freq < 121000)
+		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
+	else
+		pllcr = LVDPLLCR_PLLDLYCNT_150M;
+
+	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
+
+	/* Turn all the channels on. */
+	rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
+			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
+
+	/*
+	 * Set the  LVDS mode, select the input, enable LVDS operation,
+	 * and turn bias circuitry on.
+	 */
+	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN;
+	if (drm_crtc_index(crtc) == 2)
+		lvdcr0 |= LVDCR0_DUSEL;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	/*
+	 * Turn the PLL on, wait for the startup delay, and turn the output
+	 * on.
+	 */
+	lvdcr0 |= LVDCR0_PLLON;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	usleep_range(100, 150);
+
+	lvdcr0 |= LVDCR0_LVRES;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+}
+
+static void rcar_lvds_enable_gen3(struct rcar_lvds *lvds)
+{
+	const struct drm_display_mode *mode = &lvds->display_mode;
+	unsigned int freq = mode->clock;
+	u32 lvdcr0;
+	u32 pllcr;
+
+	/* PLL clock configuration */
+	if (freq < 42000)
+		pllcr = LVDPLLCR_PLLDIVCNT_42M;
+	else if (freq < 85000)
+		pllcr = LVDPLLCR_PLLDIVCNT_85M;
+	else if (freq < 128000)
+		pllcr = LVDPLLCR_PLLDIVCNT_128M;
+	else
+		pllcr = LVDPLLCR_PLLDIVCNT_148M;
+
+	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
+
+	/* Turn all the channels on. */
+	rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
+			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
+
+	/*
+	 * Turn the PLL on, set it to LVDS normal mode, wait for the startup
+	 * delay and turn the output on.
+	 */
+	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	lvdcr0 |= LVDCR0_PWD;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	usleep_range(100, 150);
+
+	lvdcr0 |= LVDCR0_LVRES;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+}
+
+static void rcar_lvds_enable(struct drm_bridge *bridge)
+{
+	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+	u32 lvdhcr;
+	int ret;
+
+	WARN_ON(lvds->enabled);
+
+	ret = clk_prepare_enable(lvds->clock);
+	if (ret < 0)
+		return;
+
+	/*
+	 * Hardcode the channels and control signals routing for now.
+	 *
+	 * HSYNC -> CTRL0
+	 * VSYNC -> CTRL1
+	 * DISP  -> CTRL2
+	 * 0     -> CTRL3
+	 */
+	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
+			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
+			LVDCTRCR_CTR0SEL_HSYNC);
+
+	if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES)
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
+	else
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
+
+	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
+
+	/* Perform generation-specific initialization. */
+	if (lvds->info->gen < 3)
+		rcar_lvds_enable_gen2(lvds);
+	else
+		rcar_lvds_enable_gen3(lvds);
+
+	if (lvds->panel) {
+		drm_panel_prepare(lvds->panel);
+		drm_panel_enable(lvds->panel);
+	}
+
+	lvds->enabled = true;
+}
+
+static void rcar_lvds_disable(struct drm_bridge *bridge)
+{
+	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+
+	WARN_ON(!lvds->enabled);
+
+	if (lvds->panel) {
+		drm_panel_disable(lvds->panel);
+		drm_panel_unprepare(lvds->panel);
+	}
+
+	rcar_lvds_write(lvds, LVDCR0, 0);
+	rcar_lvds_write(lvds, LVDCR1, 0);
+
+	clk_disable_unprepare(lvds->clock);
+
+	lvds->enabled = false;
+}
+
+static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	/*
+	 * The internal LVDS encoder has a restricted clock frequency operating
+	 * range (31MHz to 148.5MHz). Clamp the clock accordingly.
+	 */
+	adjusted_mode->clock = clamp(adjusted_mode->clock, 31000, 148500);
+
+	return true;
+}
+
+static void rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds)
+{
+	struct drm_display_info *info = &lvds->connector.display_info;
+	enum rcar_lvds_mode mode;
+
+	/*
+	 * There is no API yet to retrieve LVDS mode from a bridge, only panels
+	 * are supported.
+	 */
+	if (!lvds->panel)
+		return;
+
+	if (!info->num_bus_formats || !info->bus_formats) {
+		dev_err(lvds->dev, "no LVDS bus format reported\n");
+		return;
+	}
+
+	switch (info->bus_formats[0]) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		mode = RCAR_LVDS_MODE_JEIDA;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+		mode = RCAR_LVDS_MODE_VESA;
+		break;
+	default:
+		dev_err(lvds->dev, "unsupported LVDS bus format 0x%04x\n",
+			info->bus_formats[0]);
+		return;
+	}
+
+	if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
+		mode |= RCAR_LVDS_MODE_MIRROR;
+
+	lvds->mode = mode;
+}
+
+static void rcar_lvds_mode_set(struct drm_bridge *bridge,
+			       struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+
+	WARN_ON(lvds->enabled);
+
+	lvds->display_mode = *adjusted_mode;
+
+	rcar_lvds_get_lvds_mode(lvds);
+}
+
+static int rcar_lvds_attach(struct drm_bridge *bridge)
+{
+	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+	struct drm_connector *connector = &lvds->connector;
+	struct drm_encoder *encoder = bridge->encoder;
+	int ret;
+
+	/* If we have a next bridge just attach it. */
+	if (lvds->next_bridge)
+		return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
+					 bridge);
+
+	/* Otherwise we have a panel, create a connector. */
+	ret = drm_connector_init(bridge->dev, connector, &rcar_lvds_conn_funcs,
+				 DRM_MODE_CONNECTOR_LVDS);
+	if (ret < 0)
+		return ret;
+
+	drm_connector_helper_add(connector, &rcar_lvds_conn_helper_funcs);
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret < 0)
+		return ret;
+
+	return drm_panel_attach(lvds->panel, connector);
+}
+
+static void rcar_lvds_detach(struct drm_bridge *bridge)
+{
+	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+
+	if (lvds->panel)
+		drm_panel_detach(lvds->panel);
+}
+
+static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
+	.attach = rcar_lvds_attach,
+	.detach = rcar_lvds_detach,
+	.enable = rcar_lvds_enable,
+	.disable = rcar_lvds_disable,
+	.mode_fixup = rcar_lvds_mode_fixup,
+	.mode_set = rcar_lvds_mode_set,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
+{
+	struct device_node *local_output = NULL;
+	struct device_node *remote_input = NULL;
+	struct device_node *remote = NULL;
+	struct device_node *node;
+	bool is_bridge = false;
+	int ret = 0;
+
+	local_output = of_graph_get_endpoint_by_regs(lvds->dev->of_node, 1, 0);
+	if (!local_output) {
+		dev_dbg(lvds->dev, "unconnected port@1\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Locate the connected entity and infer its type from the number of
+	 * endpoints.
+	 */
+	remote = of_graph_get_remote_port_parent(local_output);
+	if (!remote) {
+		dev_dbg(lvds->dev, "unconnected endpoint %pOF\n", local_output);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	if (!of_device_is_available(remote)) {
+		dev_dbg(lvds->dev, "connected entity %pOF is disabled\n",
+			remote);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	remote_input = of_graph_get_remote_endpoint(local_output);
+
+	for_each_endpoint_of_node(remote, node) {
+		if (node != remote_input) {
+			/*
+			 * We've found one endpoint other than the input, this
+			 * must be a bridge.
+			 */
+			is_bridge = true;
+			of_node_put(node);
+			break;
+		}
+	}
+
+	if (is_bridge) {
+		lvds->next_bridge = of_drm_find_bridge(remote);
+		if (!lvds->next_bridge)
+			ret = -EPROBE_DEFER;
+	} else {
+		lvds->panel = of_drm_find_panel(remote);
+		if (!lvds->panel)
+			ret = -EPROBE_DEFER;
+	}
+
+done:
+	of_node_put(local_output);
+	of_node_put(remote_input);
+	of_node_put(remote);
+
+	return ret;
+}
+
+static int rcar_lvds_probe(struct platform_device *pdev)
+{
+	struct rcar_lvds *lvds;
+	struct resource *mem;
+	int ret;
+
+	lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
+	if (lvds == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, lvds);
+
+	lvds->dev = &pdev->dev;
+	lvds->info = of_device_get_match_data(&pdev->dev);
+	lvds->enabled = false;
+
+	ret = rcar_lvds_parse_dt(lvds);
+	if (ret < 0)
+		return ret;
+
+	lvds->bridge.driver_private = lvds;
+	lvds->bridge.funcs = &rcar_lvds_bridge_ops;
+	lvds->bridge.of_node = pdev->dev.of_node;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lvds->mmio = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(lvds->mmio))
+		return PTR_ERR(lvds->mmio);
+
+	lvds->clock = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(lvds->clock)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		return PTR_ERR(lvds->clock);
+	}
+
+	drm_bridge_add(&lvds->bridge);
+
+	return 0;
+}
+
+static int rcar_lvds_remove(struct platform_device *pdev)
+{
+	struct rcar_lvds *lvds = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&lvds->bridge);
+
+	return 0;
+}
+
+static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
+	.gen = 2,
+};
+
+static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = {
+	.gen = 2,
+	.quirks = RCAR_LVDS_QUIRK_LANES,
+};
+
+static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
+	.gen = 3,
+};
+
+static const struct of_device_id rcar_lvds_of_table[] = {
+	{ .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info },
+	{ .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_r8a7790_info },
+	{ .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
+	{ .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
+	{ .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
+	{ .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
+
+static struct platform_driver rcar_lvds_platform_driver = {
+	.probe		= rcar_lvds_probe,
+	.remove		= rcar_lvds_remove,
+	.driver		= {
+		.name	= "rcar-lvds",
+		.of_match_table = rcar_lvds_of_table,
+	},
+};
+
+module_platform_driver(rcar_lvds_platform_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas R-Car LVDS Encoder Driver");
+MODULE_LICENSE("GPL");
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 05/12] ARM: dts: porter: Fix HDMI output routing
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
       [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
  2018-01-12 23:14 ` [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings Laurent Pinchart
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The HDMI encoder is connected to the RGB output of the DU, which is
port@0, not port@1. Fix the incorrect DT description.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 arch/arm/boot/dts/r8a7791-porter.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts
index eb374956294f..9a02d03b23c2 100644
--- a/arch/arm/boot/dts/r8a7791-porter.dts
+++ b/arch/arm/boot/dts/r8a7791-porter.dts
@@ -425,7 +425,7 @@
 		      "dclkin.0", "dclkin.1";
 
 	ports {
-		port@1 {
+		port@0 {
 			endpoint {
 				remote-endpoint = <&adv7511_in>;
 			};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (2 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 05/12] ARM: dts: porter: Fix HDMI output routing Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-15 12:30   ` Sergei Shtylyov
  2018-01-12 23:14 ` [PATCH v2 07/12] ARM: dts: r8a7791: " Laurent Pinchart
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The internal LVDS encoder now has DT bindings separate from the DU. Port
the device tree over to the new model.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Remove the DU reg-names property
---
 arch/arm/boot/dts/r8a7790-lager.dts | 22 ++++++++++----
 arch/arm/boot/dts/r8a7790.dtsi      | 60 ++++++++++++++++++++++++++++++++-----
 2 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index 7d5cd01069a3..f84963cb6785 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -317,10 +317,8 @@
 	status = "okay";
 
 	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&cpg CPG_MOD 722>,
-		 <&cpg CPG_MOD 726>, <&cpg CPG_MOD 725>,
 		 <&x13_clk>, <&x2_clk>;
-	clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1",
-		      "dclkin.0", "dclkin.1";
+	clock-names = "du.0", "du.1", "du.2", "dclkin.0", "dclkin.1";
 
 	ports {
 		port@0 {
@@ -328,12 +326,26 @@
 				remote-endpoint = <&adv7123_in>;
 			};
 		};
+	};
+};
+
+&lvds0 {
+	status = "okay";
+
+	ports {
 		port@1 {
 			endpoint {
 				remote-endpoint = <&adv7511_in>;
 			};
 		};
-		port@2 {
+	};
+};
+
+&lvds1 {
+	status = "okay";
+
+	ports {
+		port@1 {
 			lvds_connector: endpoint {
 			};
 		};
@@ -689,7 +701,7 @@
 			port@0 {
 				reg = <0>;
 				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_lvds0>;
+					remote-endpoint = <&lvds0_out>;
 				};
 			};
 
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index 62baabd757b6..0fcd5e34ef82 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -1067,17 +1067,13 @@
 
 	du: display@feb00000 {
 		compatible = "renesas,du-r8a7790";
-		reg = <0 0xfeb00000 0 0x70000>,
-		      <0 0xfeb90000 0 0x1c>,
-		      <0 0xfeb94000 0 0x1c>;
-		reg-names = "du", "lvds.0", "lvds.1";
+		reg = <0 0xfeb00000 0 0x70000>;
 		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 722>, <&cpg CPG_MOD 726>,
-			 <&cpg CPG_MOD 725>;
-		clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
+			 <&cpg CPG_MOD 722>;
+		clock-names = "du.0", "du.1", "du.2";
 		status = "disabled";
 
 		ports {
@@ -1092,11 +1088,61 @@
 			port@1 {
 				reg = <1>;
 				du_out_lvds0: endpoint {
+					remote-endpoint = <&lvds0_in>;
 				};
 			};
 			port@2 {
 				reg = <2>;
 				du_out_lvds1: endpoint {
+					remote-endpoint = <&lvds1_in>;
+				};
+			};
+		};
+	};
+
+	lvds0: lvds@feb90000 {
+		compatible = "renesas,lvds-r8a7790";
+		reg = <0 0xfeb90000 0 0x1c>;
+		clocks = <&cpg CPG_MOD 726>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lvds0_in: endpoint {
+					remote-endpoint = <&du_out_lvds0>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				lvds0_out: endpoint {
+				};
+			};
+		};
+	};
+
+	lvds1: lvds@feb94000 {
+		compatible = "renesas,lvds-r8a7790";
+		reg = <0 0xfeb94000 0 0x1c>;
+		clocks = <&cpg CPG_MOD 725>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lvds1_in: endpoint {
+					remote-endpoint = <&du_out_lvds1>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				lvds1_out: endpoint {
 				};
 			};
 		};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 07/12] ARM: dts: r8a7791: Convert to new LVDS DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (3 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-15 12:27   ` Sergei Shtylyov
  2018-01-12 23:14 ` [PATCH v2 08/12] ARM: dts: r8a7792: Convert to new DU " Laurent Pinchart
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The internal LVDS encoder now has DT bindings separate from the DU. Port
the device tree over to the new model.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Remove the DU reg-names property
---
 arch/arm/boot/dts/r8a7791-koelsch.dts | 10 ++++++++--
 arch/arm/boot/dts/r8a7791-porter.dts  | 16 +++++++++++++---
 arch/arm/boot/dts/r8a7791.dtsi        | 34 ++++++++++++++++++++++++++++------
 3 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index e164eda69baf..5a0f87ed7f16 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -332,8 +332,7 @@
 
 	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&cpg CPG_MOD 726>,
 		 <&x13_clk>, <&x2_clk>;
-	clock-names = "du.0", "du.1", "lvds.0",
-		      "dclkin.0", "dclkin.1";
+	clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1";
 
 	ports {
 		port@0 {
@@ -341,6 +340,13 @@
 				remote-endpoint = <&adv7511_in>;
 			};
 		};
+	};
+};
+
+&lvds0 {
+	status = "okay";
+
+	ports {
 		port@1 {
 			lvds_connector: endpoint {
 			};
diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts
index 9a02d03b23c2..e6d02839d636 100644
--- a/arch/arm/boot/dts/r8a7791-porter.dts
+++ b/arch/arm/boot/dts/r8a7791-porter.dts
@@ -419,10 +419,9 @@
 	pinctrl-names = "default";
 	status = "okay";
 
-	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&cpg CPG_MOD 726>,
+	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
 		 <&x3_clk>, <&x16_clk>;
-	clock-names = "du.0", "du.1", "lvds.0",
-		      "dclkin.0", "dclkin.1";
+	clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1";
 
 	ports {
 		port@0 {
@@ -433,6 +432,17 @@
 	};
 };
 
+&lvds0 {
+	status = "okay";
+
+	ports {
+		port@1 {
+			lvds_connector: endpoint {
+			};
+		};
+	};
+};
+
 &rcar_sound {
 	pinctrl-0 = <&ssi_pins &audio_clk_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 67831d0405f3..b7fceb210de9 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -1103,15 +1103,12 @@
 
 	du: display@feb00000 {
 		compatible = "renesas,du-r8a7791";
-		reg = <0 0xfeb00000 0 0x40000>,
-		      <0 0xfeb90000 0 0x1c>;
-		reg-names = "du", "lvds.0";
+		reg = <0 0xfeb00000 0 0x40000>;
 		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cpg CPG_MOD 724>,
-			 <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 726>;
-		clock-names = "du.0", "du.1", "lvds.0";
+			 <&cpg CPG_MOD 723>;
+		clock-names = "du.0", "du.1";
 		status = "disabled";
 
 		ports {
@@ -1126,6 +1123,31 @@
 			port@1 {
 				reg = <1>;
 				du_out_lvds0: endpoint {
+					remote-endpoint = <&lvds0_in>;
+				};
+			};
+		};
+	};
+
+	lvds0: lvds@feb90000 {
+		compatible = "renesas,lvds-r8a7791";
+		reg = <0 0xfeb90000 0 0x1c>;
+		clocks = <&cpg CPG_MOD 726>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lvds0_in: endpoint {
+					remote-endpoint = <&du_out_lvds0>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				lvds0_out: endpoint {
 				};
 			};
 		};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 08/12] ARM: dts: r8a7792: Convert to new DU DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (4 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 07/12] ARM: dts: r8a7791: " Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 09/12] ARM: dts: r8a7793: Convert to new LVDS " Laurent Pinchart
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The DU DT bindings have been updated to drop the reg-names property.
Update the r8a7792 device tree accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 arch/arm/boot/dts/r8a7792.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi
index 3d080e07374c..d40325466aa8 100644
--- a/arch/arm/boot/dts/r8a7792.dtsi
+++ b/arch/arm/boot/dts/r8a7792.dtsi
@@ -678,7 +678,6 @@
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7792";
 			reg = <0 0xfeb00000 0 0x40000>;
-			reg-names = "du";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 09/12] ARM: dts: r8a7793: Convert to new LVDS DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (5 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 08/12] ARM: dts: r8a7792: Convert to new DU " Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 10/12] ARM: dts: r8a7794: Convert to new DU " Laurent Pinchart
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The internal LVDS encoder now has DT bindings separate from the DU. Port
the device tree over to the new model.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Remove the DU reg-names property
---
 arch/arm/boot/dts/r8a7793-gose.dts | 10 +++++++---
 arch/arm/boot/dts/r8a7793.dtsi     | 34 ++++++++++++++++++++++++++++------
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts
index 51b3ffac8efa..c6121f9b72a8 100644
--- a/arch/arm/boot/dts/r8a7793-gose.dts
+++ b/arch/arm/boot/dts/r8a7793-gose.dts
@@ -303,10 +303,9 @@
 	pinctrl-names = "default";
 	status = "okay";
 
-	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&cpg CPG_MOD 726>,
+	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
 		 <&x13_clk>, <&x2_clk>;
-	clock-names = "du.0", "du.1", "lvds.0",
-		      "dclkin.0", "dclkin.1";
+	clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1";
 
 	ports {
 		port@0 {
@@ -314,6 +313,11 @@
 				remote-endpoint = <&adv7511_in>;
 			};
 		};
+	};
+};
+
+&lvds0 {
+	ports {
 		port@1 {
 			lvds_connector: endpoint {
 			};
diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi
index 0cd1035de1a4..c382a57df168 100644
--- a/arch/arm/boot/dts/r8a7793.dtsi
+++ b/arch/arm/boot/dts/r8a7793.dtsi
@@ -976,15 +976,12 @@
 
 	du: display@feb00000 {
 		compatible = "renesas,du-r8a7793";
-		reg = <0 0xfeb00000 0 0x40000>,
-		      <0 0xfeb90000 0 0x1c>;
-		reg-names = "du", "lvds.0";
+		reg = <0 0xfeb00000 0 0x40000>;
 		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cpg CPG_MOD 724>,
-			 <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 726>;
-		clock-names = "du.0", "du.1", "lvds.0";
+			 <&cpg CPG_MOD 723>;
+		clock-names = "du.0", "du.1";
 		status = "disabled";
 
 		ports {
@@ -999,6 +996,31 @@
 			port@1 {
 				reg = <1>;
 				du_out_lvds0: endpoint {
+					remote-endpoint = <&lvds0_in>;
+				};
+			};
+		};
+	};
+
+	lvds0: lvds@feb90000 {
+		compatible = "renesas,lvds-r8a7793";
+		reg = <0 0xfeb90000 0 0x1c>;
+		clocks = <&cpg CPG_MOD 726>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lvds0_in: endpoint {
+					remote-endpoint = <&du_out_lvds0>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				lvds0_out: endpoint {
 				};
 			};
 		};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 10/12] ARM: dts: r8a7794: Convert to new DU DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (6 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 09/12] ARM: dts: r8a7793: Convert to new LVDS " Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 11/12] arm64: dts: renesas: r8a7795: Convert to new LVDS " Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 12/12] arm64: dts: renesas: r8a7796: " Laurent Pinchart
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The DU DT bindings have been updated to drop the reg-names property.
Update the r8a7792 device tree accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 arch/arm/boot/dts/r8a7794.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 5643976c1356..cccdada9e4a4 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -992,7 +992,6 @@
 	du: display@feb00000 {
 		compatible = "renesas,du-r8a7794";
 		reg = <0 0xfeb00000 0 0x40000>;
-		reg-names = "du";
 		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 11/12] arm64: dts: renesas: r8a7795: Convert to new LVDS DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (7 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 10/12] ARM: dts: r8a7794: Convert to new DU " Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  2018-01-12 23:14 ` [PATCH v2 12/12] arm64: dts: renesas: r8a7796: " Laurent Pinchart
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The internal LVDS encoder now has DT bindings separate from the DU. Port
the device tree over to the new model.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Remove the DU reg-names property
---
 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |  3 +-
 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts     |  3 +-
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |  3 +-
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |  3 +-
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           | 34 ++++++++++++++++++----
 5 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
index 9ef9a4e5f376..0dda1c0ed1ce 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
@@ -43,12 +43,11 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2", "du.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts
index 0afe777973de..f0d6528c05eb 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts
@@ -44,11 +44,10 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock5 1>,
 		 <&versaclock5 3>,
 		 <&versaclock5 4>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2", "du.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
index 00ad1ab53a7d..e34b986185d4 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
@@ -43,12 +43,11 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2", "du.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
index 79e8b65622db..31f2abaa90aa 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
@@ -43,12 +43,11 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock6 2>;
-	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2", "du.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index 15ef292a8d9f..8e14873455b9 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -2077,9 +2077,7 @@
 
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7795";
-			reg = <0 0xfeb00000 0 0x80000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			reg = <0 0xfeb00000 0 0x80000>;
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
@@ -2087,9 +2085,8 @@
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
 				 <&cpg CPG_MOD 722>,
-				 <&cpg CPG_MOD 721>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
+				 <&cpg CPG_MOD 721>;
+			clock-names = "du.0", "du.1", "du.2", "du.3";
 			vsps = <&vspd0 0 &vspd1 0 &vspd2 0 &vspd0 1>;
 			status = "disabled";
 
@@ -2117,6 +2114,31 @@
 				port@3 {
 					reg = <3>;
 					du_out_lvds0: endpoint {
+						remote-endpoint = <&lvds0_in>;
+					};
+				};
+			};
+		};
+
+		lvds0: lvds@feb90000 {
+			compatible = "renesas,lvds-r8a7795";
+			reg = <0 0xfeb90000 0 0x14>;
+			clocks = <&cpg CPG_MOD 727>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					lvds0_in: endpoint {
+						remote-endpoint = <&du_out_lvds0>;
+					};
+				};
+				port@1 {
+					reg = <1>;
+					lvds0_out: endpoint {
 					};
 				};
 			};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v2 12/12] arm64: dts: renesas: r8a7796: Convert to new LVDS DT bindings
  2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
                   ` (8 preceding siblings ...)
  2018-01-12 23:14 ` [PATCH v2 11/12] arm64: dts: renesas: r8a7795: Convert to new LVDS " Laurent Pinchart
@ 2018-01-12 23:14 ` Laurent Pinchart
  9 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-12 23:14 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Sergei Shtylyov

The internal LVDS encoder now has DT bindings separate from the DU. Port
the device tree over to the new model.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v1:

- Remove the DU reg-names property
---
 arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts     |  3 +-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |  3 +-
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           | 34 ++++++++++++++++++----
 3 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts
index daee1f1a3f68..21bd679062f3 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb.dts
@@ -33,10 +33,9 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock5 1>,
 		 <&versaclock5 3>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
 };
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
index 4088bea8d62c..ecbfbcb65df3 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
@@ -32,11 +32,10 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
-		 <&cpg CPG_MOD 727>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+	clock-names = "du.0", "du.1", "du.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
index f2b2e40c655e..169fd89fe093 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
@@ -1826,17 +1826,14 @@
 
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7796";
-			reg = <0 0xfeb00000 0 0x70000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			reg = <0 0xfeb00000 0 0x70000>;
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
-				 <&cpg CPG_MOD 722>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "lvds.0";
+				 <&cpg CPG_MOD 722>;
+			clock-names = "du.0", "du.1", "du.2";
 			status = "disabled";
 
 			vsps = <&vspd0 &vspd1 &vspd2>;
@@ -1859,6 +1856,31 @@
 				port@2 {
 					reg = <2>;
 					du_out_lvds0: endpoint {
+						remote-endpoint = <&lvds0_in>;
+					};
+				};
+			};
+		};
+
+		lvds0: lvds@feb90000 {
+			compatible = "renesas,lvds-r8a7796";
+			reg = <0 0xfeb90000 0 0x14>;
+			clocks = <&cpg CPG_MOD 727>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					lvds0_in: endpoint {
+						remote-endpoint = <&du_out_lvds0>;
+					};
+				};
+				port@1 {
+					reg = <1>;
+					lvds0_out: endpoint {
 					};
 				};
 			};
-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-12 23:14 ` [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver Laurent Pinchart
@ 2018-01-15  8:30   ` Geert Uytterhoeven
  2018-01-15  8:32     ` Laurent Pinchart
  2018-01-15 20:25   ` Sergei Shtylyov
  1 sibling, 1 reply; 38+ messages in thread
From: Geert Uytterhoeven @ 2018-01-15  8:30 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: Linux-Renesas, Sergei Shtylyov, DRI Development

Hi Laurent,

On Sat, Jan 13, 2018 at 12:14 AM, Laurent Pinchart
<laurent.pinchart+renesas@ideasonboard.com> wrote:
> The LVDS encoders used to be described in DT as part of the DU. They now
> have their own DT node, linked to the DU using the OF graph bindings.
> This allows moving internal LVDS encoder support to a separate driver
> modelled as a DRM bridge. Backward compatibility is retained as legacy
> DT is patched live to move to the new bindings.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c

> +static void rcar_lvds_enable(struct drm_bridge *bridge)
> +{
> +       struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
> +       u32 lvdhcr;
> +       int ret;
> +
> +       WARN_ON(lvds->enabled);
> +
> +       ret = clk_prepare_enable(lvds->clock);

What about starting to use Runtime PM to manage the clock, and thus calling
pm_runtime_get_sync() here instead?
That will make the driver future-proof w.r.t. LVDS blocks in power domains.

You do need a "power-domains" property, though, which may complicate DT
runtime patching.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-15  8:30   ` Geert Uytterhoeven
@ 2018-01-15  8:32     ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-15  8:32 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Laurent Pinchart, DRI Development, Linux-Renesas, Sergei Shtylyov

Hi Geert,

On Monday, 15 January 2018 10:30:23 EET Geert Uytterhoeven wrote:
> On Sat, Jan 13, 2018 at 12:14 AM, Laurent Pinchart wrote:
> > The LVDS encoders used to be described in DT as part of the DU. They now
> > have their own DT node, linked to the DU using the OF graph bindings.
> > This allows moving internal LVDS encoder support to a separate driver
> > modelled as a DRM bridge. Backward compatibility is retained as legacy
> > DT is patched live to move to the new bindings.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > 
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > 
> > +static void rcar_lvds_enable(struct drm_bridge *bridge)
> > +{
> > +       struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
> > +       u32 lvdhcr;
> > +       int ret;
> > +
> > +       WARN_ON(lvds->enabled);
> > +
> > +       ret = clk_prepare_enable(lvds->clock);
> 
> What about starting to use Runtime PM to manage the clock, and thus calling
> pm_runtime_get_sync() here instead?
> That will make the driver future-proof w.r.t. LVDS blocks in power domains.
> 
> You do need a "power-domains" property, though, which may complicate DT
> runtime patching.

And that's why I've left it out for now. It's on my to-do list, but I will do 
so in a separate patch series. Depending on the complexity I might use runtime 
PM for new DTs only and leave the runtime-patched devices trees out.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 07/12] ARM: dts: r8a7791: Convert to new LVDS DT bindings
  2018-01-12 23:14 ` [PATCH v2 07/12] ARM: dts: r8a7791: " Laurent Pinchart
@ 2018-01-15 12:27   ` Sergei Shtylyov
  0 siblings, 0 replies; 38+ messages in thread
From: Sergei Shtylyov @ 2018-01-15 12:27 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc

Hello!

On 01/13/2018 02:14 AM, Laurent Pinchart wrote:

> The internal LVDS encoder now has DT bindings separate from the DU. Port
> the device tree over to the new model.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
[...]
> diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
> index 67831d0405f3..b7fceb210de9 100644
> --- a/arch/arm/boot/dts/r8a7791.dtsi
> +++ b/arch/arm/boot/dts/r8a7791.dtsi
[...]
> @@ -1126,6 +1123,31 @@
>   			port@1 {
>   				reg = <1>;
>   				du_out_lvds0: endpoint {
> +					remote-endpoint = <&lvds0_in>;
> +				};
> +			};
> +		};
> +	};
> +
> +	lvds0: lvds@feb90000 {
> +		compatible = "renesas,lvds-r8a7791";

   Haven't we settled on <soc> going 1st, after the comma?

[...]

MBR, Sergei
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings
  2018-01-12 23:14 ` [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings Laurent Pinchart
@ 2018-01-15 12:30   ` Sergei Shtylyov
  0 siblings, 0 replies; 38+ messages in thread
From: Sergei Shtylyov @ 2018-01-15 12:30 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc

Hello!

On 01/13/2018 02:14 AM, Laurent Pinchart wrote:

> The internal LVDS encoder now has DT bindings separate from the DU. Port
> the device tree over to the new model.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
[...]
> diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
> index 62baabd757b6..0fcd5e34ef82 100644
> --- a/arch/arm/boot/dts/r8a7790.dtsi
> +++ b/arch/arm/boot/dts/r8a7790.dtsi
[...]
> @@ -1092,11 +1088,61 @@
>   			port@1 {
>   				reg = <1>;
>   				du_out_lvds0: endpoint {
> +					remote-endpoint = <&lvds0_in>;
>   				};
>   			};
>   			port@2 {
>   				reg = <2>;
>   				du_out_lvds1: endpoint {
> +					remote-endpoint = <&lvds1_in>;
> +				};
> +			};
> +		};
> +	};
> +
> +	lvds0: lvds@feb90000 {
> +		compatible = "renesas,lvds-r8a7790";

    Same question...

> +		reg = <0 0xfeb90000 0 0x1c>;
> +		clocks = <&cpg CPG_MOD 726>;
> +		status = "disabled";
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port@0 {
> +				reg = <0>;
> +				lvds0_in: endpoint {
> +					remote-endpoint = <&du_out_lvds0>;
> +				};
> +			};
> +			port@1 {
> +				reg = <1>;
> +				lvds0_out: endpoint {
> +				};
> +			};
> +		};
> +	};
> +
> +	lvds1: lvds@feb94000 {
> +		compatible = "renesas,lvds-r8a7790";

    Same question here as well...

MBR, Sergei
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-12 23:14   ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
@ 2018-01-15 17:09     ` Rob Herring
  2018-01-15 18:01       ` Laurent Pinchart
  2018-01-15 19:12       ` Frank Rowand
  2018-01-21  9:35     ` Sergei Shtylyov
  1 sibling, 2 replies; 38+ messages in thread
From: Rob Herring @ 2018-01-15 17:09 UTC (permalink / raw)
  To: Laurent Pinchart, Frank Rowand
  Cc: dri-devel, open list:MEDIA DRIVERS FOR RENESAS - FCP,
	Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

+Frank

On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart
<laurent.pinchart+renesas@ideasonboard.com> wrote:
> The internal LVDS encoders now have their own DT bindings. Before
> switching the driver infrastructure to those new bindings, implement
> backward-compatibility through live DT patching.

Uhh, we just got rid of TI's patching and now adding this one. I guess
it's necessary, but I'd like to know how long we need to keep this?

How many overlays would you need if everything is static (i.e.
removing all your fixup code)?

> Patching is disabled and will be enabled along with support for the new
> DT bindings in the DU driver.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> Changes since v1:
>
> - Select OF_FLATTREE
> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> - Pass void begin and end pointers to rcar_du_of_get_overlay()
> - Use of_get_parent() instead of accessing the parent pointer directly
> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>   root of the overlay
> - Update to the <soc>-lvds compatible string format
> ---
>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>  5 files changed, 553 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>
> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
> index 5d0b4b7119af..3f83352a7313 100644
> --- a/drivers/gpu/drm/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
>         bool "R-Car DU LVDS Encoder Support"
>         depends on DRM_RCAR_DU
>         select DRM_PANEL
> +       select OF_FLATTREE
> +       select OF_OVERLAY

OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
could have an overlay from a non-FDT source...

>         help
>           Enable support for the R-Car Display Unit embedded LVDS encoders.
>
> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
> index 0cf5c11030e8..8ed569a0f462 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -5,10 +5,11 @@ rcar-du-drm-y := rcar_du_crtc.o \
>                  rcar_du_group.o \
>                  rcar_du_kms.o \
>                  rcar_du_lvdscon.o \
> +                rcar_du_of.o \
>                  rcar_du_plane.o
>
>  rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)    += rcar_du_lvdsenc.o
> -
> +rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)    += rcar_du_of_lvds.dtb.o
>  rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)     += rcar_du_vsp.o
>
>  obj-$(CONFIG_DRM_RCAR_DU)              += rcar-du-drm.o
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> new file mode 100644
> index 000000000000..2bf91201fc93
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> @@ -0,0 +1,451 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of.c - Legacy DT bindings compatibility
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_graph.h>
> +#include <linux/slab.h>
> +
> +#include "rcar_du_crtc.h"
> +#include "rcar_du_drv.h"
> +
> +#ifdef CONFIG_DRM_RCAR_LVDS

Why not make compiling this file conditional in the Makefile?

> +
> +struct rcar_du_of_overlay {
> +       struct device_node *np;
> +       void *data;
> +       void *mem;
> +};
> +
> +static void __init rcar_du_of_free_overlay(struct rcar_du_of_overlay *overlay)
> +{
> +       of_node_put(overlay->np);
> +       kfree(overlay->data);
> +       kfree(overlay->mem);
> +}
> +
> +static int __init rcar_du_of_get_overlay(struct rcar_du_of_overlay *overlay,
> +                                        void *begin, void *end)
> +{
> +       const size_t size = end - begin;
> +
> +       memset(overlay, 0, sizeof(*overlay));
> +
> +       if (!size)
> +               return -EINVAL;
> +
> +       overlay->data = kmemdup(begin, size, GFP_KERNEL);
> +       if (!overlay->data)
> +               return -ENOMEM;
> +
> +       overlay->mem = of_fdt_unflatten_tree(overlay->data, NULL, &overlay->np);
> +       if (!overlay->mem) {
> +               rcar_du_of_free_overlay(overlay);
> +               return -ENOMEM;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct device_node __init *
> +rcar_du_of_find_node_by_path(struct device_node *parent, const char *path)
> +{

What's wrong with the core function to do this?

> +       parent = of_node_get(parent);
> +       if (!parent)
> +               return NULL;
> +
> +       while (parent && *path == '/') {
> +               struct device_node *child = NULL;
> +               struct device_node *node;
> +               const char *next;
> +               size_t len;
> +
> +               /* Skip the initial '/' delimiter and find the next one. */
> +               path++;
> +               next = strchrnul(path, '/');
> +               len = next - path;
> +               if (!len)
> +                       goto error;
> +
> +               for_each_child_of_node(parent, node) {
> +                       const char *name = kbasename(node->full_name);
> +
> +                       if (strncmp(path, name, len) == 0 &&
> +                           strlen(name) == len) {
> +                               child = node;
> +                               break;
> +                       }
> +               }
> +
> +               if (!child)
> +                       goto error;
> +
> +               of_node_put(parent);
> +               parent = child;
> +               path = next;
> +       }
> +
> +       return parent;
> +
> +error:
> +       of_node_put(parent);
> +       return NULL;
> +}
> +
> +static int __init rcar_du_of_add_property(struct device_node *np,
> +                                         const char *name, const void *value,
> +                                         size_t length)
> +{

This should be a core function. In fact, IIRC, Pantelis had a patch
adding functions like this. I believe there were only minor issues and
I said I would take it even without users, but he never followed up.

> +       struct property *prop;

We want to make struct property opaque, so I don't really want to see
more users...

> +
> +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +       if (!prop)
> +               return -ENOMEM;
> +
> +       prop->name = kstrdup(name, GFP_KERNEL);
> +       prop->value = kmemdup(value, length, GFP_KERNEL);
> +       prop->length = length;
> +
> +       if (!prop->name || !prop->value) {
> +               kfree(prop->name);
> +               kfree(prop->value);
> +               kfree(prop);
> +               return -ENOMEM;
> +       }
> +
> +       of_property_set_flag(prop, OF_DYNAMIC);
> +
> +       prop->next = np->properties;
> +       np->properties = prop;
> +
> +       return 0;
> +}
> +
> +/* Free properties allocated dynamically by rcar_du_of_add_property(). */
> +static void __init rcar_du_of_free_properties(struct device_node *np)
> +{
> +       while (np->properties) {
> +               struct property *prop = np->properties;
> +
> +               np->properties = prop->next;
> +
> +               if (OF_IS_DYNAMIC(prop)) {
> +                       kfree(prop->name);
> +                       kfree(prop->value);
> +                       kfree(prop);
> +               }
> +       }
> +}
> +
> +static int __init rcar_du_of_update_target_path(struct device_node *du,
> +                                               struct device_node *remote,
> +                                               struct device_node *np)
> +{
> +       struct device_node *target = NULL;
> +       struct property **prev;
> +       struct property *prop;
> +       char *path;
> +       int ret;
> +
> +       for (prop = np->properties, prev = &prop; prop != NULL;
> +            prev = &prop->next, prop = prop->next) {
> +               if (of_prop_cmp(prop->name, "target-path"))
> +                       continue;
> +
> +               if (!of_prop_cmp(prop->value, "soc")) {
> +                       target = of_get_parent(du);
> +                       break;
> +               }
> +               if (!of_prop_cmp(prop->value, "du")) {
> +                       target = of_node_get(du);
> +                       break;
> +               }
> +               if (!of_prop_cmp(prop->value, "lvds-sink")) {
> +                       target = of_graph_get_port_parent(remote);
> +                       break;
> +               }
> +
> +               return -EINVAL;
> +       }
> +
> +       if (!target)
> +               return -EINVAL;
> +
> +       path = kasprintf(GFP_KERNEL, "%pOF", target);
> +       of_node_put(target);
> +       if (!path)
> +               return -ENOMEM;
> +
> +       /*
> +        * Remove the existing target-path property that has not been
> +        * dynamically allocated and replace it with a new dynamic one to
> +        * ensure that the value will be properly freed.
> +        */
> +       *prev = prop->next;

You are leaking prev. prev should be moved the deleted property list.
But then you shouldn't be mucking with properties at this level in the
first place.

> +       ret = rcar_du_of_add_property(np, "target-path", path,
> +                                     strlen(path) + 1);
> +       if (ret < 0) {
> +               kfree(path);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +extern char __dtb_rcar_du_of_lvds_begin[];
> +extern char __dtb_rcar_du_of_lvds_end[];
> +
> +static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
> +                                            unsigned int port_id,
> +                                            const struct resource *res,
> +                                            const __be32 *reg,
> +                                            const struct of_phandle_args *clkspec,
> +                                            struct device_node *local,
> +                                            struct device_node *remote)
> +{
> +       struct rcar_du_of_overlay overlay;
> +       struct device_node *du_port_fixup;
> +       struct device_node *du_port;
> +       struct device_node *lvds_endpoints[2];
> +       struct device_node *lvds;
> +       struct device_node *fragment;
> +       struct device_node *bus;
> +       struct property *prop;
> +       const char *compatible;
> +       const char *soc_suffix;
> +       unsigned int psize;
> +       unsigned int i;
> +       __be32 value[4];
> +       char name[23];
> +       int ovcs_id;
> +       int ret;
> +
> +       /* Skip if the LVDS node already exists. */
> +       sprintf(name, "lvds@%llx", (u64)res->start);

Fragile. unit-address and res->start are not necessarily the same thing.

> +       bus = of_get_parent(du);
> +       lvds = of_get_child_by_name(bus, name);
> +       of_node_put(bus);
> +       if (lvds) {
> +               of_node_put(lvds);
> +               return;
> +       }
> +
> +       /* Parse the overlay. */
> +       ret = rcar_du_of_get_overlay(&overlay, __dtb_rcar_du_of_lvds_begin,
> +                                    __dtb_rcar_du_of_lvds_end);
> +       if (ret < 0)
> +               return;
> +
> +       /*
> +        * Patch the LVDS and DU port nodes names and the associated fixup
> +        * entries.
> +        */
> +       lvds = rcar_du_of_find_node_by_path(overlay.np,
> +               "/fragment@0/__overlay__/lvds");
> +       lvds_endpoints[0] = rcar_du_of_find_node_by_path(lvds,
> +               "/ports/port@0/endpoint");
> +       lvds_endpoints[1] = rcar_du_of_find_node_by_path(lvds,
> +               "/ports/port@1/endpoint");
> +       du_port = rcar_du_of_find_node_by_path(overlay.np,
> +               "/fragment@1/__overlay__/ports/port@0");
> +       du_port_fixup = rcar_du_of_find_node_by_path(overlay.np,
> +               "/__local_fixups__/fragment@1/__overlay__/ports/port@0");
> +       if (!lvds || !lvds_endpoints[0] || !lvds_endpoints[1] ||
> +           !du_port || !du_port_fixup)
> +               goto out_put_nodes;
> +
> +       lvds->full_name = kstrdup(name, GFP_KERNEL);
> +
> +       sprintf(name, "port@%u", port_id);
> +       du_port->full_name = kstrdup(name, GFP_KERNEL);
> +       du_port_fixup->full_name = kstrdup(name, GFP_KERNEL);
> +
> +       if (!lvds->full_name || !du_port->full_name ||
> +           !du_port_fixup->full_name)
> +               goto out_free_names;
> +
> +       /* Patch the target paths in all fragments. */
> +       for_each_child_of_node(overlay.np, fragment) {
> +               if (strncmp("fragment@", of_node_full_name(fragment), 9))
> +                       continue;
> +
> +               ret = rcar_du_of_update_target_path(du, remote, fragment);
> +               if (ret < 0) {
> +                       of_node_put(fragment);
> +                       goto out_free_properties;
> +               }
> +       }
> +
> +       /*
> +        * Create a compatible string for the LVDS node using the SoC model
> +        * from the DU node.
> +        */
> +       ret = of_property_read_string(du, "compatible", &compatible);
> +       if (ret < 0)
> +               goto out_free_properties;
> +
> +       soc_suffix = strchr(compatible, '-');
> +       if (!soc_suffix || strlen(soc_suffix) > 10)
> +               goto out_free_properties;
> +
> +       psize = sprintf(name, "renesas,%s-lvds", soc_suffix + 1) + 1;
> +       ret = rcar_du_of_add_property(lvds, "compatible", name, psize);
> +       if (ret < 0)
> +               goto out_free_properties;
> +
> +       /* Copy the LVDS reg and clocks properties from the DU node. */
> +       psize = (of_n_addr_cells(du) + of_n_size_cells(du)) * 4;
> +       ret = rcar_du_of_add_property(lvds, "reg", reg, psize);
> +       if (ret < 0)
> +               goto out_free_properties;
> +
> +       if (clkspec->args_count >= ARRAY_SIZE(value) - 1)
> +               goto out_free_properties;
> +
> +       value[0] = cpu_to_be32(clkspec->np->phandle);
> +       for (i = 0; i < clkspec->args_count; ++i)
> +               value[i + 1] = cpu_to_be32(clkspec->args[i]);
> +
> +       psize = (clkspec->args_count + 1) * 4;
> +       ret = rcar_du_of_add_property(lvds, "clocks", value, psize);
> +       if (ret < 0)
> +               goto out_free_properties;
> +
> +       /*
> +        * Insert the node in the OF graph: patch the LVDS ports remote-endpoint
> +        * properties to point to the endpoints of the sibling nodes in the
> +        * graph.
> +        */
> +       prop = of_find_property(lvds_endpoints[0], "remote-endpoint", NULL);
> +       if (!prop)
> +               goto out_free_properties;
> +
> +       *(__be32 *)prop->value = cpu_to_be32(local->phandle);
> +
> +       prop = of_find_property(lvds_endpoints[1], "remote-endpoint", NULL);
> +       if (!prop)
> +               goto out_free_properties;
> +
> +       *(__be32 *)prop->value = cpu_to_be32(remote->phandle);
> +
> +       /* Apply the overlay, this will resolve phandles. */
> +       ovcs_id = 0;
> +       ret = of_overlay_apply(overlay.np, &ovcs_id);
> +
> +       /* We're done, free all allocated memory. */
> +out_free_properties:
> +       rcar_du_of_free_properties(lvds);
> +       rcar_du_of_free_properties(du_port);
> +       rcar_du_of_free_properties(du_port_fixup);
> +out_free_names:
> +       kfree(lvds->full_name);
> +       kfree(du_port->full_name);
> +       kfree(du_port_fixup->full_name);
> +out_put_nodes:
> +       of_node_put(lvds);
> +       of_node_put(lvds_endpoints[0]);
> +       of_node_put(lvds_endpoints[1]);
> +       of_node_put(du_port);
> +       of_node_put(du_port_fixup);
> +
> +       rcar_du_of_free_overlay(&overlay);
> +}
> +
> +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
> +{
> +       const struct rcar_du_device_info *info;
> +       const struct of_device_id *match;
> +       struct device_node *du;
> +       unsigned int i;
> +       int ret;
> +
> +       /* Get the DU node and exit if not present or disabled. */
> +       du = of_find_matching_node_and_match(NULL, of_ids, &match);
> +       if (!du || !of_device_is_available(du))
> +               goto done;
> +
> +       info = match->data;
> +
> +       /* Patch every LVDS encoder. */
> +       for (i = 0; i < info->num_lvds; ++i) {
> +               struct of_phandle_args clkspec;
> +               struct device_node *local, *remote;
> +               struct resource res;
> +               unsigned int port_id;
> +               const __be32 *reg;
> +               char name[7];
> +               int index;
> +
> +               /*
> +                * Retrieve the register specifier, the clock specifier and the
> +                * local and remote endpoints of the LVDS link.
> +                */
> +               sprintf(name, "lvds.%u", i);
> +               index = of_property_match_string(du, "reg-names", name);
> +               if (index < 0)
> +                       continue;
> +
> +               reg = of_get_address(du, index, NULL, NULL);
> +               if (!reg)
> +                       continue;
> +
> +               ret = of_address_to_resource(du, index, &res);
> +               if (ret < 0)
> +                       continue;
> +
> +               index = of_property_match_string(du, "clock-names", name);
> +               if (index < 0)
> +                       continue;
> +
> +               ret = of_parse_phandle_with_args(du, "clocks", "#clock-cells",
> +                                                index, &clkspec);
> +               if (ret < 0)
> +                       continue;
> +
> +               port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> +
> +               local = of_graph_get_endpoint_by_regs(du, port_id, 0);
> +               if (!local) {
> +                       of_node_put(clkspec.np);
> +                       continue;
> +               }
> +
> +               remote = of_graph_get_remote_endpoint(local);
> +               if (!remote) {
> +                       of_node_put(local);
> +                       of_node_put(clkspec.np);
> +                       continue;
> +               }
> +
> +               /* Patch the LVDS encoder. */
> +               rcar_du_of_lvds_patch_one(du, port_id, &res, reg, &clkspec,
> +                                         local, remote);
> +
> +               of_node_put(clkspec.np);
> +               of_node_put(remote);
> +               of_node_put(local);
> +       }
> +
> +done:
> +       of_node_put(du);
> +}
> +#else
> +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
> +{
> +}
> +#endif /* CONFIG_DRM_RCAR_LVDS */
> +
> +void __init rcar_du_of_init(const struct of_device_id *of_ids)
> +{
> +       rcar_du_of_lvds_patch(of_ids);
> +}
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> new file mode 100644
> index 000000000000..7105eaef58c6
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> @@ -0,0 +1,16 @@
> +// SPDX-License-Identifier: GPL-2.0

The guidelines say headers should be C style. This is due to headers
getting included by assembly code.

> +/*
> + * rcar_du_of.h - Legacy DT bindings compatibility
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + */
> +#ifndef __RCAR_DU_OF_H__
> +#define __RCAR_DU_OF_H__
> +
> +#include <linux/init.h>
> +
> +struct of_device_id;
> +
> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
> +
> +#endif /* __RCAR_DU_OF_H__ */
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> new file mode 100644
> index 000000000000..bc75c7a1c3bd
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> @@ -0,0 +1,82 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds.dts - Legacy LVDS DT bindings conversion
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/*
> + * The target-paths, lvds node name, DU port number and LVDS remote endpoints
> + * will be patched dynamically at runtime.
> + */
> +
> +/dts-v1/;
> +/ {
> +       fragment@0 {
> +               target-path = "soc";

I don't really like this abuse of target-path that isn't really a
valid path. I don't debate the need, but we just need a standard way
to handle this.

Perhaps we need to allow target-path to be a string list. That gets
back to my question on how many static combinations you have. I'd
prefer duplication of overlays with simple applying code to coding a
bunch of matching and fixups.

> +               __overlay__ {
> +                       lvds {
> +                               ports {
> +                                       #address-cells = <1>;
> +                                       #size-cells = <0>;
> +
> +                                       port@0 {
> +                                               reg = <0>;
> +                                               lvds_input: endpoint {
> +                                                       remote-endpoint = <0>;
> +                                               };
> +                                       };
> +
> +                                       port@1 {
> +                                               reg = <1>;
> +                                               lvds_output: endpoint {
> +                                                       remote-endpoint = <0>;
> +                                               };
> +                                       };
> +                               };
> +                       };
> +               };
> +       };
> +
> +       fragment@1 {
> +               target-path = "du";
> +               __overlay__ {
> +                       ports {
> +                               port@0 {
> +                                       endpoint {
> +                                               remote-endpoint = <&lvds_input>;
> +                                       };
> +                               };
> +                       };
> +               };
> +       };
> +
> +       fragment@2 {
> +               target-path = "lvds-sink";
> +               __overlay__ {
> +                       remote-endpoint = <&lvds_output>;
> +               };
> +       };
> +
> +       __local_fixups__ {

dtc generates this now.

> +               fragment@1 {
> +                       __overlay__ {
> +                               ports {
> +                                       port@0 {
> +                                               endpoint {
> +                                                       remote-endpoint = <0>;
> +                                               };
> +                                       };
> +                               };
> +                       };
> +               };
> +               fragment@2 {
> +                       __overlay__ {
> +                               remote-endpoint = <0>;
> +                       };
> +               };
> +       };
> +};
> --
> Regards,
>
> Laurent Pinchart
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 17:09     ` Rob Herring
@ 2018-01-15 18:01       ` Laurent Pinchart
  2018-01-16  8:56         ` Geert Uytterhoeven
  2018-01-15 19:12       ` Frank Rowand
  1 sibling, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-15 18:01 UTC (permalink / raw)
  To: Rob Herring
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Laurent Pinchart, Sergei Shtylyov, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Geert Uytterhoeven,
	Frank Rowand

Hi Rob,

(CC'ing Geert)

On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
> +Frank
> 
> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> > The internal LVDS encoders now have their own DT bindings. Before
> > switching the driver infrastructure to those new bindings, implement
> > backward-compatibility through live DT patching.
> 
> Uhh, we just got rid of TI's patching and now adding this one. I guess
> it's necessary, but I'd like to know how long we need to keep this?

That's a good question. How long are we supposed to keep DT backward 
compatibility for ? I don't think there's a one-size-fits-them-all answer to 
this question. Geert, any opinion ? How long do you plan to keep the CPG 
(clocks) DT backward compatibility for instance ?

> How many overlays would you need if everything is static (i.e. removing all
> your fixup code)?

Do you mean if I hardcoded support for SoCs individually instead of handling 
the differences in code ? At least 5 as that's the number of SoCs that are 
impacted, but that wouldn't be enough. Part of the DT structure that is 
patched is board-specific, not SoC-specific. That's 10 boards in mainline, 
plus all the custom boards out there, and even the development boards 
supported in mainline to which a flat panel has been externally connected.

> > Patching is disabled and will be enabled along with support for the new
> > DT bindings in the DU driver.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > Changes since v1:
> > 
> > - Select OF_FLATTREE
> > - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> > - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> > - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> > - Pass void begin and end pointers to rcar_du_of_get_overlay()
> > - Use of_get_parent() instead of accessing the parent pointer directly
> > - Find the LVDS endpoints nodes based on the LVDS node instead of the
> >   root of the overlay
> > - Update to the <soc>-lvds compatible string format
> > ---
> >  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
> >  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 +++++++++++++++++++++++
> >  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
> >  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
> >  5 files changed, 553 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > 
> > diff --git a/drivers/gpu/drm/rcar-du/Kconfig
> > b/drivers/gpu/drm/rcar-du/Kconfig index 5d0b4b7119af..3f83352a7313 100644
> > --- a/drivers/gpu/drm/rcar-du/Kconfig
> > +++ b/drivers/gpu/drm/rcar-du/Kconfig
> > @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
> >         bool "R-Car DU LVDS Encoder Support"
> >         depends on DRM_RCAR_DU
> >         select DRM_PANEL
> > +       select OF_FLATTREE
> > +       select OF_OVERLAY
> 
> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
> could have an overlay from a non-FDT source...

Up to you, I'll happily drop OF_FLATTREE if it gets selected automatically. If 
you think it's a good idea I can submit a patch.

> >         help
> >           Enable support for the R-Car Display Unit embedded LVDS
> >           encoders.

[snip]

> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_of.c new file mode 100644
> > index 000000000000..2bf91201fc93
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> > @@ -0,0 +1,451 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * rcar_du_of.c - Legacy DT bindings compatibility
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + *
> > + * Based on work from Jyri Sarha <jsarha@ti.com>
> > + * Copyright (C) 2015 Texas Instruments
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_fdt.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/slab.h>
> > +
> > +#include "rcar_du_crtc.h"
> > +#include "rcar_du_drv.h"
> > +
> > +#ifdef CONFIG_DRM_RCAR_LVDS
> 
> Why not make compiling this file conditional in the Makefile?

In case I need to patch other DU-related constructs in the future other than 
LVDS. I could compile this conditionally in the Makefile for now and change it 
later if needed. I have no strong preference.

> > +
> > +struct rcar_du_of_overlay {
> > +       struct device_node *np;
> > +       void *data;
> > +       void *mem;
> > +};
> > +
> > +static void __init rcar_du_of_free_overlay(struct rcar_du_of_overlay
> > *overlay)
> > +{
> > +       of_node_put(overlay->np);
> > +       kfree(overlay->data);
> > +       kfree(overlay->mem);
> > +}
> > +
> > +static int __init rcar_du_of_get_overlay(struct rcar_du_of_overlay
> > *overlay,
> > +                                        void *begin, void
> > *end)
> > +{
> > +       const size_t size = end - begin;
> > +
> > +       memset(overlay, 0, sizeof(*overlay));
> > +
> > +       if (!size)
> > +               return -EINVAL;
> > +
> > +       overlay->data = kmemdup(begin, size, GFP_KERNEL);
> > +       if (!overlay->data)
> > +               return -ENOMEM;
> > +
> > +       overlay->mem = of_fdt_unflatten_tree(overlay->data, NULL,
> > &overlay->np); +       if (!overlay->mem) {
> > +               rcar_du_of_free_overlay(overlay);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static struct device_node __init *
> > +rcar_du_of_find_node_by_path(struct device_node *parent, const char
> > *path)
> > +{
> 
> What's wrong with the core function to do this?

I haven't found any function that performs lookup by path starting at a given 
root. of_find_node_by_path() operates on an absolute path starting at the root 
of the live DT. Is there a function I have missed ?

And of course this should be a core OF function, there's no reason to make it 
driver-specific.

> > +       parent = of_node_get(parent);
> > +       if (!parent)
> > +               return NULL;
> > +
> > +       while (parent && *path == '/') {
> > +               struct device_node *child = NULL;
> > +               struct device_node *node;
> > +               const char *next;
> > +               size_t len;
> > +
> > +               /* Skip the initial '/' delimiter and find the next one.
> > */
> > +               path++;
> > +               next = strchrnul(path, '/');
> > +               len = next - path;
> > +               if (!len)
> > +                       goto error;
> > +
> > +               for_each_child_of_node(parent, node) {
> > +                       const char *name = kbasename(node->full_name);
> > +
> > +                       if (strncmp(path, name, len) == 0 &&
> > +                           strlen(name) == len) {
> > +                               child = node;
> > +                               break;
> > +                       }
> > +               }
> > +
> > +               if (!child)
> > +                       goto error;
> > +
> > +               of_node_put(parent);
> > +               parent = child;
> > +               path = next;
> > +       }
> > +
> > +       return parent;
> > +
> > +error:
> > +       of_node_put(parent);
> > +       return NULL;
> > +}
> > +
> > +static int __init rcar_du_of_add_property(struct device_node *np,
> > +                                         const char *name, const void
> > *value,
> > +                                         size_t length)
> > +{
> 
> This should be a core function. In fact, IIRC, Pantelis had a patch
> adding functions like this. I believe there were only minor issues and
> I said I would take it even without users, but he never followed up.

I agree, it should be a core function. The reason I implemented it as a 
driver-specific function was that I wanted a functional prototype and an 
overall agreement on the approach before proposing extensions to the OF API.

> > +       struct property *prop;
> 
> We want to make struct property opaque, so I don't really want to see
> more users...

If we make this a core function it shouldn't be an issue. We would then also 
need a function to update the value of an existing property. That's more 
tricky than it might seem, as properties are either fully dynamic or fully 
static. We can't have a non-OF_DYNAMIC struct property instance (created when 
parsing the FDT) that gets a dynamically-allocated value pointer all of a 
sudden.

I see two ways to fix this, either making dynamic memory management more fine-
grained at the property level, or creating a new property to replace the old 
one when updating the value. I believe device_node instances suffer from the 
same problem.

By the way I believe there are memory leaks in the OF core, as I haven't found 
any code that frees OF_DYNAMIC properties. A grep for OF_DYNAMIC or 
OF_IS_DYNAMIC returned no check of the flag for properties apart from one 
occurrence in arch/sparc/kernel/prom_common.c.

> > +
> > +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> > +       if (!prop)
> > +               return -ENOMEM;
> > +
> > +       prop->name = kstrdup(name, GFP_KERNEL);
> > +       prop->value = kmemdup(value, length, GFP_KERNEL);
> > +       prop->length = length;
> > +
> > +       if (!prop->name || !prop->value) {
> > +               kfree(prop->name);
> > +               kfree(prop->value);
> > +               kfree(prop);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       of_property_set_flag(prop, OF_DYNAMIC);
> > +
> > +       prop->next = np->properties;
> > +       np->properties = prop;
> > +
> > +       return 0;
> > +}
> > +
> > +/* Free properties allocated dynamically by rcar_du_of_add_property(). */
> > +static void __init rcar_du_of_free_properties(struct device_node *np)
> > +{
> > +       while (np->properties) {
> > +               struct property *prop = np->properties;
> > +
> > +               np->properties = prop->next;
> > +
> > +               if (OF_IS_DYNAMIC(prop)) {
> > +                       kfree(prop->name);
> > +                       kfree(prop->value);
> > +                       kfree(prop);
> > +               }
> > +       }
> > +}
> > +
> > +static int __init rcar_du_of_update_target_path(struct device_node *du,
> > +                                               struct device_node
> > *remote,
> > +                                               struct device_node *np)
> > +{
> > +       struct device_node *target = NULL;
> > +       struct property **prev;
> > +       struct property *prop;
> > +       char *path;
> > +       int ret;
> > +
> > +       for (prop = np->properties, prev = &prop; prop != NULL;
> > +            prev = &prop->next, prop = prop->next) {
> > +               if (of_prop_cmp(prop->name, "target-path"))
> > +                       continue;
> > +
> > +               if (!of_prop_cmp(prop->value, "soc")) {
> > +                       target = of_get_parent(du);
> > +                       break;
> > +               }
> > +               if (!of_prop_cmp(prop->value, "du")) {
> > +                       target = of_node_get(du);
> > +                       break;
> > +               }
> > +               if (!of_prop_cmp(prop->value, "lvds-sink")) {
> > +                       target = of_graph_get_port_parent(remote);
> > +                       break;
> > +               }
> > +
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (!target)
> > +               return -EINVAL;
> > +
> > +       path = kasprintf(GFP_KERNEL, "%pOF", target);
> > +       of_node_put(target);
> > +       if (!path)
> > +               return -ENOMEM;
> > +
> > +       /*
> > +        * Remove the existing target-path property that has not been
> > +        * dynamically allocated and replace it with a new dynamic one to
> > +        * ensure that the value will be properly freed.
> > +        */
> > +       *prev = prop->next;
> 
> You are leaking prev. prev should be moved the deleted property list.
> But then you shouldn't be mucking with properties at this level in the
> first place.

If we implement an OF function to update the value of a property I won't need 
to, and I'd be fine with that.

What I need for this patch series is three new functions to

- lookup a node by path starting at a given node
- add a property
- update the value of an existing property

I can submit proposals if we agree that those functions should be implemented. 
I'd like to know how you would like to handle the last two though: we have 
lots of type-specific property read functions, I don't think we should 
duplicate all that for write given the number of expected users. Maybe the 
property add and update functions should just take a void pointer and a length 
for the value ?

> > +       ret = rcar_du_of_add_property(np, "target-path", path,
> > +                                     strlen(path) + 1);
> > +       if (ret < 0) {
> > +               kfree(path);
> > +               return ret;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +extern char __dtb_rcar_du_of_lvds_begin[];
> > +extern char __dtb_rcar_du_of_lvds_end[];
> > +
> > +static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
> > +                                            unsigned int port_id,
> > +                                            const struct resource *res,
> > +                                            const __be32 *reg,
> > +                                            const struct of_phandle_args
> > *clkspec,
> > +                                            struct device_node
> > *local,
> > +                                            struct device_node
> > *remote)
> > +{
> > +       struct rcar_du_of_overlay overlay;
> > +       struct device_node *du_port_fixup;
> > +       struct device_node *du_port;
> > +       struct device_node *lvds_endpoints[2];
> > +       struct device_node *lvds;
> > +       struct device_node *fragment;
> > +       struct device_node *bus;
> > +       struct property *prop;
> > +       const char *compatible;
> > +       const char *soc_suffix;
> > +       unsigned int psize;
> > +       unsigned int i;
> > +       __be32 value[4];
> > +       char name[23];
> > +       int ovcs_id;
> > +       int ret;
> > +
> > +       /* Skip if the LVDS node already exists. */
> > +       sprintf(name, "lvds@%llx", (u64)res->start);
> 
> Fragile. unit-address and res->start are not necessarily the same thing.

I thought the unit address was supposed to be the start address of the first 
reg entry ? I can instead loop over all nodes named lvds and compared the reg 
address.

In practice I think this should work. This function is only called if the 
device tree implements the legacy bindings (otherwise there's no "lvds.*" reg-
names entry) and we thus have no existing lvds@* node at boot time. The 
purpose of this check is to avoid patching the same device tree twice if the 
module is removed an reinserted. I thus control the unit address as I generate 
it myself.

> > +       bus = of_get_parent(du);
> > +       lvds = of_get_child_by_name(bus, name);
> > +       of_node_put(bus);
> > +       if (lvds) {
> > +               of_node_put(lvds);
> > +               return;
> > +       }
> > +
> > +       /* Parse the overlay. */
> > +       ret = rcar_du_of_get_overlay(&overlay,
> > __dtb_rcar_du_of_lvds_begin,
> > +                                    __dtb_rcar_du_of_lvds_end);
> > +       if (ret < 0)
> > +               return;
> > +
> > +       /*
> > +        * Patch the LVDS and DU port nodes names and the associated fixup
> > +        * entries.
> > +        */
> > +       lvds = rcar_du_of_find_node_by_path(overlay.np,
> > +               "/fragment@0/__overlay__/lvds");
> > +       lvds_endpoints[0] = rcar_du_of_find_node_by_path(lvds,
> > +               "/ports/port@0/endpoint");
> > +       lvds_endpoints[1] = rcar_du_of_find_node_by_path(lvds,
> > +               "/ports/port@1/endpoint");
> > +       du_port = rcar_du_of_find_node_by_path(overlay.np,
> > +               "/fragment@1/__overlay__/ports/port@0");
> > +       du_port_fixup = rcar_du_of_find_node_by_path(overlay.np,
> > +               "/__local_fixups__/fragment@1/__overlay__/ports/port@0");
> > +       if (!lvds || !lvds_endpoints[0] || !lvds_endpoints[1] ||
> > +           !du_port || !du_port_fixup)
> > +               goto out_put_nodes;
> > +
> > +       lvds->full_name = kstrdup(name, GFP_KERNEL);
> > +
> > +       sprintf(name, "port@%u", port_id);
> > +       du_port->full_name = kstrdup(name, GFP_KERNEL);
> > +       du_port_fixup->full_name = kstrdup(name, GFP_KERNEL);
> > +
> > +       if (!lvds->full_name || !du_port->full_name ||
> > +           !du_port_fixup->full_name)
> > +               goto out_free_names;
> > +
> > +       /* Patch the target paths in all fragments. */
> > +       for_each_child_of_node(overlay.np, fragment) {
> > +               if (strncmp("fragment@", of_node_full_name(fragment), 9))
> > +                       continue;
> > +
> > +               ret = rcar_du_of_update_target_path(du, remote, fragment);
> > +               if (ret < 0) {
> > +                       of_node_put(fragment);
> > +                       goto out_free_properties;
> > +               }
> > +       }
> > +
> > +       /*
> > +        * Create a compatible string for the LVDS node using the SoC
> > model
> > +        * from the DU node.
> > +        */
> > +       ret = of_property_read_string(du, "compatible", &compatible);
> > +       if (ret < 0)
> > +               goto out_free_properties;
> > +
> > +       soc_suffix = strchr(compatible, '-');
> > +       if (!soc_suffix || strlen(soc_suffix) > 10)
> > +               goto out_free_properties;
> > +
> > +       psize = sprintf(name, "renesas,%s-lvds", soc_suffix + 1) + 1;
> > +       ret = rcar_du_of_add_property(lvds, "compatible", name, psize);
> > +       if (ret < 0)
> > +               goto out_free_properties;
> > +
> > +       /* Copy the LVDS reg and clocks properties from the DU node. */
> > +       psize = (of_n_addr_cells(du) + of_n_size_cells(du)) * 4;
> > +       ret = rcar_du_of_add_property(lvds, "reg", reg, psize);
> > +       if (ret < 0)
> > +               goto out_free_properties;
> > +
> > +       if (clkspec->args_count >= ARRAY_SIZE(value) - 1)
> > +               goto out_free_properties;
> > +
> > +       value[0] = cpu_to_be32(clkspec->np->phandle);
> > +       for (i = 0; i < clkspec->args_count; ++i)
> > +               value[i + 1] = cpu_to_be32(clkspec->args[i]);
> > +
> > +       psize = (clkspec->args_count + 1) * 4;
> > +       ret = rcar_du_of_add_property(lvds, "clocks", value, psize);
> > +       if (ret < 0)
> > +               goto out_free_properties;
> > +
> > +       /*
> > +        * Insert the node in the OF graph: patch the LVDS ports
> > remote-endpoint
> > +        * properties to point to the endpoints of the sibling nodes in
> > the
> > +        * graph.
> > +        */
> > +       prop = of_find_property(lvds_endpoints[0], "remote-endpoint",
> > NULL);
> > +       if (!prop)
> > +               goto out_free_properties;
> > +
> > +       *(__be32 *)prop->value = cpu_to_be32(local->phandle);
> > +
> > +       prop = of_find_property(lvds_endpoints[1], "remote-endpoint",
> > NULL);
> > +       if (!prop)
> > +               goto out_free_properties;
> > +
> > +       *(__be32 *)prop->value = cpu_to_be32(remote->phandle);
> > +
> > +       /* Apply the overlay, this will resolve phandles. */
> > +       ovcs_id = 0;
> > +       ret = of_overlay_apply(overlay.np, &ovcs_id);
> > +
> > +       /* We're done, free all allocated memory. */
> > +out_free_properties:
> > +       rcar_du_of_free_properties(lvds);
> > +       rcar_du_of_free_properties(du_port);
> > +       rcar_du_of_free_properties(du_port_fixup);
> > +out_free_names:
> > +       kfree(lvds->full_name);
> > +       kfree(du_port->full_name);
> > +       kfree(du_port_fixup->full_name);
> > +out_put_nodes:
> > +       of_node_put(lvds);
> > +       of_node_put(lvds_endpoints[0]);
> > +       of_node_put(lvds_endpoints[1]);
> > +       of_node_put(du_port);
> > +       of_node_put(du_port_fixup);
> > +
> > +       rcar_du_of_free_overlay(&overlay);
> > +}
> > +
> > +static void __init rcar_du_of_lvds_patch(const struct of_device_id
> > *of_ids)
> > +{
> > +       const struct rcar_du_device_info *info;
> > +       const struct of_device_id *match;
> > +       struct device_node *du;
> > +       unsigned int i;
> > +       int ret;
> > +
> > +       /* Get the DU node and exit if not present or disabled. */
> > +       du = of_find_matching_node_and_match(NULL, of_ids, &match);
> > +       if (!du || !of_device_is_available(du))
> > +               goto done;
> > +
> > +       info = match->data;
> > +
> > +       /* Patch every LVDS encoder. */
> > +       for (i = 0; i < info->num_lvds; ++i) {
> > +               struct of_phandle_args clkspec;
> > +               struct device_node *local, *remote;
> > +               struct resource res;
> > +               unsigned int port_id;
> > +               const __be32 *reg;
> > +               char name[7];
> > +               int index;
> > +
> > +               /*
> > +                * Retrieve the register specifier, the clock specifier
> > and the
> > +                * local and remote endpoints of the LVDS link.
> > +                */
> > +               sprintf(name, "lvds.%u", i);
> > +               index = of_property_match_string(du, "reg-names", name);
> > +               if (index < 0)
> > +                       continue;
> > +
> > +               reg = of_get_address(du, index, NULL, NULL);
> > +               if (!reg)
> > +                       continue;
> > +
> > +               ret = of_address_to_resource(du, index, &res);
> > +               if (ret < 0)
> > +                       continue;
> > +
> > +               index = of_property_match_string(du, "clock-names", name);
> > +               if (index < 0)
> > +                       continue;
> > +
> > +               ret = of_parse_phandle_with_args(du, "clocks",
> > "#clock-cells",
> > +                                                index, &clkspec);
> > +               if (ret < 0)
> > +                       continue;
> > +
> > +               port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> > +
> > +               local = of_graph_get_endpoint_by_regs(du, port_id, 0);
> > +               if (!local) {
> > +                       of_node_put(clkspec.np);
> > +                       continue;
> > +               }
> > +
> > +               remote = of_graph_get_remote_endpoint(local);
> > +               if (!remote) {
> > +                       of_node_put(local);
> > +                       of_node_put(clkspec.np);
> > +                       continue;
> > +               }
> > +
> > +               /* Patch the LVDS encoder. */
> > +               rcar_du_of_lvds_patch_one(du, port_id, &res, reg,
> > &clkspec,
> > +                                         local, remote);
> > +
> > +               of_node_put(clkspec.np);
> > +               of_node_put(remote);
> > +               of_node_put(local);
> > +       }
> > +
> > +done:
> > +       of_node_put(du);
> > +}
> > +#else
> > +static void __init rcar_du_of_lvds_patch(const struct of_device_id
> > *of_ids)
> > +{
> > +}
> > +#endif /* CONFIG_DRM_RCAR_LVDS */
> > +
> > +void __init rcar_du_of_init(const struct of_device_id *of_ids)
> > +{
> > +       rcar_du_of_lvds_patch(of_ids);
> > +}
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h
> > b/drivers/gpu/drm/rcar-du/rcar_du_of.h new file mode 100644
> > index 000000000000..7105eaef58c6
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> > @@ -0,0 +1,16 @@
> > +// SPDX-License-Identifier: GPL-2.0
> 
> The guidelines say headers should be C style. This is due to headers
> getting included by assembly code.

My bad, I'll fix that.

> > +/*
> > + * rcar_du_of.h - Legacy DT bindings compatibility
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + */
> > +#ifndef __RCAR_DU_OF_H__
> > +#define __RCAR_DU_OF_H__
> > +
> > +#include <linux/init.h>
> > +
> > +struct of_device_id;
> > +
> > +void __init rcar_du_of_init(const struct of_device_id *of_ids);
> > +
> > +#endif /* __RCAR_DU_OF_H__ */
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts new file mode 100644
> > index 000000000000..bc75c7a1c3bd
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > @@ -0,0 +1,82 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * rcar_du_of_lvds.dts - Legacy LVDS DT bindings conversion
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + *
> > + * Based on work from Jyri Sarha <jsarha@ti.com>
> > + * Copyright (C) 2015 Texas Instruments
> > + */
> > +
> > +/*
> > + * The target-paths, lvds node name, DU port number and LVDS remote
> > endpoints
> > + * will be patched dynamically at runtime.
> > + */
> > +
> > +/dts-v1/;
> > +/ {
> > +       fragment@0 {
> > +               target-path = "soc";
> 
> I don't really like this abuse of target-path that isn't really a
> valid path. I don't debate the need, but we just need a standard way
> to handle this.

I agree it's a bit of a hack, I just couldn't think of a better way. Proposals 
are welcome :-)

> Perhaps we need to allow target-path to be a string list. That gets
> back to my question on how many static combinations you have. I'd
> prefer duplication of overlays with simple applying code to coding a
> bunch of matching and fixups.

See my answer above, I don't think static overlays would be a good option. For 
fragments 0 and 1 we could use one overlay per SoC, which could be manageable, 
but fragment 2 is board-specific.

> > +               __overlay__ {
> > +                       lvds {
> > +                               ports {
> > +                                       #address-cells = <1>;
> > +                                       #size-cells = <0>;
> > +
> > +                                       port@0 {
> > +                                               reg = <0>;
> > +                                               lvds_input: endpoint {
> > +                                                       remote-endpoint =
> > <0>; +                                               };
> > +                                       };
> > +
> > +                                       port@1 {
> > +                                               reg = <1>;
> > +                                               lvds_output: endpoint {
> > +                                                       remote-endpoint =
> > <0>;
> > +                                               };
> > +                                       };
> > +                               };
> > +                       };
> > +               };
> > +       };
> > +
> > +       fragment@1 {
> > +               target-path = "du";
> > +               __overlay__ {
> > +                       ports {
> > +                               port@0 {
> > +                                       endpoint {
> > +                                               remote-endpoint =
> > <&lvds_input>;
> > +                                       };
> > +                               };
> > +                       };
> > +               };
> > +       };
> > +
> > +       fragment@2 {
> > +               target-path = "lvds-sink";
> > +               __overlay__ {
> > +                       remote-endpoint = <&lvds_output>;
> > +               };
> > +       };
> > +
> > +       __local_fixups__ {
> 
> dtc generates this now.

Ah, nice to know. I'll retest without the manual __local_fixups__.

> > +               fragment@1 {
> > +                       __overlay__ {
> > +                               ports {
> > +                                       port@0 {
> > +                                               endpoint {
> > +                                                       remote-endpoint =
> > <0>; +                                               };
> > +                                       };
> > +                               };
> > +                       };
> > +               };
> > +               fragment@2 {
> > +                       __overlay__ {
> > +                               remote-endpoint = <0>;
> > +                       };
> > +               };
> > +       };
> > +};

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 17:09     ` Rob Herring
  2018-01-15 18:01       ` Laurent Pinchart
@ 2018-01-15 19:12       ` Frank Rowand
  2018-01-15 19:22         ` Laurent Pinchart
  1 sibling, 1 reply; 38+ messages in thread
From: Frank Rowand @ 2018-01-15 19:12 UTC (permalink / raw)
  To: Rob Herring, Laurent Pinchart
  Cc: dri-devel, open list:MEDIA DRIVERS FOR RENESAS - FCP,
	Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Frank Rowand

On 01/15/18 09:09, Rob Herring wrote:
> +Frank
> 
> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart
> <laurent.pinchart+renesas@ideasonboard.com> wrote:
>> The internal LVDS encoders now have their own DT bindings. Before
>> switching the driver infrastructure to those new bindings, implement
>> backward-compatibility through live DT patching.
> 
> Uhh, we just got rid of TI's patching and now adding this one. I guess

Please no.  What we just got rid of was making it difficult for me to
make changes to the overlay infrastructure.  There are issues with
overlays that need to be fixed before overlays become really usable.
I am about to propose the next change, which involves removing a
chunk of code that I will not be able to remove if this patch is
accepted (the proposal is awaiting me collecting some data about
the impact of the change, which I expect to complete this week).

Can you please handle both the old and new bindings through driver
code instead?

Thanks,

Frank


> it's necessary, but I'd like to know how long we need to keep this?
> 
> How many overlays would you need if everything is static (i.e.
> removing all your fixup code)?
> 
>> Patching is disabled and will be enabled along with support for the new
>> DT bindings in the DU driver.
>>
>> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>> ---
>> Changes since v1:
>>
>> - Select OF_FLATTREE
>> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
>> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
>> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
>> - Pass void begin and end pointers to rcar_du_of_get_overlay()
>> - Use of_get_parent() instead of accessing the parent pointer directly
>> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>>   root of the overlay
>> - Update to the <soc>-lvds compatible string format
>> ---
>>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++++++++
>>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>>  5 files changed, 553 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>>
>> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
>> index 5d0b4b7119af..3f83352a7313 100644
>> --- a/drivers/gpu/drm/rcar-du/Kconfig
>> +++ b/drivers/gpu/drm/rcar-du/Kconfig
>> @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
>>         bool "R-Car DU LVDS Encoder Support"
>>         depends on DRM_RCAR_DU
>>         select DRM_PANEL
>> +       select OF_FLATTREE
>> +       select OF_OVERLAY
> 
> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
> could have an overlay from a non-FDT source...
> 
>>         help
>>           Enable support for the R-Car Display Unit embedded LVDS encoders.
>>
>> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
>> index 0cf5c11030e8..8ed569a0f462 100644
>> --- a/drivers/gpu/drm/rcar-du/Makefile
>> +++ b/drivers/gpu/drm/rcar-du/Makefile
>> @@ -5,10 +5,11 @@ rcar-du-drm-y := rcar_du_crtc.o \
>>                  rcar_du_group.o \
>>                  rcar_du_kms.o \
>>                  rcar_du_lvdscon.o \
>> +                rcar_du_of.o \
>>                  rcar_du_plane.o
>>
>>  rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)    += rcar_du_lvdsenc.o
>> -
>> +rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)    += rcar_du_of_lvds.dtb.o
>>  rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)     += rcar_du_vsp.o
>>
>>  obj-$(CONFIG_DRM_RCAR_DU)              += rcar-du-drm.o
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c b/drivers/gpu/drm/rcar-du/rcar_du_of.c
>> new file mode 100644
>> index 000000000000..2bf91201fc93
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
>> @@ -0,0 +1,451 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of.c - Legacy DT bindings compatibility
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_fdt.h>
>> +#include <linux/of_graph.h>
>> +#include <linux/slab.h>
>> +
>> +#include "rcar_du_crtc.h"
>> +#include "rcar_du_drv.h"
>> +
>> +#ifdef CONFIG_DRM_RCAR_LVDS
> 
> Why not make compiling this file conditional in the Makefile?
> 
>> +
>> +struct rcar_du_of_overlay {
>> +       struct device_node *np;
>> +       void *data;
>> +       void *mem;
>> +};
>> +
>> +static void __init rcar_du_of_free_overlay(struct rcar_du_of_overlay *overlay)
>> +{
>> +       of_node_put(overlay->np);
>> +       kfree(overlay->data);
>> +       kfree(overlay->mem);
>> +}
>> +
>> +static int __init rcar_du_of_get_overlay(struct rcar_du_of_overlay *overlay,
>> +                                        void *begin, void *end)
>> +{
>> +       const size_t size = end - begin;
>> +
>> +       memset(overlay, 0, sizeof(*overlay));
>> +
>> +       if (!size)
>> +               return -EINVAL;
>> +
>> +       overlay->data = kmemdup(begin, size, GFP_KERNEL);
>> +       if (!overlay->data)
>> +               return -ENOMEM;
>> +
>> +       overlay->mem = of_fdt_unflatten_tree(overlay->data, NULL, &overlay->np);
>> +       if (!overlay->mem) {
>> +               rcar_du_of_free_overlay(overlay);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static struct device_node __init *
>> +rcar_du_of_find_node_by_path(struct device_node *parent, const char *path)
>> +{
> 
> What's wrong with the core function to do this?
> 
>> +       parent = of_node_get(parent);
>> +       if (!parent)
>> +               return NULL;
>> +
>> +       while (parent && *path == '/') {
>> +               struct device_node *child = NULL;
>> +               struct device_node *node;
>> +               const char *next;
>> +               size_t len;
>> +
>> +               /* Skip the initial '/' delimiter and find the next one. */
>> +               path++;
>> +               next = strchrnul(path, '/');
>> +               len = next - path;
>> +               if (!len)
>> +                       goto error;
>> +
>> +               for_each_child_of_node(parent, node) {
>> +                       const char *name = kbasename(node->full_name);
>> +
>> +                       if (strncmp(path, name, len) == 0 &&
>> +                           strlen(name) == len) {
>> +                               child = node;
>> +                               break;
>> +                       }
>> +               }
>> +
>> +               if (!child)
>> +                       goto error;
>> +
>> +               of_node_put(parent);
>> +               parent = child;
>> +               path = next;
>> +       }
>> +
>> +       return parent;
>> +
>> +error:
>> +       of_node_put(parent);
>> +       return NULL;
>> +}
>> +
>> +static int __init rcar_du_of_add_property(struct device_node *np,
>> +                                         const char *name, const void *value,
>> +                                         size_t length)
>> +{
> 
> This should be a core function. In fact, IIRC, Pantelis had a patch
> adding functions like this. I believe there were only minor issues and
> I said I would take it even without users, but he never followed up.
> 
>> +       struct property *prop;
> 
> We want to make struct property opaque, so I don't really want to see
> more users...
> 
>> +
>> +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
>> +       if (!prop)
>> +               return -ENOMEM;
>> +
>> +       prop->name = kstrdup(name, GFP_KERNEL);
>> +       prop->value = kmemdup(value, length, GFP_KERNEL);
>> +       prop->length = length;
>> +
>> +       if (!prop->name || !prop->value) {
>> +               kfree(prop->name);
>> +               kfree(prop->value);
>> +               kfree(prop);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       of_property_set_flag(prop, OF_DYNAMIC);
>> +
>> +       prop->next = np->properties;
>> +       np->properties = prop;
>> +
>> +       return 0;
>> +}
>> +
>> +/* Free properties allocated dynamically by rcar_du_of_add_property(). */
>> +static void __init rcar_du_of_free_properties(struct device_node *np)
>> +{
>> +       while (np->properties) {
>> +               struct property *prop = np->properties;
>> +
>> +               np->properties = prop->next;
>> +
>> +               if (OF_IS_DYNAMIC(prop)) {
>> +                       kfree(prop->name);
>> +                       kfree(prop->value);
>> +                       kfree(prop);
>> +               }
>> +       }
>> +}
>> +
>> +static int __init rcar_du_of_update_target_path(struct device_node *du,
>> +                                               struct device_node *remote,
>> +                                               struct device_node *np)
>> +{
>> +       struct device_node *target = NULL;
>> +       struct property **prev;
>> +       struct property *prop;
>> +       char *path;
>> +       int ret;
>> +
>> +       for (prop = np->properties, prev = &prop; prop != NULL;
>> +            prev = &prop->next, prop = prop->next) {
>> +               if (of_prop_cmp(prop->name, "target-path"))
>> +                       continue;
>> +
>> +               if (!of_prop_cmp(prop->value, "soc")) {
>> +                       target = of_get_parent(du);
>> +                       break;
>> +               }
>> +               if (!of_prop_cmp(prop->value, "du")) {
>> +                       target = of_node_get(du);
>> +                       break;
>> +               }
>> +               if (!of_prop_cmp(prop->value, "lvds-sink")) {
>> +                       target = of_graph_get_port_parent(remote);
>> +                       break;
>> +               }
>> +
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (!target)
>> +               return -EINVAL;
>> +
>> +       path = kasprintf(GFP_KERNEL, "%pOF", target);
>> +       of_node_put(target);
>> +       if (!path)
>> +               return -ENOMEM;
>> +
>> +       /*
>> +        * Remove the existing target-path property that has not been
>> +        * dynamically allocated and replace it with a new dynamic one to
>> +        * ensure that the value will be properly freed.
>> +        */
>> +       *prev = prop->next;
> 
> You are leaking prev. prev should be moved the deleted property list.
> But then you shouldn't be mucking with properties at this level in the
> first place.
> 
>> +       ret = rcar_du_of_add_property(np, "target-path", path,
>> +                                     strlen(path) + 1);
>> +       if (ret < 0) {
>> +               kfree(path);
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +extern char __dtb_rcar_du_of_lvds_begin[];
>> +extern char __dtb_rcar_du_of_lvds_end[];
>> +
>> +static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
>> +                                            unsigned int port_id,
>> +                                            const struct resource *res,
>> +                                            const __be32 *reg,
>> +                                            const struct of_phandle_args *clkspec,
>> +                                            struct device_node *local,
>> +                                            struct device_node *remote)
>> +{
>> +       struct rcar_du_of_overlay overlay;
>> +       struct device_node *du_port_fixup;
>> +       struct device_node *du_port;
>> +       struct device_node *lvds_endpoints[2];
>> +       struct device_node *lvds;
>> +       struct device_node *fragment;
>> +       struct device_node *bus;
>> +       struct property *prop;
>> +       const char *compatible;
>> +       const char *soc_suffix;
>> +       unsigned int psize;
>> +       unsigned int i;
>> +       __be32 value[4];
>> +       char name[23];
>> +       int ovcs_id;
>> +       int ret;
>> +
>> +       /* Skip if the LVDS node already exists. */
>> +       sprintf(name, "lvds@%llx", (u64)res->start);
> 
> Fragile. unit-address and res->start are not necessarily the same thing.
> 
>> +       bus = of_get_parent(du);
>> +       lvds = of_get_child_by_name(bus, name);
>> +       of_node_put(bus);
>> +       if (lvds) {
>> +               of_node_put(lvds);
>> +               return;
>> +       }
>> +
>> +       /* Parse the overlay. */
>> +       ret = rcar_du_of_get_overlay(&overlay, __dtb_rcar_du_of_lvds_begin,
>> +                                    __dtb_rcar_du_of_lvds_end);
>> +       if (ret < 0)
>> +               return;
>> +
>> +       /*
>> +        * Patch the LVDS and DU port nodes names and the associated fixup
>> +        * entries.
>> +        */
>> +       lvds = rcar_du_of_find_node_by_path(overlay.np,
>> +               "/fragment@0/__overlay__/lvds");
>> +       lvds_endpoints[0] = rcar_du_of_find_node_by_path(lvds,
>> +               "/ports/port@0/endpoint");
>> +       lvds_endpoints[1] = rcar_du_of_find_node_by_path(lvds,
>> +               "/ports/port@1/endpoint");
>> +       du_port = rcar_du_of_find_node_by_path(overlay.np,
>> +               "/fragment@1/__overlay__/ports/port@0");
>> +       du_port_fixup = rcar_du_of_find_node_by_path(overlay.np,
>> +               "/__local_fixups__/fragment@1/__overlay__/ports/port@0");
>> +       if (!lvds || !lvds_endpoints[0] || !lvds_endpoints[1] ||
>> +           !du_port || !du_port_fixup)
>> +               goto out_put_nodes;
>> +
>> +       lvds->full_name = kstrdup(name, GFP_KERNEL);
>> +
>> +       sprintf(name, "port@%u", port_id);
>> +       du_port->full_name = kstrdup(name, GFP_KERNEL);
>> +       du_port_fixup->full_name = kstrdup(name, GFP_KERNEL);
>> +
>> +       if (!lvds->full_name || !du_port->full_name ||
>> +           !du_port_fixup->full_name)
>> +               goto out_free_names;
>> +
>> +       /* Patch the target paths in all fragments. */
>> +       for_each_child_of_node(overlay.np, fragment) {
>> +               if (strncmp("fragment@", of_node_full_name(fragment), 9))
>> +                       continue;
>> +
>> +               ret = rcar_du_of_update_target_path(du, remote, fragment);
>> +               if (ret < 0) {
>> +                       of_node_put(fragment);
>> +                       goto out_free_properties;
>> +               }
>> +       }
>> +
>> +       /*
>> +        * Create a compatible string for the LVDS node using the SoC model
>> +        * from the DU node.
>> +        */
>> +       ret = of_property_read_string(du, "compatible", &compatible);
>> +       if (ret < 0)
>> +               goto out_free_properties;
>> +
>> +       soc_suffix = strchr(compatible, '-');
>> +       if (!soc_suffix || strlen(soc_suffix) > 10)
>> +               goto out_free_properties;
>> +
>> +       psize = sprintf(name, "renesas,%s-lvds", soc_suffix + 1) + 1;
>> +       ret = rcar_du_of_add_property(lvds, "compatible", name, psize);
>> +       if (ret < 0)
>> +               goto out_free_properties;
>> +
>> +       /* Copy the LVDS reg and clocks properties from the DU node. */
>> +       psize = (of_n_addr_cells(du) + of_n_size_cells(du)) * 4;
>> +       ret = rcar_du_of_add_property(lvds, "reg", reg, psize);
>> +       if (ret < 0)
>> +               goto out_free_properties;
>> +
>> +       if (clkspec->args_count >= ARRAY_SIZE(value) - 1)
>> +               goto out_free_properties;
>> +
>> +       value[0] = cpu_to_be32(clkspec->np->phandle);
>> +       for (i = 0; i < clkspec->args_count; ++i)
>> +               value[i + 1] = cpu_to_be32(clkspec->args[i]);
>> +
>> +       psize = (clkspec->args_count + 1) * 4;
>> +       ret = rcar_du_of_add_property(lvds, "clocks", value, psize);
>> +       if (ret < 0)
>> +               goto out_free_properties;
>> +
>> +       /*
>> +        * Insert the node in the OF graph: patch the LVDS ports remote-endpoint
>> +        * properties to point to the endpoints of the sibling nodes in the
>> +        * graph.
>> +        */
>> +       prop = of_find_property(lvds_endpoints[0], "remote-endpoint", NULL);
>> +       if (!prop)
>> +               goto out_free_properties;
>> +
>> +       *(__be32 *)prop->value = cpu_to_be32(local->phandle);
>> +
>> +       prop = of_find_property(lvds_endpoints[1], "remote-endpoint", NULL);
>> +       if (!prop)
>> +               goto out_free_properties;
>> +
>> +       *(__be32 *)prop->value = cpu_to_be32(remote->phandle);
>> +
>> +       /* Apply the overlay, this will resolve phandles. */
>> +       ovcs_id = 0;
>> +       ret = of_overlay_apply(overlay.np, &ovcs_id);
>> +
>> +       /* We're done, free all allocated memory. */
>> +out_free_properties:
>> +       rcar_du_of_free_properties(lvds);
>> +       rcar_du_of_free_properties(du_port);
>> +       rcar_du_of_free_properties(du_port_fixup);
>> +out_free_names:
>> +       kfree(lvds->full_name);
>> +       kfree(du_port->full_name);
>> +       kfree(du_port_fixup->full_name);
>> +out_put_nodes:
>> +       of_node_put(lvds);
>> +       of_node_put(lvds_endpoints[0]);
>> +       of_node_put(lvds_endpoints[1]);
>> +       of_node_put(du_port);
>> +       of_node_put(du_port_fixup);
>> +
>> +       rcar_du_of_free_overlay(&overlay);
>> +}
>> +
>> +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
>> +{
>> +       const struct rcar_du_device_info *info;
>> +       const struct of_device_id *match;
>> +       struct device_node *du;
>> +       unsigned int i;
>> +       int ret;
>> +
>> +       /* Get the DU node and exit if not present or disabled. */
>> +       du = of_find_matching_node_and_match(NULL, of_ids, &match);
>> +       if (!du || !of_device_is_available(du))
>> +               goto done;
>> +
>> +       info = match->data;
>> +
>> +       /* Patch every LVDS encoder. */
>> +       for (i = 0; i < info->num_lvds; ++i) {
>> +               struct of_phandle_args clkspec;
>> +               struct device_node *local, *remote;
>> +               struct resource res;
>> +               unsigned int port_id;
>> +               const __be32 *reg;
>> +               char name[7];
>> +               int index;
>> +
>> +               /*
>> +                * Retrieve the register specifier, the clock specifier and the
>> +                * local and remote endpoints of the LVDS link.
>> +                */
>> +               sprintf(name, "lvds.%u", i);
>> +               index = of_property_match_string(du, "reg-names", name);
>> +               if (index < 0)
>> +                       continue;
>> +
>> +               reg = of_get_address(du, index, NULL, NULL);
>> +               if (!reg)
>> +                       continue;
>> +
>> +               ret = of_address_to_resource(du, index, &res);
>> +               if (ret < 0)
>> +                       continue;
>> +
>> +               index = of_property_match_string(du, "clock-names", name);
>> +               if (index < 0)
>> +                       continue;
>> +
>> +               ret = of_parse_phandle_with_args(du, "clocks", "#clock-cells",
>> +                                                index, &clkspec);
>> +               if (ret < 0)
>> +                       continue;
>> +
>> +               port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
>> +
>> +               local = of_graph_get_endpoint_by_regs(du, port_id, 0);
>> +               if (!local) {
>> +                       of_node_put(clkspec.np);
>> +                       continue;
>> +               }
>> +
>> +               remote = of_graph_get_remote_endpoint(local);
>> +               if (!remote) {
>> +                       of_node_put(local);
>> +                       of_node_put(clkspec.np);
>> +                       continue;
>> +               }
>> +
>> +               /* Patch the LVDS encoder. */
>> +               rcar_du_of_lvds_patch_one(du, port_id, &res, reg, &clkspec,
>> +                                         local, remote);
>> +
>> +               of_node_put(clkspec.np);
>> +               of_node_put(remote);
>> +               of_node_put(local);
>> +       }
>> +
>> +done:
>> +       of_node_put(du);
>> +}
>> +#else
>> +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
>> +{
>> +}
>> +#endif /* CONFIG_DRM_RCAR_LVDS */
>> +
>> +void __init rcar_du_of_init(const struct of_device_id *of_ids)
>> +{
>> +       rcar_du_of_lvds_patch(of_ids);
>> +}
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h b/drivers/gpu/drm/rcar-du/rcar_du_of.h
>> new file mode 100644
>> index 000000000000..7105eaef58c6
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
>> @@ -0,0 +1,16 @@
>> +// SPDX-License-Identifier: GPL-2.0
> 
> The guidelines say headers should be C style. This is due to headers
> getting included by assembly code.
> 
>> +/*
>> + * rcar_du_of.h - Legacy DT bindings compatibility
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + */
>> +#ifndef __RCAR_DU_OF_H__
>> +#define __RCAR_DU_OF_H__
>> +
>> +#include <linux/init.h>
>> +
>> +struct of_device_id;
>> +
>> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
>> +
>> +#endif /* __RCAR_DU_OF_H__ */
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>> new file mode 100644
>> index 000000000000..bc75c7a1c3bd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>> @@ -0,0 +1,82 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds.dts - Legacy LVDS DT bindings conversion
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/*
>> + * The target-paths, lvds node name, DU port number and LVDS remote endpoints
>> + * will be patched dynamically at runtime.
>> + */
>> +
>> +/dts-v1/;
>> +/ {
>> +       fragment@0 {
>> +               target-path = "soc";
> 
> I don't really like this abuse of target-path that isn't really a
> valid path. I don't debate the need, but we just need a standard way
> to handle this.
> 
> Perhaps we need to allow target-path to be a string list. That gets
> back to my question on how many static combinations you have. I'd
> prefer duplication of overlays with simple applying code to coding a
> bunch of matching and fixups.
> 
>> +               __overlay__ {
>> +                       lvds {
>> +                               ports {
>> +                                       #address-cells = <1>;
>> +                                       #size-cells = <0>;
>> +
>> +                                       port@0 {
>> +                                               reg = <0>;
>> +                                               lvds_input: endpoint {
>> +                                                       remote-endpoint = <0>;
>> +                                               };
>> +                                       };
>> +
>> +                                       port@1 {
>> +                                               reg = <1>;
>> +                                               lvds_output: endpoint {
>> +                                                       remote-endpoint = <0>;
>> +                                               };
>> +                                       };
>> +                               };
>> +                       };
>> +               };
>> +       };
>> +
>> +       fragment@1 {
>> +               target-path = "du";
>> +               __overlay__ {
>> +                       ports {
>> +                               port@0 {
>> +                                       endpoint {
>> +                                               remote-endpoint = <&lvds_input>;
>> +                                       };
>> +                               };
>> +                       };
>> +               };
>> +       };
>> +
>> +       fragment@2 {
>> +               target-path = "lvds-sink";
>> +               __overlay__ {
>> +                       remote-endpoint = <&lvds_output>;
>> +               };
>> +       };
>> +
>> +       __local_fixups__ {
> 
> dtc generates this now.
> 
>> +               fragment@1 {
>> +                       __overlay__ {
>> +                               ports {
>> +                                       port@0 {
>> +                                               endpoint {
>> +                                                       remote-endpoint = <0>;
>> +                                               };
>> +                                       };
>> +                               };
>> +                       };
>> +               };
>> +               fragment@2 {
>> +                       __overlay__ {
>> +                               remote-endpoint = <0>;
>> +                       };
>> +               };
>> +       };
>> +};
>> --
>> Regards,
>>
>> Laurent Pinchart
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe devicetree" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> .
> 

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 19:12       ` Frank Rowand
@ 2018-01-15 19:22         ` Laurent Pinchart
  2018-01-15 20:12           ` Frank Rowand
  0 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-15 19:22 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	dri-devel, open list:MEDIA DRIVERS FOR RENESAS - FCP

Hi Frank,

On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
> On 01/15/18 09:09, Rob Herring wrote:
> > +Frank
> > 
> > On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> >> The internal LVDS encoders now have their own DT bindings. Before
> >> switching the driver infrastructure to those new bindings, implement
> >> backward-compatibility through live DT patching.
> > 
> > Uhh, we just got rid of TI's patching and now adding this one. I guess
> 
> Please no.  What we just got rid of was making it difficult for me to
> make changes to the overlay infrastructure.  There are issues with
> overlays that need to be fixed before overlays become really usable.
> I am about to propose the next change, which involves removing a
> chunk of code that I will not be able to remove if this patch is
> accepted (the proposal is awaiting me collecting some data about
> the impact of the change, which I expect to complete this week).
> 
> Can you please handle both the old and new bindings through driver
> code instead?

I could, but it would be pointless. The point here is to allow cleanups in the 
driver. The LVDS encoder handling code is very intrusive in its current form 
and I need to get rid of it. There would be zero point in moving to the new 
infrastructure, as the main point is to get rid of the old code which prevents 
moving forward. As a consequence that would block new boards from receiving 
proper upstream support. An easy option is to break backward compatibility. 
I'm personally fine with that, but I assume other people would complain :-)

I can, on the other hand, work with you to see how live DT patching could be 
implemented in this driver without blocking your code. When developing this 
patch series I start by patching the device tree manually without relying on 
overlays at all, but got blocked by the fact that I need to allocate phandles 
for new nodes I create. If there was an API to allocate an unused phandle I 
could avoid using the overlay infrastructure at all. Or there could be other 
options I'm not thinking of as I don't know what the changes you're working on 
are. Can we work on this together to find a solution that would suit us both ?

> > it's necessary, but I'd like to know how long we need to keep this?
> > 
> > How many overlays would you need if everything is static (i.e.
> > removing all your fixup code)?
> > 
> >> Patching is disabled and will be enabled along with support for the new
> >> DT bindings in the DU driver.
> >> 
> >> Signed-off-by: Laurent Pinchart
> >> <laurent.pinchart+renesas@ideasonboard.com>
> >> ---
> >> Changes since v1:
> >> 
> >> - Select OF_FLATTREE
> >> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> >> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> >> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> >> - Pass void begin and end pointers to rcar_du_of_get_overlay()
> >> - Use of_get_parent() instead of accessing the parent pointer directly
> >> - Find the LVDS endpoints nodes based on the LVDS node instead of the
> >>   root of the overlay
> >> - Update to the <soc>-lvds compatible string format
> >> ---
> >> 
> >>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
> >>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
> >>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
> >>  5 files changed, 553 insertions(+), 1 deletion(-)
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts

[snip]

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 19:22         ` Laurent Pinchart
@ 2018-01-15 20:12           ` Frank Rowand
       [not found]             ` <444f1b6b-fa57-da7c-08fd-51b28cdb5fff-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 38+ messages in thread
From: Frank Rowand @ 2018-01-15 20:12 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Rob Herring, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 01/15/18 11:22, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
>> On 01/15/18 09:09, Rob Herring wrote:
>>> +Frank
>>>
>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>>> The internal LVDS encoders now have their own DT bindings. Before
>>>> switching the driver infrastructure to those new bindings, implement
>>>> backward-compatibility through live DT patching.
>>>
>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>

Let me first answer the question that you ask later.  You ask "Can we work on
this together to find a solution that would suit us both ?"

My answer to that is emphatically YES.  I will definitely work with you to
try to find a good solution.


>> Please no.  What we just got rid of was making it difficult for me to
>> make changes to the overlay infrastructure.  There are issues with
>> overlays that need to be fixed before overlays become really usable.
>> I am about to propose the next change, which involves removing a
>> chunk of code that I will not be able to remove if this patch is
>> accepted (the proposal is awaiting me collecting some data about
>> the impact of the change, which I expect to complete this week).

I should have thought just a little bit more before I hit send.  The
situation is even worse than I wrote.  One of the next steps (in
addition to what I wrote about above) is to change the overlay apply
function to accept a flattened device tree (FDT), not an expanded
device tree.  In this changed model, the unflattened overlay is
not available to be modified before it is applied.

It is important for the devicetree infrastructure to have ownership
of the FDT that is used to create the unflattened tree.  (Notice
that in the proposed patch, rcar_du_of_get_overlay() follows the
TI example of doing a kmemdup of the blob (FDT), then uses the
copy for the unflatten.  The kmemdup() in this case is to create
a persistent copy of the FDT.)  The driver having ownership of
this copy, and having the ability to free it is one of the many
problems with the current overlay implementation.

>>
>> Can you please handle both the old and new bindings through driver
>> code instead?
> 
> I could, but it would be pointless. The point here is to allow cleanups in the 
> driver. The LVDS encoder handling code is very intrusive in its current form 
> and I need to get rid of it. There would be zero point in moving to the new 
> infrastructure, as the main point is to get rid of the old code which prevents 
> moving forward. As a consequence that would block new boards from receiving 
> proper upstream support. An easy option is to break backward compatibility. 
> I'm personally fine with that, but I assume other people would complain :-)
> 
> I can, on the other hand, work with you to see how live DT patching could be 
> implemented in this driver without blocking your code. When developing this 
> patch series I start by patching the device tree manually without relying on 
> overlays at all, but got blocked by the fact that I need to allocate phandles 
> for new nodes I create. If there was an API to allocate an unused phandle I 
> could avoid using the overlay infrastructure at all. Or there could be other 

It seems reasonable to provide a way to autogenerate a phandle (if requested)
by the devicetree code that creates a new node.  Were you using a function
from drivers/of/dynamic.c to create the node?


> options I'm not thinking of as I don't know what the changes you're working on 
> are. Can we work on this together to find a solution that would suit us both ?

Again, yes, I would be glad to work with you on this.

-Frank

> 
>>> it's necessary, but I'd like to know how long we need to keep this?
>>>
>>> How many overlays would you need if everything is static (i.e.
>>> removing all your fixup code)?
>>>
>>>> Patching is disabled and will be enabled along with support for the new
>>>> DT bindings in the DU driver.
>>>>
>>>> Signed-off-by: Laurent Pinchart
>>>> <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
>>>> ---
>>>> Changes since v1:
>>>>
>>>> - Select OF_FLATTREE
>>>> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
>>>> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
>>>> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
>>>> - Pass void begin and end pointers to rcar_du_of_get_overlay()
>>>> - Use of_get_parent() instead of accessing the parent pointer directly
>>>> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>>>>   root of the overlay
>>>> - Update to the <soc>-lvds compatible string format
>>>> ---
>>>>
>>>>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>>>>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>>>>  5 files changed, 553 insertions(+), 1 deletion(-)
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> 
> [snip]
> 

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

* Re: [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-12 23:14 ` [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver Laurent Pinchart
  2018-01-15  8:30   ` Geert Uytterhoeven
@ 2018-01-15 20:25   ` Sergei Shtylyov
  2018-01-15 20:32     ` Laurent Pinchart
  1 sibling, 1 reply; 38+ messages in thread
From: Sergei Shtylyov @ 2018-01-15 20:25 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc

Hello!

On 01/13/2018 02:14 AM, Laurent Pinchart wrote:

> The LVDS encoders used to be described in DT as part of the DU. They now
> have their own DT node, linked to the DU using the OF graph bindings.
> This allows moving internal LVDS encoder support to a separate driver
> modelled as a DRM bridge. Backward compatibility is retained as legacy
> DT is patched live to move to the new bindings.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
[...]
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 6e02c762a557..06a3fbdd728a 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
[...]
>   /* -----------------------------------------------------------------------------
> @@ -74,7 +75,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
>   			.port = 1,
>   		},
>   	},
> -	.num_lvds = 0,
>   };
>   
>   static const struct rcar_du_device_info rcar_du_r8a7779_info = {
> @@ -95,14 +95,13 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
>   			.port = 1,
>   		},
>   	},
> -	.num_lvds = 0,
>   };
>   
>   static const struct rcar_du_device_info rcar_du_r8a7790_info = {
>   	.gen = 2,
>   	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>   		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
> -	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
> +	.quirks = RCAR_DU_QUIRK_ALIGN_128B,
>   	.num_crtcs = 3,
>   	.routes = {
>   		/*
> @@ -164,7 +163,6 @@ static const struct rcar_du_device_info rcar_du_r8a7792_info = {
>   			.port = 1,
>   		},
>   	},
> -	.num_lvds = 0,
>   };
>   
>   static const struct rcar_du_device_info rcar_du_r8a7794_info = {
> @@ -186,7 +184,6 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = {
>   			.port = 1,
>   		},
>   	},
> -	.num_lvds = 0,

    I think you can remove *all* such initializers and the field itself with 
them -- otherwise it looks like you're doing a not-quite-related drive-by 
clean up...

[...]

MBR, Sergei
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found]             ` <444f1b6b-fa57-da7c-08fd-51b28cdb5fff-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2018-01-15 20:29               ` Laurent Pinchart
  2018-01-15 23:46                 ` Frank Rowand
  0 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-15 20:29 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Rob Herring, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Frank,

On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
> On 01/15/18 11:22, Laurent Pinchart wrote:
> > On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
> >> On 01/15/18 09:09, Rob Herring wrote:
> >>> +Frank
> >>> 
> >>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> >>>> The internal LVDS encoders now have their own DT bindings. Before
> >>>> switching the driver infrastructure to those new bindings, implement
> >>>> backward-compatibility through live DT patching.
> >>> 
> >>> Uhh, we just got rid of TI's patching and now adding this one. I guess
> 
> Let me first answer the question that you ask later.  You ask "Can we work
> on this together to find a solution that would suit us both ?"
> 
> My answer to that is emphatically YES.  I will definitely work with you to
> try to find a good solution.

\o/

> >> Please no.  What we just got rid of was making it difficult for me to
> >> make changes to the overlay infrastructure.  There are issues with
> >> overlays that need to be fixed before overlays become really usable.
> >> I am about to propose the next change, which involves removing a
> >> chunk of code that I will not be able to remove if this patch is
> >> accepted (the proposal is awaiting me collecting some data about
> >> the impact of the change, which I expect to complete this week).
> 
> I should have thought just a little bit more before I hit send.  The
> situation is even worse than I wrote.  One of the next steps (in
> addition to what I wrote about above) is to change the overlay apply
> function to accept a flattened device tree (FDT), not an expanded
> device tree.  In this changed model, the unflattened overlay is
> not available to be modified before it is applied.

That makes sense if we consider overlays to be immutable objects that we apply 
without offering a way to modify them. I won't challenge that API decision, as 
my use of an overlay here is a bit of a hack indeed.

> It is important for the devicetree infrastructure to have ownership
> of the FDT that is used to create the unflattened tree.  (Notice
> that in the proposed patch, rcar_du_of_get_overlay() follows the
> TI example of doing a kmemdup of the blob (FDT), then uses the
> copy for the unflatten.  The kmemdup() in this case is to create
> a persistent copy of the FDT.)  The driver having ownership of
> this copy, and having the ability to free it is one of the many
> problems with the current overlay implementation.

Yes, that's something I've identified as well. Lots of work has been done to 
clean up the OF core and we're clearly not done yet. I'm happy to see all the 
improvements you're working on.

> >> Can you please handle both the old and new bindings through driver
> >> code instead?
> > 
> > I could, but it would be pointless. The point here is to allow cleanups in
> > the driver. The LVDS encoder handling code is very intrusive in its
> > current form and I need to get rid of it. There would be zero point in
> > moving to the new infrastructure, as the main point is to get rid of the
> > old code which prevents moving forward. As a consequence that would block
> > new boards from receiving proper upstream support. An easy option is to
> > break backward compatibility. I'm personally fine with that, but I assume
> > other people would complain :-)
> > 
> > I can, on the other hand, work with you to see how live DT patching could
> > be implemented in this driver without blocking your code. When developing
> > this patch series I start by patching the device tree manually without
> > relying on overlays at all, but got blocked by the fact that I need to
> > allocate phandles for new nodes I create. If there was an API to allocate
> > an unused phandle I could avoid using the overlay infrastructure at all.
> > Or there could be other
> 
> It seems reasonable to provide a way to autogenerate a phandle (if
> requested) by the devicetree code that creates a new node.  Were you using
> a function from drivers/of/dynamic.c to create the node?

Not to allocate the node, no. I allocated the device_node structure manually 
with kzalloc(), and inserted it in the device tree with of_attach_node(). Is 
that the right approach ? I haven't been able to test the code as I stopped 
when I realized I couldn't allocate phandles.

> > options I'm not thinking of as I don't know what the changes you're
> > working on are. Can we work on this together to find a solution that
> > would suit us both ?
> 
> Again, yes, I would be glad to work with you on this.

How would you like to proceed ? I can try the manual approach again but need 
information about how I could cleanly implement phandle allocation. I will 
likely then run into other issues for which I might need help.

> >>> it's necessary, but I'd like to know how long we need to keep this?
> >>> 
> >>> How many overlays would you need if everything is static (i.e.
> >>> removing all your fixup code)?
> >>> 
> >>>> Patching is disabled and will be enabled along with support for the new
> >>>> DT bindings in the DU driver.
> >>>> 
> >>>> Signed-off-by: Laurent Pinchart
> >>>> <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> >>>> ---
> >>>> Changes since v1:
> >>>> 
> >>>> - Select OF_FLATTREE
> >>>> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> >>>> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> >>>> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> >>>> - Pass void begin and end pointers to rcar_du_of_get_overlay()
> >>>> - Use of_get_parent() instead of accessing the parent pointer directly
> >>>> - Find the LVDS endpoints nodes based on the LVDS node instead of the
> >>>> 
> >>>>   root of the overlay
> >>>> 
> >>>> - Update to the <soc>-lvds compatible string format
> >>>> ---
> >>>> 
> >>>>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
> >>>>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
> >>>>  5 files changed, 553 insertions(+), 1 deletion(-)
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > 
> > [snip]

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-15 20:25   ` Sergei Shtylyov
@ 2018-01-15 20:32     ` Laurent Pinchart
  2018-01-15 21:01       ` Sergei Shtylyov
  0 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-15 20:32 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel

Hi Sergei,

On Monday, 15 January 2018 22:25:16 EET Sergei Shtylyov wrote:
> On 01/13/2018 02:14 AM, Laurent Pinchart wrote:
> > The LVDS encoders used to be described in DT as part of the DU. They now
> > have their own DT node, linked to the DU using the OF graph bindings.
> > This allows moving internal LVDS encoder support to a separate driver
> > modelled as a DRM bridge. Backward compatibility is retained as legacy
> > DT is patched live to move to the new bindings.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> 
> [...]
> 
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 6e02c762a557..06a3fbdd728a
> > 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> 
> [...]
> 
> >   /* --------------------------------------------------------------------
> > @@ -74,7 +75,6 @@ static const struct rcar_du_device_info
> > rzg1_du_r8a7745_info = {
> >   			.port = 1,
 >   		},
> >   	},
> > -	.num_lvds = 0,
> >   };
> >   
> >   static const struct rcar_du_device_info rcar_du_r8a7779_info = {
> > @@ -95,14 +95,13 @@ static const struct rcar_du_device_info
> > rcar_du_r8a7779_info = {
> >   			.port = 1,
> >   		},
> >   	},
> > -	.num_lvds = 0,
> >   };
> >   
> >   static const struct rcar_du_device_info rcar_du_r8a7790_info = {
> >   	.gen = 2,
> >   	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
> >   		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
> > -	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
> > +	.quirks = RCAR_DU_QUIRK_ALIGN_128B,
> >   	.num_crtcs = 3,
> >   	.routes = {
> >   		/*
> > @@ -164,7 +163,6 @@ static const struct rcar_du_device_info
> > rcar_du_r8a7792_info = {
> >   			.port = 1,
> >   		},
> >   	},
> > -	.num_lvds = 0,
> >   };
> >   
> >   static const struct rcar_du_device_info rcar_du_r8a7794_info = {
> > @@ -186,7 +184,6 @@ static const struct rcar_du_device_info
> > rcar_du_r8a7794_info = {
> >   			.port = 1,
> >   		},
> >   	},
> > -	.num_lvds = 0,
> 
> I think you can remove *all* such initializers and the field itself with
> them -- otherwise it looks like you're doing a not-quite-related drive-by
> clean up...

The OF compatibility code uses the .num_lvds field, that's why I haven't 
removed it.

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-01-15 20:32     ` Laurent Pinchart
@ 2018-01-15 21:01       ` Sergei Shtylyov
  0 siblings, 0 replies; 38+ messages in thread
From: Sergei Shtylyov @ 2018-01-15 21:01 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: Laurent Pinchart, dri-devel, linux-renesas-soc

On 01/15/2018 11:32 PM, Laurent Pinchart wrote:

>>> The LVDS encoders used to be described in DT as part of the DU. They now
>>> have their own DT node, linked to the DU using the OF graph bindings.
>>> This allows moving internal LVDS encoder support to a separate driver
>>> modelled as a DRM bridge. Backward compatibility is retained as legacy
>>> DT is patched live to move to the new bindings.
>>>
>>> Signed-off-by: Laurent Pinchart
>>> <laurent.pinchart+renesas@ideasonboard.com>
>>
>> [...]
>>
>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>>> b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 6e02c762a557..06a3fbdd728a
>>> 100644
>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>>
>> [...]
>>
>>>    /* --------------------------------------------------------------------
>>> @@ -74,7 +75,6 @@ static const struct rcar_du_device_info
>>> rzg1_du_r8a7745_info = {
>>>    			.port = 1,
>   >   		},
>>>    	},
>>> -	.num_lvds = 0,
>>>    };
>>>    
>>>    static const struct rcar_du_device_info rcar_du_r8a7779_info = {
>>> @@ -95,14 +95,13 @@ static const struct rcar_du_device_info
>>> rcar_du_r8a7779_info = {
>>>    			.port = 1,
>>>    		},
>>>    	},
>>> -	.num_lvds = 0,
>>>    };
>>>    
>>>    static const struct rcar_du_device_info rcar_du_r8a7790_info = {
>>>    	.gen = 2,
>>>    	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>>>    		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
>>> -	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
>>> +	.quirks = RCAR_DU_QUIRK_ALIGN_128B,
>>>    	.num_crtcs = 3,
>>>    	.routes = {
>>>    		/*
>>> @@ -164,7 +163,6 @@ static const struct rcar_du_device_info
>>> rcar_du_r8a7792_info = {
>>>    			.port = 1,
>>>    		},
>>>    	},
>>> -	.num_lvds = 0,
>>>    };
>>>    
>>>    static const struct rcar_du_device_info rcar_du_r8a7794_info = {
>>> @@ -186,7 +184,6 @@ static const struct rcar_du_device_info
>>> rcar_du_r8a7794_info = {
>>>    			.port = 1,
>>>    		},
>>>    	},
>>> -	.num_lvds = 0,
>>
>> I think you can remove *all* such initializers and the field itself with
>> them -- otherwise it looks like you're doing a not-quite-related drive-by
>> clean up...
> 
> The OF compatibility code uses the .num_lvds field, that's why I haven't
> removed it.

    Ah, I haven't yet reviewed that patch! But then I would leave the 
initializers alone...

MBR, Sergei

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 20:29               ` Laurent Pinchart
@ 2018-01-15 23:46                 ` Frank Rowand
  2018-01-15 23:57                   ` Frank Rowand
  2018-01-16 14:35                   ` Rob Herring
  0 siblings, 2 replies; 38+ messages in thread
From: Frank Rowand @ 2018-01-15 23:46 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Rob Herring, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 01/15/18 12:29, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
>> On 01/15/18 11:22, Laurent Pinchart wrote:
>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
>>>> On 01/15/18 09:09, Rob Herring wrote:
>>>>> +Frank
>>>>>
>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>>>>> The internal LVDS encoders now have their own DT bindings. Before
>>>>>> switching the driver infrastructure to those new bindings, implement
>>>>>> backward-compatibility through live DT patching.
>>>>>
>>>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>
>> Let me first answer the question that you ask later.  You ask "Can we work
>> on this together to find a solution that would suit us both ?"
>>
>> My answer to that is emphatically YES.  I will definitely work with you to
>> try to find a good solution.
> 
> \o/
> 
>>>> Please no.  What we just got rid of was making it difficult for me to
>>>> make changes to the overlay infrastructure.  There are issues with
>>>> overlays that need to be fixed before overlays become really usable.
>>>> I am about to propose the next change, which involves removing a
>>>> chunk of code that I will not be able to remove if this patch is
>>>> accepted (the proposal is awaiting me collecting some data about
>>>> the impact of the change, which I expect to complete this week).
>>
>> I should have thought just a little bit more before I hit send.  The
>> situation is even worse than I wrote.  One of the next steps (in
>> addition to what I wrote about above) is to change the overlay apply
>> function to accept a flattened device tree (FDT), not an expanded
>> device tree.  In this changed model, the unflattened overlay is
>> not available to be modified before it is applied.
> 
> That makes sense if we consider overlays to be immutable objects that we apply 
> without offering a way to modify them. I won't challenge that API decision, as 
> my use of an overlay here is a bit of a hack indeed.
> 
>> It is important for the devicetree infrastructure to have ownership
>> of the FDT that is used to create the unflattened tree.  (Notice
>> that in the proposed patch, rcar_du_of_get_overlay() follows the
>> TI example of doing a kmemdup of the blob (FDT), then uses the
>> copy for the unflatten.  The kmemdup() in this case is to create
>> a persistent copy of the FDT.)  The driver having ownership of
>> this copy, and having the ability to free it is one of the many
>> problems with the current overlay implementation.
> 
> Yes, that's something I've identified as well. Lots of work has been done to 
> clean up the OF core and we're clearly not done yet. I'm happy to see all the 
> improvements you're working on.
> 
>>>> Can you please handle both the old and new bindings through driver
>>>> code instead?
>>>
>>> I could, but it would be pointless. The point here is to allow cleanups in
>>> the driver. The LVDS encoder handling code is very intrusive in its
>>> current form and I need to get rid of it. There would be zero point in
>>> moving to the new infrastructure, as the main point is to get rid of the
>>> old code which prevents moving forward. As a consequence that would block
>>> new boards from receiving proper upstream support. An easy option is to
>>> break backward compatibility. I'm personally fine with that, but I assume
>>> other people would complain :-)
>>>
>>> I can, on the other hand, work with you to see how live DT patching could
>>> be implemented in this driver without blocking your code. When developing
>>> this patch series I start by patching the device tree manually without
>>> relying on overlays at all, but got blocked by the fact that I need to
>>> allocate phandles for new nodes I create. If there was an API to allocate
>>> an unused phandle I could avoid using the overlay infrastructure at all.
>>> Or there could be other
>>
>> It seems reasonable to provide a way to autogenerate a phandle (if
>> requested) by the devicetree code that creates a new node.  Were you using
>> a function from drivers/of/dynamic.c to create the node?
> 
> Not to allocate the node, no. I allocated the device_node structure manually 
> with kzalloc(), and inserted it in the device tree with of_attach_node(). Is 
> that the right approach ? I haven't been able to test the code as I stopped 
> when I realized I couldn't allocate phandles.
> 
>>> options I'm not thinking of as I don't know what the changes you're
>>> working on are. Can we work on this together to find a solution that
>>> would suit us both ?
>>
>> Again, yes, I would be glad to work with you on this.
> 
> How would you like to proceed ? I can try the manual approach again but need 
> information about how I could cleanly implement phandle allocation. I will 
> likely then run into other issues for which I might need help.

Here are my first thoughts, based on 4.15-rc7:

Question to Rob and Frank: should of_attach_node() be called directly, or
should it be called indirectly by creating a change set that adds the node?

Frank's off the cuff answer (but would like to think more about it): since
the driver is modifying its own devicetree data, and thus no other entity
needs to be notified about the changes, there is no need to add the complexity
of using a change set.

The following is how of_attach_node() could be modified to dynamically create
a phandle on request.


of_attach_node()

   Add parameter: int create_phandle

   of_attach_node(): pass create_phandle to __of_attach_node().

   Modify existing callers of of_attach_node(): use value of 0 (zero)
   for create_phandle.

   rcar caller of of_attach_node(): use value of 1 for create_phandle.


__of_attach_node()

   Add parameter: int create_phandle

   if (create_phandle)
      - protect creating value of new phandle and inserting the node with 
        of_overlay_mutex_lock() / of_overlay_mutex_unlock()
      - if phandle does not exist, then phandle = live_tree_max_phandle() + 1

   Notice that there will not actually be a phandle property created for the
   node.  Instead the phandle value will only exist in the struct device_node.
   We are trying to move in this direction for all phandles, but have not yet
   gotten there.

   Modify existing callers of __of_attach_node(): use value of 0 (zero)
   for create_phandle.

   (If a change set is used to add the node instead of calling
   of_attach_node(), then the change set code would have to be modified to
   expose the create_phandle parameter to of_changeset_attach_node() and
   related code.)

-Frank

> 
>>>>> it's necessary, but I'd like to know how long we need to keep this?
>>>>>
>>>>> How many overlays would you need if everything is static (i.e.
>>>>> removing all your fixup code)?
>>>>>
>>>>>> Patching is disabled and will be enabled along with support for the new
>>>>>> DT bindings in the DU driver.
>>>>>>
>>>>>> Signed-off-by: Laurent Pinchart
>>>>>> <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
>>>>>> ---
>>>>>> Changes since v1:
>>>>>>
>>>>>> - Select OF_FLATTREE
>>>>>> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
>>>>>> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
>>>>>> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
>>>>>> - Pass void begin and end pointers to rcar_du_of_get_overlay()
>>>>>> - Use of_get_parent() instead of accessing the parent pointer directly
>>>>>> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>>>>>>
>>>>>>   root of the overlay
>>>>>>
>>>>>> - Update to the <soc>-lvds compatible string format
>>>>>> ---
>>>>>>
>>>>>>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>>>>>>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>>>>>>  5 files changed, 553 insertions(+), 1 deletion(-)
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>>>
>>> [snip]
> 

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 23:46                 ` Frank Rowand
@ 2018-01-15 23:57                   ` Frank Rowand
  2018-01-16 14:35                   ` Rob Herring
  1 sibling, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-01-15 23:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Rob Herring, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On 01/15/18 15:46, Frank Rowand wrote:
> On 01/15/18 12:29, Laurent Pinchart wrote:
>> Hi Frank,
>>
>> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
>>> On 01/15/18 11:22, Laurent Pinchart wrote:
>>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
>>>>> On 01/15/18 09:09, Rob Herring wrote:
>>>>>> +Frank
>>>>>>
>>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>>>>>> The internal LVDS encoders now have their own DT bindings. Before
>>>>>>> switching the driver infrastructure to those new bindings, implement
>>>>>>> backward-compatibility through live DT patching.
>>>>>>
>>>>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>>
>>> Let me first answer the question that you ask later.  You ask "Can we work
>>> on this together to find a solution that would suit us both ?"
>>>
>>> My answer to that is emphatically YES.  I will definitely work with you to
>>> try to find a good solution.
>>
>> \o/
>>
>>>>> Please no.  What we just got rid of was making it difficult for me to
>>>>> make changes to the overlay infrastructure.  There are issues with
>>>>> overlays that need to be fixed before overlays become really usable.
>>>>> I am about to propose the next change, which involves removing a
>>>>> chunk of code that I will not be able to remove if this patch is
>>>>> accepted (the proposal is awaiting me collecting some data about
>>>>> the impact of the change, which I expect to complete this week).
>>>
>>> I should have thought just a little bit more before I hit send.  The
>>> situation is even worse than I wrote.  One of the next steps (in
>>> addition to what I wrote about above) is to change the overlay apply
>>> function to accept a flattened device tree (FDT), not an expanded
>>> device tree.  In this changed model, the unflattened overlay is
>>> not available to be modified before it is applied.
>>
>> That makes sense if we consider overlays to be immutable objects that we apply 
>> without offering a way to modify them. I won't challenge that API decision, as 
>> my use of an overlay here is a bit of a hack indeed.
>>
>>> It is important for the devicetree infrastructure to have ownership
>>> of the FDT that is used to create the unflattened tree.  (Notice
>>> that in the proposed patch, rcar_du_of_get_overlay() follows the
>>> TI example of doing a kmemdup of the blob (FDT), then uses the
>>> copy for the unflatten.  The kmemdup() in this case is to create
>>> a persistent copy of the FDT.)  The driver having ownership of
>>> this copy, and having the ability to free it is one of the many
>>> problems with the current overlay implementation.
>>
>> Yes, that's something I've identified as well. Lots of work has been done to 
>> clean up the OF core and we're clearly not done yet. I'm happy to see all the 
>> improvements you're working on.
>>
>>>>> Can you please handle both the old and new bindings through driver
>>>>> code instead?
>>>>
>>>> I could, but it would be pointless. The point here is to allow cleanups in
>>>> the driver. The LVDS encoder handling code is very intrusive in its
>>>> current form and I need to get rid of it. There would be zero point in
>>>> moving to the new infrastructure, as the main point is to get rid of the
>>>> old code which prevents moving forward. As a consequence that would block
>>>> new boards from receiving proper upstream support. An easy option is to
>>>> break backward compatibility. I'm personally fine with that, but I assume
>>>> other people would complain :-)
>>>>
>>>> I can, on the other hand, work with you to see how live DT patching could
>>>> be implemented in this driver without blocking your code. When developing
>>>> this patch series I start by patching the device tree manually without
>>>> relying on overlays at all, but got blocked by the fact that I need to
>>>> allocate phandles for new nodes I create. If there was an API to allocate
>>>> an unused phandle I could avoid using the overlay infrastructure at all.
>>>> Or there could be other
>>>
>>> It seems reasonable to provide a way to autogenerate a phandle (if
>>> requested) by the devicetree code that creates a new node.  Were you using
>>> a function from drivers/of/dynamic.c to create the node?
>>
>> Not to allocate the node, no. I allocated the device_node structure manually 
>> with kzalloc(), and inserted it in the device tree with of_attach_node(). Is 
>> that the right approach ? I haven't been able to test the code as I stopped 
>> when I realized I couldn't allocate phandles.
>>
>>>> options I'm not thinking of as I don't know what the changes you're
>>>> working on are. Can we work on this together to find a solution that
>>>> would suit us both ?
>>>
>>> Again, yes, I would be glad to work with you on this.
>>
>> How would you like to proceed ? I can try the manual approach again but need 
>> information about how I could cleanly implement phandle allocation. I will 
>> likely then run into other issues for which I might need help.
> 
> Here are my first thoughts, based on 4.15-rc7:
> 
> Question to Rob and Frank: should of_attach_node() be called directly, or
> should it be called indirectly by creating a change set that adds the node?
> 
> Frank's off the cuff answer (but would like to think more about it): since
> the driver is modifying its own devicetree data, and thus no other entity
> needs to be notified about the changes, there is no need to add the complexity
> of using a change set.
> 
> The following is how of_attach_node() could be modified to dynamically create
> a phandle on request.
> 
> 
> of_attach_node()
> 
>    Add parameter: int create_phandle
> 
>    of_attach_node(): pass create_phandle to __of_attach_node().
> 
>    Modify existing callers of of_attach_node(): use value of 0 (zero)
>    for create_phandle.
> 
>    rcar caller of of_attach_node(): use value of 1 for create_phandle.
> 
> 
> __of_attach_node()
> 
>    Add parameter: int create_phandle
> 
>    if (create_phandle)
>       - protect creating value of new phandle and inserting the node with 
>         of_overlay_mutex_lock() / of_overlay_mutex_unlock()
>       - if phandle does not exist, then phandle = live_tree_max_phandle() + 1
> 
>    Notice that there will not actually be a phandle property created for the
>    node.  Instead the phandle value will only exist in the struct device_node.
>    We are trying to move in this direction for all phandles, but have not yet
>    gotten there.
> 
>    Modify existing callers of __of_attach_node(): use value of 0 (zero)
>    for create_phandle.
> 
>    (If a change set is used to add the node instead of calling
>    of_attach_node(), then the change set code would have to be modified to
>    expose the create_phandle parameter to of_changeset_attach_node() and
>    related code.)

One side effect of using of_attach_node() is that the caller of of_attach_node()
has created the node's struct device_node (and any other memory pointed to from
that struct), of __of_attach_node() grafts that device_node into the live tree.

So this is something that we will need to clean up long term within the
devicetree infrastructure code.  That data needs to be replicated in memory
that the devicetree infrastructure controls so that the driver can not
inadvertently free the memory.


> 
> -Frank
> 
>>
>>>>>> it's necessary, but I'd like to know how long we need to keep this?
>>>>>>
>>>>>> How many overlays would you need if everything is static (i.e.
>>>>>> removing all your fixup code)?
>>>>>>
>>>>>>> Patching is disabled and will be enabled along with support for the new
>>>>>>> DT bindings in the DU driver.
>>>>>>>
>>>>>>> Signed-off-by: Laurent Pinchart
>>>>>>> <laurent.pinchart+renesas@ideasonboard.com>
>>>>>>> ---
>>>>>>> Changes since v1:
>>>>>>>
>>>>>>> - Select OF_FLATTREE
>>>>>>> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
>>>>>>> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
>>>>>>> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
>>>>>>> - Pass void begin and end pointers to rcar_du_of_get_overlay()
>>>>>>> - Use of_get_parent() instead of accessing the parent pointer directly
>>>>>>> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>>>>>>>
>>>>>>>   root of the overlay
>>>>>>>
>>>>>>> - Update to the <soc>-lvds compatible string format
>>>>>>> ---
>>>>>>>
>>>>>>>  drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>>>>>>>  drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++
>>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>>>>>>>  5 files changed, 553 insertions(+), 1 deletion(-)
>>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
>>>>
>>>> [snip]
>>
> 
> 

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 18:01       ` Laurent Pinchart
@ 2018-01-16  8:56         ` Geert Uytterhoeven
       [not found]           ` <CAMuHMdUNcKOod1KCAGSBeMr52PWKqkJo0AWmSNk76t0=Zvu0gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2018-01-16 15:08           ` Rob Herring
  0 siblings, 2 replies; 38+ messages in thread
From: Geert Uytterhoeven @ 2018-01-16  8:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Rob Herring, Laurent Pinchart, Frank Rowand, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Laurent,

On Mon, Jan 15, 2018 at 7:01 PM, Laurent Pinchart
<laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> wrote:
> On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>> > The internal LVDS encoders now have their own DT bindings. Before
>> > switching the driver infrastructure to those new bindings, implement
>> > backward-compatibility through live DT patching.
>>
>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>> it's necessary, but I'd like to know how long we need to keep this?
>
> That's a good question. How long are we supposed to keep DT backward
> compatibility for ? I don't think there's a one-size-fits-them-all answer to
> this question. Geert, any opinion ? How long do you plan to keep the CPG
> (clocks) DT backward compatibility for instance ?

Good question indeed...

It's not just CPG/MSSR. Over the years we also added or changed APMU (SMP),
SYSC (power domains), RST (mode pins), CMT (timers), ..., all of which have
some sort of compatibility support in the kernel.

Hence to avoid having to remember the kernel versions that dropped backwards
compatibility for each of the above components, I was thinking about an
R-Car Gen2 DT Flag Day.

However, that was before I learned about your plans for LVDS (it seems every
kernel release we learn about something new, postponing the flag day ;-).
And now I'm quite sure we'll have another change in the future (DU per
channel device nodes)...

About using DT fixups to implement backwards compatibility: I did my share
of thinking and experimenting with DT fixups (see e.g. "[PATCH/RFC 0/1]
soc: renesas: Add DT fixup code for backwards compatibility"
(https://www.spinics.net/lists/linux-renesas-soc/msg04305.html).
DT fixups are hard to implement right, and not everything can be done
that way.  Hence in the end, none of this was ever used upstream, and
everything was handled in C...

So I'm wondering if it would be easier if you would implement backwards
compatibility in C, using different compatible values for the new bindings?
I.e. switch from "renesas,du-r8a77*" to "renesas,r8a77*-du" +
"renesas,r8a77*-lvds"?
That way it also becomes very clear that there are old and new bindings,
and that there is backwards compatibility code for the old binding.

I know you're aware (the rest of the audience may not be) that the LVDS
part is not the only separate hardware block current unified in the single
DU node: each DU channel has its own hardware block.  Perhaps you can also
bite the bullet and have a single device node per DT channel, allowing
Runtime PM for DU channels?
Of course you have to tie channels together using a "companion" (cfr. USB)
or "renesas,bonding" (cfr. DRIF) property (unfortunately I learned about
the former only after the latter was already established).

Finally, implementing backwards compatibility support by DT fixup using
overlays may complicate backporting to LTSI kernels, due to the dependency
on DT overlays, which were reworked lately.

>> > --- a/drivers/gpu/drm/rcar-du/Kconfig
>> > +++ b/drivers/gpu/drm/rcar-du/Kconfig
>> > @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
>> >         bool "R-Car DU LVDS Encoder Support"
>> >         depends on DRM_RCAR_DU
>> >         select DRM_PANEL
>> > +       select OF_FLATTREE
>> > +       select OF_OVERLAY
>>
>> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
>> could have an overlay from a non-FDT source...

Currently the select is needed for of_fdt_unflatten_tree() only, which is
not used by the core OF_OVERLAY code. So you could build an overlay in
memory yourself, and pass that, without using of_fdt_unflatten_tree().
But that is going to change if I read Frank's reponse well?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
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] 38+ messages in thread

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found]           ` <CAMuHMdUNcKOod1KCAGSBeMr52PWKqkJo0AWmSNk76t0=Zvu0gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2018-01-16 10:23             ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-16 10:23 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Rob Herring, Laurent Pinchart, Frank Rowand, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Geert,

On Tuesday, 16 January 2018 10:56:10 EET Geert Uytterhoeven wrote:
> On Mon, Jan 15, 2018 at 7:01 PM, Laurent Pinchart wrote:
> > On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
> >> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> >>> The internal LVDS encoders now have their own DT bindings. Before
> >>> switching the driver infrastructure to those new bindings, implement
> >>> backward-compatibility through live DT patching.
> >> 
> >> Uhh, we just got rid of TI's patching and now adding this one. I guess
> >> it's necessary, but I'd like to know how long we need to keep this?
> > 
> > That's a good question. How long are we supposed to keep DT backward
> > compatibility for ? I don't think there's a one-size-fits-them-all answer
> > to this question. Geert, any opinion ? How long do you plan to keep the
> > CPG (clocks) DT backward compatibility for instance ?
> 
> Good question indeed...
> 
> It's not just CPG/MSSR. Over the years we also added or changed APMU (SMP),
> SYSC (power domains), RST (mode pins), CMT (timers), ..., all of which have
> some sort of compatibility support in the kernel.
> 
> Hence to avoid having to remember the kernel versions that dropped backwards
> compatibility for each of the above components, I was thinking about an
> R-Car Gen2 DT Flag Day.
> 
> However, that was before I learned about your plans for LVDS (it seems every
> kernel release we learn about something new, postponing the flag day ;-).
> And now I'm quite sure we'll have another change in the future (DU per
> channel device nodes)...

I don't think the DU and LVDS rework should postpone your flag day for all the 
core components.

> About using DT fixups to implement backwards compatibility: I did my share
> of thinking and experimenting with DT fixups (see e.g. "[PATCH/RFC 0/1]
> soc: renesas: Add DT fixup code for backwards compatibility"
> (https://www.spinics.net/lists/linux-renesas-soc/msg04305.html).
> DT fixups are hard to implement right, and not everything can be done
> that way.  Hence in the end, none of this was ever used upstream, and
> everything was handled in C...
> 
> So I'm wondering if it would be easier if you would implement backwards
> compatibility in C, using different compatible values for the new bindings?
> I.e. switch from "renesas,du-r8a77*" to "renesas,r8a77*-du" +
> "renesas,r8a77*-lvds"?
> That way it also becomes very clear that there are old and new bindings,
> and that there is backwards compatibility code for the old binding.

Quoting my reply to Frank,

I could, but it would be pointless. The point here is to allow cleanups in the 
driver. The LVDS encoder handling code is very intrusive in its current form 
and I need to get rid of it. There would be zero point in moving to the new 
infrastructure, as the main point is to get rid of the old code which prevents 
moving forward. As a consequence that would block new boards from receiving 
proper upstream support. An easy option is to break backward compatibility. 
I'm personally fine with that, but I assume other people would complain :-)

> I know you're aware (the rest of the audience may not be) that the LVDS
> part is not the only separate hardware block current unified in the single
> DU node: each DU channel has its own hardware block.  Perhaps you can also
> bite the bullet and have a single device node per DT channel, allowing
> Runtime PM for DU channels?

That's more difficult as the channels have cross-dependencies. I might give it 
a try at some point, or I might not. In any case it's a separate piece of 
work, and backward compatibility for that one might be handled in the driver 
instead of through DT patching.

> Of course you have to tie channels together using a "companion" (cfr. USB)
> or "renesas,bonding" (cfr. DRIF) property (unfortunately I learned about
> the former only after the latter was already established).
> 
> Finally, implementing backwards compatibility support by DT fixup using
> overlays may complicate backporting to LTSI kernels, due to the dependency
> on DT overlays, which were reworked lately.

I can drop backward compatibility completely if you prefer, that would be much 
easier to backport ;-)

As discussed with Frank I will likely try to patch the DT live without using 
overlays, but that will likely also be annoying to backport as the ongoing 
modifications to the OF core are not limited to overlays anyway.

> >>> --- a/drivers/gpu/drm/rcar-du/Kconfig
> >>> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> >>> @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
> >>>         bool "R-Car DU LVDS Encoder Support"
> >>>         depends on DRM_RCAR_DU
> >>>         select DRM_PANEL
> >>> +       select OF_FLATTREE
> >>> +       select OF_OVERLAY
> >> 
> >> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
> >> could have an overlay from a non-FDT source...
> 
> Currently the select is needed for of_fdt_unflatten_tree() only, which is
> not used by the core OF_OVERLAY code. So you could build an overlay in
> memory yourself, and pass that, without using of_fdt_unflatten_tree().
> But that is going to change if I read Frank's reponse well?

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-15 23:46                 ` Frank Rowand
  2018-01-15 23:57                   ` Frank Rowand
@ 2018-01-16 14:35                   ` Rob Herring
       [not found]                     ` <CAL_JsqKD_VKMrfi42hZ3eHPAMWBwryV0g_cXDUeyaKfPP99LmA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 38+ messages in thread
From: Rob Herring @ 2018-01-16 14:35 UTC (permalink / raw)
  To: Frank Rowand
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Laurent Pinchart, Sergei Shtylyov, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Laurent Pinchart

On Mon, Jan 15, 2018 at 5:46 PM, Frank Rowand <frowand.list@gmail.com> wrote:
> On 01/15/18 12:29, Laurent Pinchart wrote:
>> Hi Frank,
>>
>> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
>>> On 01/15/18 11:22, Laurent Pinchart wrote:
>>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
>>>>> On 01/15/18 09:09, Rob Herring wrote:
>>>>>> +Frank
>>>>>>
>>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>>>>>> The internal LVDS encoders now have their own DT bindings. Before
>>>>>>> switching the driver infrastructure to those new bindings, implement
>>>>>>> backward-compatibility through live DT patching.
>>>>>>
>>>>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>>
>>> Let me first answer the question that you ask later.  You ask "Can we work
>>> on this together to find a solution that would suit us both ?"
>>>
>>> My answer to that is emphatically YES.  I will definitely work with you to
>>> try to find a good solution.
>>
>> \o/
>>
>>>>> Please no.  What we just got rid of was making it difficult for me to
>>>>> make changes to the overlay infrastructure.  There are issues with
>>>>> overlays that need to be fixed before overlays become really usable.
>>>>> I am about to propose the next change, which involves removing a
>>>>> chunk of code that I will not be able to remove if this patch is
>>>>> accepted (the proposal is awaiting me collecting some data about
>>>>> the impact of the change, which I expect to complete this week).
>>>
>>> I should have thought just a little bit more before I hit send.  The
>>> situation is even worse than I wrote.  One of the next steps (in
>>> addition to what I wrote about above) is to change the overlay apply
>>> function to accept a flattened device tree (FDT), not an expanded
>>> device tree.  In this changed model, the unflattened overlay is
>>> not available to be modified before it is applied.
>>
>> That makes sense if we consider overlays to be immutable objects that we apply
>> without offering a way to modify them. I won't challenge that API decision, as
>> my use of an overlay here is a bit of a hack indeed.
>>
>>> It is important for the devicetree infrastructure to have ownership
>>> of the FDT that is used to create the unflattened tree.  (Notice
>>> that in the proposed patch, rcar_du_of_get_overlay() follows the
>>> TI example of doing a kmemdup of the blob (FDT), then uses the
>>> copy for the unflatten.  The kmemdup() in this case is to create
>>> a persistent copy of the FDT.)  The driver having ownership of
>>> this copy, and having the ability to free it is one of the many
>>> problems with the current overlay implementation.
>>
>> Yes, that's something I've identified as well. Lots of work has been done to
>> clean up the OF core and we're clearly not done yet. I'm happy to see all the
>> improvements you're working on.
>>
>>>>> Can you please handle both the old and new bindings through driver
>>>>> code instead?
>>>>
>>>> I could, but it would be pointless. The point here is to allow cleanups in
>>>> the driver. The LVDS encoder handling code is very intrusive in its
>>>> current form and I need to get rid of it. There would be zero point in
>>>> moving to the new infrastructure, as the main point is to get rid of the
>>>> old code which prevents moving forward. As a consequence that would block
>>>> new boards from receiving proper upstream support. An easy option is to
>>>> break backward compatibility. I'm personally fine with that, but I assume
>>>> other people would complain :-)
>>>>
>>>> I can, on the other hand, work with you to see how live DT patching could
>>>> be implemented in this driver without blocking your code. When developing
>>>> this patch series I start by patching the device tree manually without
>>>> relying on overlays at all, but got blocked by the fact that I need to
>>>> allocate phandles for new nodes I create. If there was an API to allocate
>>>> an unused phandle I could avoid using the overlay infrastructure at all.
>>>> Or there could be other
>>>
>>> It seems reasonable to provide a way to autogenerate a phandle (if
>>> requested) by the devicetree code that creates a new node.  Were you using
>>> a function from drivers/of/dynamic.c to create the node?
>>
>> Not to allocate the node, no. I allocated the device_node structure manually
>> with kzalloc(), and inserted it in the device tree with of_attach_node(). Is
>> that the right approach ? I haven't been able to test the code as I stopped
>> when I realized I couldn't allocate phandles.
>>
>>>> options I'm not thinking of as I don't know what the changes you're
>>>> working on are. Can we work on this together to find a solution that
>>>> would suit us both ?
>>>
>>> Again, yes, I would be glad to work with you on this.
>>
>> How would you like to proceed ? I can try the manual approach again but need
>> information about how I could cleanly implement phandle allocation. I will
>> likely then run into other issues for which I might need help.
>
> Here are my first thoughts, based on 4.15-rc7:
>
> Question to Rob and Frank: should of_attach_node() be called directly, or
> should it be called indirectly by creating a change set that adds the node?
>
> Frank's off the cuff answer (but would like to think more about it): since
> the driver is modifying its own devicetree data, and thus no other entity
> needs to be notified about the changes, there is no need to add the complexity
> of using a change set.

There's exactly 2 users outside of the DT core. That's generally a
sign of an API I'd like to make private.

> The following is how of_attach_node() could be modified to dynamically create
> a phandle on request.

How would this work for all the phandle references that need to be fixed up?

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

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-16  8:56         ` Geert Uytterhoeven
       [not found]           ` <CAMuHMdUNcKOod1KCAGSBeMr52PWKqkJo0AWmSNk76t0=Zvu0gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2018-01-16 15:08           ` Rob Herring
       [not found]             ` <CAL_JsqJuzXgx-ntbHdYiabi7DUyT8y0Vxj-c5KBmf+Gk+EWtMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 38+ messages in thread
From: Rob Herring @ 2018-01-16 15:08 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Laurent Pinchart, Laurent Pinchart, Frank Rowand, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

On Tue, Jan 16, 2018 at 2:56 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Laurent,
>
> On Mon, Jan 15, 2018 at 7:01 PM, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
>> On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>> > The internal LVDS encoders now have their own DT bindings. Before
>>> > switching the driver infrastructure to those new bindings, implement
>>> > backward-compatibility through live DT patching.
>>>
>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>> it's necessary, but I'd like to know how long we need to keep this?
>>
>> That's a good question. How long are we supposed to keep DT backward
>> compatibility for ? I don't think there's a one-size-fits-them-all answer to
>> this question. Geert, any opinion ? How long do you plan to keep the CPG
>> (clocks) DT backward compatibility for instance ?
>
> Good question indeed...
>
> It's not just CPG/MSSR. Over the years we also added or changed APMU (SMP),
> SYSC (power domains), RST (mode pins), CMT (timers), ..., all of which have
> some sort of compatibility support in the kernel.
>
> Hence to avoid having to remember the kernel versions that dropped backwards
> compatibility for each of the above components, I was thinking about an
> R-Car Gen2 DT Flag Day.

There's probably also DT changes that enable new features folks would
want/need? Or maybe carrying for some number of LTS releases is
enough.

> However, that was before I learned about your plans for LVDS (it seems every
> kernel release we learn about something new, postponing the flag day ;-).
> And now I'm quite sure we'll have another change in the future (DU per
> channel device nodes)...
>
> About using DT fixups to implement backwards compatibility: I did my share
> of thinking and experimenting with DT fixups (see e.g. "[PATCH/RFC 0/1]
> soc: renesas: Add DT fixup code for backwards compatibility"
> (https://www.spinics.net/lists/linux-renesas-soc/msg04305.html).
> DT fixups are hard to implement right, and not everything can be done
> that way.  Hence in the end, none of this was ever used upstream, and
> everything was handled in C...

In an ideal world, we would have some tool:

dt-diff-to-overlay old.dts new.dts > my-fixup-overlay.dts

And then in the kernel have infrastructure such you just declare match
tables with overlays to apply:

struct of_device_id dt_match[] = {
  {
    .compatible = "vendor,board",
  },
  {},
};
DT_FIXUP(dt_match, my-fixup-overlay.dtbo);

But maybe I'm dreaming...

> So I'm wondering if it would be easier if you would implement backwards
> compatibility in C, using different compatible values for the new bindings?
> I.e. switch from "renesas,du-r8a77*" to "renesas,r8a77*-du" +
> "renesas,r8a77*-lvds"?
> That way it also becomes very clear that there are old and new bindings,
> and that there is backwards compatibility code for the old binding.
>
> I know you're aware (the rest of the audience may not be) that the LVDS
> part is not the only separate hardware block current unified in the single
> DU node: each DU channel has its own hardware block.  Perhaps you can also
> bite the bullet and have a single device node per DT channel, allowing
> Runtime PM for DU channels?
> Of course you have to tie channels together using a "companion" (cfr. USB)
> or "renesas,bonding" (cfr. DRIF) property (unfortunately I learned about
> the former only after the latter was already established).
>
> Finally, implementing backwards compatibility support by DT fixup using
> overlays may complicate backporting to LTSI kernels, due to the dependency
> on DT overlays, which were reworked lately.
>
>>> > --- a/drivers/gpu/drm/rcar-du/Kconfig
>>> > +++ b/drivers/gpu/drm/rcar-du/Kconfig
>>> > @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
>>> >         bool "R-Car DU LVDS Encoder Support"
>>> >         depends on DRM_RCAR_DU
>>> >         select DRM_PANEL
>>> > +       select OF_FLATTREE
>>> > +       select OF_OVERLAY
>>>
>>> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
>>> could have an overlay from a non-FDT source...
>
> Currently the select is needed for of_fdt_unflatten_tree() only, which is
> not used by the core OF_OVERLAY code. So you could build an overlay in
> memory yourself, and pass that, without using of_fdt_unflatten_tree().
> But that is going to change if I read Frank's reponse well?

Yes, it's currently a 4 or so step process that we plan to make a single call.

Rob

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found]             ` <CAL_JsqJuzXgx-ntbHdYiabi7DUyT8y0Vxj-c5KBmf+Gk+EWtMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2018-01-16 15:31               ` Geert Uytterhoeven
  0 siblings, 0 replies; 38+ messages in thread
From: Geert Uytterhoeven @ 2018-01-16 15:31 UTC (permalink / raw)
  To: Rob Herring
  Cc: Laurent Pinchart, Laurent Pinchart, Frank Rowand, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Rob,

On Tue, Jan 16, 2018 at 4:08 PM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Tue, Jan 16, 2018 at 2:56 AM, Geert Uytterhoeven
> <geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org> wrote:
>> On Mon, Jan 15, 2018 at 7:01 PM, Laurent Pinchart
>> <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> wrote:
>>> On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>>>> > The internal LVDS encoders now have their own DT bindings. Before
>>>> > switching the driver infrastructure to those new bindings, implement
>>>> > backward-compatibility through live DT patching.
>>>>
>>>> Uhh, we just got rid of TI's patching and now adding this one. I guess
>>>> it's necessary, but I'd like to know how long we need to keep this?
>>>
>>> That's a good question. How long are we supposed to keep DT backward
>>> compatibility for ? I don't think there's a one-size-fits-them-all answer to
>>> this question. Geert, any opinion ? How long do you plan to keep the CPG
>>> (clocks) DT backward compatibility for instance ?
>>
>> Good question indeed...
>>
>> It's not just CPG/MSSR. Over the years we also added or changed APMU (SMP),
>> SYSC (power domains), RST (mode pins), CMT (timers), ..., all of which have
>> some sort of compatibility support in the kernel.
>>
>> Hence to avoid having to remember the kernel versions that dropped backwards
>> compatibility for each of the above components, I was thinking about an
>> R-Car Gen2 DT Flag Day.
>
> There's probably also DT changes that enable new features folks would
> want/need? Or maybe carrying for some number of LTS releases is
> enough.

Sure. If you want new features, you have to upgrade the DTB anyway.
Backwards compatibility is about keeping features without updating DTB.

>> However, that was before I learned about your plans for LVDS (it seems every
>> kernel release we learn about something new, postponing the flag day ;-).
>> And now I'm quite sure we'll have another change in the future (DU per
>> channel device nodes)...
>>
>> About using DT fixups to implement backwards compatibility: I did my share
>> of thinking and experimenting with DT fixups (see e.g. "[PATCH/RFC 0/1]
>> soc: renesas: Add DT fixup code for backwards compatibility"
>> (https://www.spinics.net/lists/linux-renesas-soc/msg04305.html).
>> DT fixups are hard to implement right, and not everything can be done
>> that way.  Hence in the end, none of this was ever used upstream, and
>> everything was handled in C...
>
> In an ideal world, we would have some tool:
>
> dt-diff-to-overlay old.dts new.dts > my-fixup-overlay.dts
>
> And then in the kernel have infrastructure such you just declare match
> tables with overlays to apply:
>
> struct of_device_id dt_match[] = {
>   {
>     .compatible = "vendor,board",
>   },
>   {},
> };
> DT_FIXUP(dt_match, my-fixup-overlay.dtbo);
>
> But maybe I'm dreaming...

Really?

We might as well include the latest DTB in the kernel, and use that if
machine_is_compatible("vendor,board")? ;-)

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
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] 38+ messages in thread

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found]                     ` <CAL_JsqKD_VKMrfi42hZ3eHPAMWBwryV0g_cXDUeyaKfPP99LmA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2018-01-16 16:32                       ` Laurent Pinchart
  2018-01-16 16:54                         ` Rob Herring
  0 siblings, 1 reply; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-16 16:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Rob,

On Tuesday, 16 January 2018 16:35:26 EET Rob Herring wrote:
> On Mon, Jan 15, 2018 at 5:46 PM, Frank Rowand wrote:
> > On 01/15/18 12:29, Laurent Pinchart wrote:
> >> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
> >>> On 01/15/18 11:22, Laurent Pinchart wrote:
> >>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
> >>>>> On 01/15/18 09:09, Rob Herring wrote:
> >>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> >>>>>>> The internal LVDS encoders now have their own DT bindings. Before
> >>>>>>> switching the driver infrastructure to those new bindings, implement
> >>>>>>> backward-compatibility through live DT patching.
> >>>>>> 
> >>>>>> Uhh, we just got rid of TI's patching and now adding this one. I
> >>>>>> guess
> >>> 
> >>> Let me first answer the question that you ask later.  You ask "Can we
> >>> work on this together to find a solution that would suit us both ?"
> >>> 
> >>> My answer to that is emphatically YES.  I will definitely work with you
> >>> to try to find a good solution.
> >> 
> >> \o/
> >> 
> >>>>> Please no.  What we just got rid of was making it difficult for me to
> >>>>> make changes to the overlay infrastructure.  There are issues with
> >>>>> overlays that need to be fixed before overlays become really usable.
> >>>>> I am about to propose the next change, which involves removing a
> >>>>> chunk of code that I will not be able to remove if this patch is
> >>>>> accepted (the proposal is awaiting me collecting some data about
> >>>>> the impact of the change, which I expect to complete this week).
> >>> 
> >>> I should have thought just a little bit more before I hit send.  The
> >>> situation is even worse than I wrote.  One of the next steps (in
> >>> addition to what I wrote about above) is to change the overlay apply
> >>> function to accept a flattened device tree (FDT), not an expanded
> >>> device tree.  In this changed model, the unflattened overlay is
> >>> not available to be modified before it is applied.
> >> 
> >> That makes sense if we consider overlays to be immutable objects that we
> >> apply without offering a way to modify them. I won't challenge that API
> >> decision, as my use of an overlay here is a bit of a hack indeed.
> >> 
> >>> It is important for the devicetree infrastructure to have ownership
> >>> of the FDT that is used to create the unflattened tree.  (Notice
> >>> that in the proposed patch, rcar_du_of_get_overlay() follows the
> >>> TI example of doing a kmemdup of the blob (FDT), then uses the
> >>> copy for the unflatten.  The kmemdup() in this case is to create
> >>> a persistent copy of the FDT.)  The driver having ownership of
> >>> this copy, and having the ability to free it is one of the many
> >>> problems with the current overlay implementation.
> >> 
> >> Yes, that's something I've identified as well. Lots of work has been done
> >> to clean up the OF core and we're clearly not done yet. I'm happy to see
> >> all the improvements you're working on.
> >> 
> >>>>> Can you please handle both the old and new bindings through driver
> >>>>> code instead?
> >>>> 
> >>>> I could, but it would be pointless. The point here is to allow cleanups
> >>>> in the driver. The LVDS encoder handling code is very intrusive in its
> >>>> current form and I need to get rid of it. There would be zero point in
> >>>> moving to the new infrastructure, as the main point is to get rid of
> >>>> the old code which prevents moving forward. As a consequence that would
> >>>> block new boards from receiving proper upstream support. An easy option
> >>>> is to break backward compatibility. I'm personally fine with that, but
> >>>> I assume other people would complain :-)
> >>>> 
> >>>> I can, on the other hand, work with you to see how live DT patching
> >>>> could be implemented in this driver without blocking your code. When
> >>>> developing this patch series I start by patching the device tree
> >>>> manually without relying on overlays at all, but got blocked by the
> >>>> fact that I need to allocate phandles for new nodes I create. If there
> >>>> was an API to allocate an unused phandle I could avoid using the
> >>>> overlay infrastructure at all. Or there could be other
> >>> 
> >>> It seems reasonable to provide a way to autogenerate a phandle (if
> >>> requested) by the devicetree code that creates a new node.  Were you
> >>> using a function from drivers/of/dynamic.c to create the node?
> >> 
> >> Not to allocate the node, no. I allocated the device_node structure
> >> manually with kzalloc(), and inserted it in the device tree with
> >> of_attach_node(). Is that the right approach ? I haven't been able to
> >> test the code as I stopped when I realized I couldn't allocate phandles.
> >> 
> >>>> options I'm not thinking of as I don't know what the changes you're
> >>>> working on are. Can we work on this together to find a solution that
> >>>> would suit us both ?
> >>> 
> >>> Again, yes, I would be glad to work with you on this.
> >> 
> >> How would you like to proceed ? I can try the manual approach again but
> >> need information about how I could cleanly implement phandle allocation.
> >> I will likely then run into other issues for which I might need help.
> > 
> > Here are my first thoughts, based on 4.15-rc7:
> > 
> > Question to Rob and Frank: should of_attach_node() be called directly, or
> > should it be called indirectly by creating a change set that adds the
> > node?
> > 
> > Frank's off the cuff answer (but would like to think more about it): since
> > the driver is modifying its own devicetree data, and thus no other entity
> > needs to be notified about the changes, there is no need to add the
> > complexity of using a change set.
> 
> There's exactly 2 users outside of the DT core. That's generally a
> sign of an API I'd like to make private.
> 
> > The following is how of_attach_node() could be modified to dynamically
> > create a phandle on request.
> 
> How would this work for all the phandle references that need to be fixed up?

As I know which properties contain a phandle that needs to be fixed up, my 
plan is to update those properties manually with the value of the newly 
allocated phandle.

What I need here is the ability to insert the following structure in the 
device tree:

        lvds@feb90000 {
               compatible = "renesas,r8a7796-lvds"; (*)
               reg = <0 0xfeb90000 0 0x14>; (*)
               clocks = <&cpg CPG_MOD 727>; (*)

               ports {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        port@0 {
                                reg = <0>;
                                lvds0_in: endpoint {
                                        remote-endpoint = <&du_out_lvds0>; (*)
                                };
                        };
                        port@1 {
                                reg = <1>;
                                lvds0_out: endpoint {
                                        remote-endpoint = <&panel_in>; (*)
                                };
                        };
                };
        };

with the node unit address and all properties marked with a (*) computed at 
runtime based on information extract from the device tree. Additionally I need 
phandles for the lvds0_in and lvds0_out nodes, and set the value of two 
properties in the tree with those phandles.

I've used overlays as that was the only way I found to allocate phandles, but 
any other API will work for me as well.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-16 16:32                       ` Laurent Pinchart
@ 2018-01-16 16:54                         ` Rob Herring
       [not found]                           ` <CAL_Jsq+4X17Q+wva0R6sPHY02TJ5+E5vE8Y98+DB5VF2MdFy0g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 38+ messages in thread
From: Rob Herring @ 2018-01-16 16:54 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Laurent Pinchart, Sergei Shtylyov, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Frank Rowand

On Tue, Jan 16, 2018 at 10:32 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Rob,
>
> On Tuesday, 16 January 2018 16:35:26 EET Rob Herring wrote:
>> On Mon, Jan 15, 2018 at 5:46 PM, Frank Rowand wrote:
>> > On 01/15/18 12:29, Laurent Pinchart wrote:
>> >> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
>> >>> On 01/15/18 11:22, Laurent Pinchart wrote:
>> >>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
>> >>>>> On 01/15/18 09:09, Rob Herring wrote:
>> >>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
>> >>>>>>> The internal LVDS encoders now have their own DT bindings. Before
>> >>>>>>> switching the driver infrastructure to those new bindings, implement
>> >>>>>>> backward-compatibility through live DT patching.

[...]

>> >> How would you like to proceed ? I can try the manual approach again but
>> >> need information about how I could cleanly implement phandle allocation.
>> >> I will likely then run into other issues for which I might need help.
>> >
>> > Here are my first thoughts, based on 4.15-rc7:
>> >
>> > Question to Rob and Frank: should of_attach_node() be called directly, or
>> > should it be called indirectly by creating a change set that adds the
>> > node?
>> >
>> > Frank's off the cuff answer (but would like to think more about it): since
>> > the driver is modifying its own devicetree data, and thus no other entity
>> > needs to be notified about the changes, there is no need to add the
>> > complexity of using a change set.
>>
>> There's exactly 2 users outside of the DT core. That's generally a
>> sign of an API I'd like to make private.
>>
>> > The following is how of_attach_node() could be modified to dynamically
>> > create a phandle on request.
>>
>> How would this work for all the phandle references that need to be fixed up?
>
> As I know which properties contain a phandle that needs to be fixed up, my
> plan is to update those properties manually with the value of the newly
> allocated phandle.

That sounds like more low level, internal detail mucking with than
this current patch.

> What I need here is the ability to insert the following structure in the
> device tree:
>
>         lvds@feb90000 {
>                compatible = "renesas,r8a7796-lvds"; (*)
>                reg = <0 0xfeb90000 0 0x14>; (*)
>                clocks = <&cpg CPG_MOD 727>; (*)

I'm still of the opinion that all of this should be in a per SoC overlay.

>
>                ports {
>                         #address-cells = <1>;
>                         #size-cells = <0>;
>
>                         port@0 {
>                                 reg = <0>;
>                                 lvds0_in: endpoint {
>                                         remote-endpoint = <&du_out_lvds0>; (*)
>                                 };
>                         };
>                         port@1 {
>                                 reg = <1>;
>                                 lvds0_out: endpoint {
>                                         remote-endpoint = <&panel_in>; (*)

Then do the fixup of just the remote-endpoint properties. While it
would be nice to say overlays are completely static, I'm guessing
that's not going to be the case. After all, we pretty much have
overlays because DT being static has limitations.

>                                 };
>                         };
>                 };
>         };
>
> with the node unit address and all properties marked with a (*) computed at
> runtime based on information extract from the device tree. Additionally I need
> phandles for the lvds0_in and lvds0_out nodes, and set the value of two
> properties in the tree with those phandles.
>
> I've used overlays as that was the only way I found to allocate phandles, but
> any other API will work for me as well.

I don't think drivers mucking with phandles directly to avoid another
overlay user is an improvement.

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

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
       [not found]                           ` <CAL_Jsq+4X17Q+wva0R6sPHY02TJ5+E5vE8Y98+DB5VF2MdFy0g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2018-01-16 20:35                             ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-01-16 20:35 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Laurent Pinchart, dri-devel,
	open list:MEDIA DRIVERS FOR RENESAS - FCP, Sergei Shtylyov,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS

Hi Rob,

On Tuesday, 16 January 2018 18:54:00 EET Rob Herring wrote:
> On Tue, Jan 16, 2018 at 10:32 AM, Laurent Pinchart wrote:
> > On Tuesday, 16 January 2018 16:35:26 EET Rob Herring wrote:
> >> On Mon, Jan 15, 2018 at 5:46 PM, Frank Rowand wrote:
> >>> On 01/15/18 12:29, Laurent Pinchart wrote:
> >>>> On Monday, 15 January 2018 22:12:33 EET Frank Rowand wrote:
> >>>>> On 01/15/18 11:22, Laurent Pinchart wrote:
> >>>>>> On Monday, 15 January 2018 21:12:44 EET Frank Rowand wrote:
> >>>>>>> On 01/15/18 09:09, Rob Herring wrote:
> >>>>>>>> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> >>>>>>>>> The internal LVDS encoders now have their own DT bindings. Before
> >>>>>>>>> switching the driver infrastructure to those new bindings,
> >>>>>>>>> implement backward-compatibility through live DT patching.
> 
> [...]
> 
> >>>> How would you like to proceed ? I can try the manual approach again
> >>>> but need information about how I could cleanly implement phandle
> >>>> allocation. I will likely then run into other issues for which I might
> >>>> need help.
> >>> 
> >>> Here are my first thoughts, based on 4.15-rc7:
> >>> 
> >>> Question to Rob and Frank: should of_attach_node() be called directly,
> >>> or should it be called indirectly by creating a change set that adds the
> >>> node?
> >>> 
> >>> Frank's off the cuff answer (but would like to think more about it):
> >>> since the driver is modifying its own devicetree data, and thus no other
> >>> entity needs to be notified about the changes, there is no need to add
> >>> the complexity of using a change set.
> >> 
> >> There's exactly 2 users outside of the DT core. That's generally a
> >> sign of an API I'd like to make private.
> >> 
> >>> The following is how of_attach_node() could be modified to dynamically
> >>> create a phandle on request.
> >> 
> >> How would this work for all the phandle references that need to be fixed
> >> up?
> > 
> > As I know which properties contain a phandle that needs to be fixed up, my
> > plan is to update those properties manually with the value of the newly
> > allocated phandle.
> 
> That sounds like more low level, internal detail mucking with than
> this current patch.

While I think the current patch is a bit of a hack I still like to to some 
extend, so I'm not requesting APIs to muck with OF internals instead of using 
the overlay API. It's entirely up to you and Frank (and other OF core 
developers). I'm fine with either way, all I know is that I need a solution 
:-)

> > What I need here is the ability to insert the following structure in the
> > device tree:
> > 
> >         lvds@feb90000 {
> >         
> >                compatible = "renesas,r8a7796-lvds"; (*)
> >                reg = <0 0xfeb90000 0 0x14>; (*)
> >                clocks = <&cpg CPG_MOD 727>; (*)
> 
> I'm still of the opinion that all of this should be in a per SoC overlay.
> 
> >                ports {
> >                         #address-cells = <1>;
> >                         #size-cells = <0>;
> >                         
> >                         port@0 {
> >                                 reg = <0>;
> >                                 lvds0_in: endpoint {
> >                                         remote-endpoint = <&du_out_lvds0>;
> >                                         (*)
> >                                 };
> >                         };
> >                         port@1 {
> >                                 reg = <1>;
> >                                 lvds0_out: endpoint {
> >                                         remote-endpoint = <&panel_in>; (*)
> 
> Then do the fixup of just the remote-endpoint properties. While it
> would be nice to say overlays are completely static, I'm guessing
> that's not going to be the case. After all, we pretty much have
> overlays because DT being static has limitations.

Do you mean fixing them up in the parsed overlay before applying it, or 
manually in the live device tree after applying the overlay ?

> >                                 };
> >                         };
> >                 };
> >         };
> > 
> > with the node unit address and all properties marked with a (*) computed
> > at runtime based on information extract from the device tree. Additionally
> > I need phandles for the lvds0_in and lvds0_out nodes, and set the value of
> > two properties in the tree with those phandles.
> > 
> > I've used overlays as that was the only way I found to allocate phandles,
> > but any other API will work for me as well.
> 
> I don't think drivers mucking with phandles directly to avoid another
> overlay user is an improvement.

Again I'm fine either way.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
  2018-01-12 23:14   ` [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
@ 2018-01-19 22:47     ` Rob Herring
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2018-01-19 22:47 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, linux-renesas-soc, Sergei Shtylyov, devicetree

On Sat, Jan 13, 2018 at 01:14:19AM +0200, Laurent Pinchart wrote:
> The Renesas R-Car Gen2 and Gen3 SoCs have internal LVDS encoders. Add
> corresponding device tree bindings.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> Changes since v1:
> 
> - Move the SoC name before the IP name in compatible strings
> - Rename parallel input to parallel RGB input
> - Fixed "renesas,r8a7743-lvds" description
> - Document the resets property
> - Fixed typo
> ---
>  .../bindings/display/bridge/renesas,lvds.txt       | 56 ++++++++++++++++++++++
>  MAINTAINERS                                        |  1 +
>  2 files changed, 57 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt

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

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

* Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-01-12 23:14   ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
  2018-01-15 17:09     ` Rob Herring
@ 2018-01-21  9:35     ` Sergei Shtylyov
  1 sibling, 0 replies; 38+ messages in thread
From: Sergei Shtylyov @ 2018-01-21  9:35 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, devicetree

Hello!

On 1/13/2018 2:14 AM, Laurent Pinchart wrote:

    Here's my (superficial) comments...

> The internal LVDS encoders now have their own DT bindings. Before
> switching the driver infrastructure to those new bindings, implement
> backward-compatibility through live DT patching.
> 
> Patching is disabled and will be enabled along with support for the new
> DT bindings in the DU driver.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> Changes since v1:
> 
> - Select OF_FLATTREE
> - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> - Pass void begin and end pointers to rcar_du_of_get_overlay()
> - Use of_get_parent() instead of accessing the parent pointer directly
> - Find the LVDS endpoints nodes based on the LVDS node instead of the
>    root of the overlay
> - Update to the <soc>-lvds compatible string format
> ---
>   drivers/gpu/drm/rcar-du/Kconfig             |   2 +
>   drivers/gpu/drm/rcar-du/Makefile            |   3 +-
>   drivers/gpu/drm/rcar-du/rcar_du_of.c        | 451 ++++++++++++++++++++++++++++
>   drivers/gpu/drm/rcar-du/rcar_du_of.h        |  16 +
>   drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts |  82 +++++
>   5 files changed, 553 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
>   create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
>   create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> 
> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
> index 5d0b4b7119af..3f83352a7313 100644
> --- a/drivers/gpu/drm/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
>   	bool "R-Car DU LVDS Encoder Support"
>   	depends on DRM_RCAR_DU
>   	select DRM_PANEL
> +	select OF_FLATTREE
> +	select OF_OVERLAY
>   	help
>   	  Enable support for the R-Car Display Unit embedded LVDS encoders.
>   
> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
> index 0cf5c11030e8..8ed569a0f462 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -5,10 +5,11 @@ rcar-du-drm-y := rcar_du_crtc.o \
>   		 rcar_du_group.o \
>   		 rcar_du_kms.o \
>   		 rcar_du_lvdscon.o \
> +		 rcar_du_of.o \
>   		 rcar_du_plane.o
>   
>   rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o
> -
> +rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of_lvds.dtb.o
>   rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
>   
>   obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> new file mode 100644
> index 000000000000..2bf91201fc93
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> @@ -0,0 +1,451 @@
[...]
> +static struct device_node __init *
> +static int __init rcar_du_of_add_property(struct device_node *np,
> +					  const char *name, const void *value,
> +					  size_t length)
> +{
> +	struct property *prop;
> +
> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +	if (!prop)
> +		return -ENOMEM;
> +
> +	prop->name = kstrdup(name, GFP_KERNEL);
> +	prop->value = kmemdup(value, length, GFP_KERNEL);
> +	prop->length = length;
> +
> +	if (!prop->name || !prop->value) {
> +		kfree(prop->name);
> +		kfree(prop->value);
> +		kfree(prop);
> +		return -ENOMEM;
> +	}
> +
> +	of_property_set_flag(prop, OF_DYNAMIC);
> +
> +	prop->next = np->properties;
> +	np->properties = prop;
> +
> +	return 0;
> +}
> +
> +/* Free properties allocated dynamically by rcar_du_of_add_property(). */
> +static void __init rcar_du_of_free_properties(struct device_node *np)
> +{
> +	while (np->properties) {
> +		struct property *prop = np->properties;
> +
> +		np->properties = prop->next;
> +
> +		if (OF_IS_DYNAMIC(prop)) {
> +			kfree(prop->name);
> +			kfree(prop->value);
> +			kfree(prop);

    Perhaps these kfree() worth factoring out?

> +		}
> +	}
> +}
> +
[...]
> +extern char __dtb_rcar_du_of_lvds_begin[];
> +extern char __dtb_rcar_du_of_lvds_end[];
> +
> +static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
> +					     unsigned int port_id,
> +					     const struct resource *res,
> +					     const __be32 *reg,
> +					     const struct of_phandle_args *clkspec,
> +					     struct device_node *local,
> +					     struct device_node *remote)
> +{
[...]
> +	/* Apply the overlay, this will resolve phandles. */
> +	ovcs_id = 0;
> +	ret = of_overlay_apply(overlay.np, &ovcs_id);

    You don't use 'ret' afterwards...

> +
> +	/* We're done, free all allocated memory. */
> +out_free_properties:
> +	rcar_du_of_free_properties(lvds);
> +	rcar_du_of_free_properties(du_port);
> +	rcar_du_of_free_properties(du_port_fixup);
> +out_free_names:
> +	kfree(lvds->full_name);
> +	kfree(du_port->full_name);
> +	kfree(du_port_fixup->full_name);
> +out_put_nodes:
> +	of_node_put(lvds);
> +	of_node_put(lvds_endpoints[0]);
> +	of_node_put(lvds_endpoints[1]);
> +	of_node_put(du_port);
> +	of_node_put(du_port_fixup);
> +
> +	rcar_du_of_free_overlay(&overlay);
> +}
> +
> +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids)
> +{
> +	const struct rcar_du_device_info *info;
> +	const struct of_device_id *match;
> +	struct device_node *du;
> +	unsigned int i;
> +	int ret;
> +
> +	/* Get the DU node and exit if not present or disabled. */
> +	du = of_find_matching_node_and_match(NULL, of_ids, &match);
> +	if (!du || !of_device_is_available(du))
> +		goto done;
> +
> +	info = match->data;
> +
> +	/* Patch every LVDS encoder. */
> +	for (i = 0; i < info->num_lvds; ++i) {
> +		struct of_phandle_args clkspec;
> +		struct device_node *local, *remote;
> +		struct resource res;
> +		unsigned int port_id;
> +		const __be32 *reg;
> +		char name[7];
> +		int index;
> +
> +		/*
> +		 * Retrieve the register specifier, the clock specifier and the
> +		 * local and remote endpoints of the LVDS link.
> +		 */
> +		sprintf(name, "lvds.%u", i);
> +		index = of_property_match_string(du, "reg-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		reg = of_get_address(du, index, NULL, NULL);
> +		if (!reg)
> +			continue;
> +
> +		ret = of_address_to_resource(du, index, &res);
> +		if (ret < 0)
> +			continue;
> +
> +		index = of_property_match_string(du, "clock-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		ret = of_parse_phandle_with_args(du, "clocks", "#clock-cells",
> +						 index, &clkspec);
> +		if (ret < 0)
> +			continue;
> +
> +		port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> +
> +		local = of_graph_get_endpoint_by_regs(du, port_id, 0);
> +		if (!local) {
> +			of_node_put(clkspec.np);
> +			continue;
> +		}
> +
> +		remote = of_graph_get_remote_endpoint(local);
> +		if (!remote) {
> +			of_node_put(local);
> +			of_node_put(clkspec.np);
> +			continue;
> +		}
> +
> +		/* Patch the LVDS encoder. */
> +		rcar_du_of_lvds_patch_one(du, port_id, &res, reg, &clkspec,
> +					  local, remote);
> +
> +		of_node_put(clkspec.np);
> +		of_node_put(remote);
> +		of_node_put(local);

    Worth using labels here to avoid the dupication?

> +	}
> +
> +done:
> +	of_node_put(du);
> +}
[...]

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

end of thread, other threads:[~2018-01-21  9:35 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
     [not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
2018-01-12 23:14   ` [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
2018-01-19 22:47     ` Rob Herring
2018-01-12 23:14   ` [PATCH v2 02/12] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings Laurent Pinchart
2018-01-12 23:14   ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
2018-01-15 17:09     ` Rob Herring
2018-01-15 18:01       ` Laurent Pinchart
2018-01-16  8:56         ` Geert Uytterhoeven
     [not found]           ` <CAMuHMdUNcKOod1KCAGSBeMr52PWKqkJo0AWmSNk76t0=Zvu0gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 10:23             ` Laurent Pinchart
2018-01-16 15:08           ` Rob Herring
     [not found]             ` <CAL_JsqJuzXgx-ntbHdYiabi7DUyT8y0Vxj-c5KBmf+Gk+EWtMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 15:31               ` Geert Uytterhoeven
2018-01-15 19:12       ` Frank Rowand
2018-01-15 19:22         ` Laurent Pinchart
2018-01-15 20:12           ` Frank Rowand
     [not found]             ` <444f1b6b-fa57-da7c-08fd-51b28cdb5fff-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-01-15 20:29               ` Laurent Pinchart
2018-01-15 23:46                 ` Frank Rowand
2018-01-15 23:57                   ` Frank Rowand
2018-01-16 14:35                   ` Rob Herring
     [not found]                     ` <CAL_JsqKD_VKMrfi42hZ3eHPAMWBwryV0g_cXDUeyaKfPP99LmA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 16:32                       ` Laurent Pinchart
2018-01-16 16:54                         ` Rob Herring
     [not found]                           ` <CAL_Jsq+4X17Q+wva0R6sPHY02TJ5+E5vE8Y98+DB5VF2MdFy0g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 20:35                             ` Laurent Pinchart
2018-01-21  9:35     ` Sergei Shtylyov
2018-01-12 23:14 ` [PATCH v2 04/12] drm: rcar-du: Convert LVDS encoder code to bridge driver Laurent Pinchart
2018-01-15  8:30   ` Geert Uytterhoeven
2018-01-15  8:32     ` Laurent Pinchart
2018-01-15 20:25   ` Sergei Shtylyov
2018-01-15 20:32     ` Laurent Pinchart
2018-01-15 21:01       ` Sergei Shtylyov
2018-01-12 23:14 ` [PATCH v2 05/12] ARM: dts: porter: Fix HDMI output routing Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 06/12] ARM: dts: r8a7790: Convert to new LVDS DT bindings Laurent Pinchart
2018-01-15 12:30   ` Sergei Shtylyov
2018-01-12 23:14 ` [PATCH v2 07/12] ARM: dts: r8a7791: " Laurent Pinchart
2018-01-15 12:27   ` Sergei Shtylyov
2018-01-12 23:14 ` [PATCH v2 08/12] ARM: dts: r8a7792: Convert to new DU " Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 09/12] ARM: dts: r8a7793: Convert to new LVDS " Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 10/12] ARM: dts: r8a7794: Convert to new DU " Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 11/12] arm64: dts: renesas: r8a7795: Convert to new LVDS " Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 12/12] arm64: dts: renesas: r8a7796: " Laurent Pinchart

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