devicetree.vger.kernel.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>
  0 siblings, 1 reply; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ messages in thread

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

Thread overview: 22+ 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

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