All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
@ 2018-02-22 13:13 ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Frank Rowand, 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 1/4 and 2/4 define new DT bindings for the LVDS
encoders, and deprecate their description inside the DU bindings. To retain
backward compatibility with existing DT, patch 3/4 then patch the device tree
at runtime to convert the legacy bindings to the new ones.

With the DT side addressed, patch 4/4 converts the LVDS support code to a
separate bridge driver.

I decided to go for live DT patching in patch 3/4 because implementing
support for both the legacy and new bindings in the driver would have been
very intrusive, and prevented further cleanups. This version relies more
heavily on overlays to avoid touching the internals of the OF core compared to
v2, even if manual fixes to the device tree are still needed.

As all the patches but the last one have been acked, I plan to send a pull
request by the end of the week if no new issue is discovered.

Compared to v5, I've dropped the OF changeset halpers series as Frank raised
concerns about hidding it in the middle of a driver patch series. I've thus
copied the implementation of of_changeset_add_property_copy() in the driver to
avoid blocking this series. The function arguments are identical, so when the
OF changeset helpers will land it will be very easy to drop the private copy
and use the of_changeset_add_property_copy() helper.

Compared to v4, the patch "of: changeset: Add of_changeset_node_move method"
has been dropped as it's not needed. The patches that update the DT sources to
the new DU and LVDS bindings have been dropped as well to avoid spamming the
lists as they depend on the driver changes going in first to avoid
regressions and haven't been changed.

Compared to v3, this series uses the OF changeset API to update properties
instead of accessing the internals of the property structure. This removes the
local implementation of functions to look up nodes by path and update
properties. In order to do this, I pulled in Pantelis' patch series titled
"[PATCH v2 0/5] of: dynamic: Changesets helpers & fixes" at Rob's request, and
rebased it while taking two small review comments into account.

Rob, I'd like this series to be merged in v4.17. As the changeset helpers are
now a dependency, I'd need you to merge them early (ideally on top of
v4.16-rc1) and provide a stable branch, or get your ack to merge them through
Dave's tree if they don't conflict with what you have and will queue for
v4.17.

This version also drops the small fix to the Porter board device tree that has
been queued for v4.17 already.

Compared to v2, the biggest change is in patch 3/4. Following Rob's and
Frank's reviews it was clear that modifying the unflattened DT structure of
the overlay before applying it wasn't popular. I have thus decided to use one
overlay source per SoC to move as much of the DT changes to the overlay as
possible, and only perform manual modifications (that are still needed as some
of the information is board-specific) on the system DT after applying the
overlay. As a result the overlay is parsed and applied without being modified.

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 (4):
  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

 .../bindings/display/bridge/renesas,lvds.txt       |  56 +++
 .../devicetree/bindings/display/renesas,du.txt     |  31 +-
 MAINTAINERS                                        |   1 +
 drivers/gpu/drm/rcar-du/Kconfig                    |   6 +-
 drivers/gpu/drm/rcar-du/Makefile                   |  10 +-
 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          | 238 ----------
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h          |  64 ---
 drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 ++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 +
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 +++
 drivers/gpu/drm/rcar-du/rcar_lvds.c                | 524 +++++++++++++++++++++
 22 files changed, 1290 insertions(+), 637 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_r8a7790.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_lvds.c

-- 
Regards,

Laurent Pinchart

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

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

* [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
@ 2018-02-22 13:13 ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Rob Herring, Frank Rowand, 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 1/4 and 2/4 define new DT bindings for the LVDS
encoders, and deprecate their description inside the DU bindings. To retain
backward compatibility with existing DT, patch 3/4 then patch the device tree
at runtime to convert the legacy bindings to the new ones.

With the DT side addressed, patch 4/4 converts the LVDS support code to a
separate bridge driver.

I decided to go for live DT patching in patch 3/4 because implementing
support for both the legacy and new bindings in the driver would have been
very intrusive, and prevented further cleanups. This version relies more
heavily on overlays to avoid touching the internals of the OF core compared to
v2, even if manual fixes to the device tree are still needed.

As all the patches but the last one have been acked, I plan to send a pull
request by the end of the week if no new issue is discovered.

Compared to v5, I've dropped the OF changeset halpers series as Frank raised
concerns about hidding it in the middle of a driver patch series. I've thus
copied the implementation of of_changeset_add_property_copy() in the driver to
avoid blocking this series. The function arguments are identical, so when the
OF changeset helpers will land it will be very easy to drop the private copy
and use the of_changeset_add_property_copy() helper.

Compared to v4, the patch "of: changeset: Add of_changeset_node_move method"
has been dropped as it's not needed. The patches that update the DT sources to
the new DU and LVDS bindings have been dropped as well to avoid spamming the
lists as they depend on the driver changes going in first to avoid
regressions and haven't been changed.

Compared to v3, this series uses the OF changeset API to update properties
instead of accessing the internals of the property structure. This removes the
local implementation of functions to look up nodes by path and update
properties. In order to do this, I pulled in Pantelis' patch series titled
"[PATCH v2 0/5] of: dynamic: Changesets helpers & fixes" at Rob's request, and
rebased it while taking two small review comments into account.

Rob, I'd like this series to be merged in v4.17. As the changeset helpers are
now a dependency, I'd need you to merge them early (ideally on top of
v4.16-rc1) and provide a stable branch, or get your ack to merge them through
Dave's tree if they don't conflict with what you have and will queue for
v4.17.

This version also drops the small fix to the Porter board device tree that has
been queued for v4.17 already.

Compared to v2, the biggest change is in patch 3/4. Following Rob's and
Frank's reviews it was clear that modifying the unflattened DT structure of
the overlay before applying it wasn't popular. I have thus decided to use one
overlay source per SoC to move as much of the DT changes to the overlay as
possible, and only perform manual modifications (that are still needed as some
of the information is board-specific) on the system DT after applying the
overlay. As a result the overlay is parsed and applied without being modified.

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 (4):
  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

 .../bindings/display/bridge/renesas,lvds.txt       |  56 +++
 .../devicetree/bindings/display/renesas,du.txt     |  31 +-
 MAINTAINERS                                        |   1 +
 drivers/gpu/drm/rcar-du/Kconfig                    |   6 +-
 drivers/gpu/drm/rcar-du/Makefile                   |  10 +-
 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          | 238 ----------
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h          |  64 ---
 drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 ++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 +
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 +++
 drivers/gpu/drm/rcar-du/rcar_lvds.c                | 524 +++++++++++++++++++++
 22 files changed, 1290 insertions(+), 637 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_r8a7790.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_lvds.c

-- 
Regards,

Laurent Pinchart

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

* [PATCH v6 1/4] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
  2018-02-22 13:13 ` Laurent Pinchart
@ 2018-02-22 13:13   ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, devicetree

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>
Reviewed-by: Rob Herring <robh@kernel.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 2afba909724c..13c8ec11135a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4744,6 +4744,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

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

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

* [PATCH v6 1/4] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
@ 2018-02-22 13:13   ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, devicetree

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>
Reviewed-by: Rob Herring <robh@kernel.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 2afba909724c..13c8ec11135a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4744,6 +4744,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

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

* [PATCH v6 2/4] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings
  2018-02-22 13:13 ` Laurent Pinchart
@ 2018-02-22 13:13   ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, devicetree

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@ideasonboard.com>
Reviewed-by: Rob Herring <robh@kernel.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

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

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

* [PATCH v6 2/4] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings
@ 2018-02-22 13:13   ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, devicetree

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@ideasonboard.com>
Reviewed-by: Rob Herring <robh@kernel.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

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

* [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-22 13:13 ` Laurent Pinchart
@ 2018-02-22 13:13   ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Frank Rowand, devicetree

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 v5:

- Use a private copy of rcar_du_of_changeset_add_property()

Changes since v3:

- Use the OF changeset API
- Use of_graph_get_endpoint_by_regs()
- Replace hardcoded constants by sizeof()

Changes since v2:

- Update the SPDX headers to use C-style comments in header files
- Removed the manually created __local_fixups__ node
- Perform manual fixups on live DT instead of overlay

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                   |   7 +-
 drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
 9 files changed, 661 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_r8a7790.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
+					   rcar_du_of_lvds_r8a7790.dtb.o \
+					   rcar_du_of_lvds_r8a7791.dtb.o \
+					   rcar_du_of_lvds_r8a7793.dtb.o \
+					   rcar_du_of_lvds_r8a7795.dtb.o \
+					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
@@ -0,0 +1,342 @@
+// 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"
+
+/* -----------------------------------------------------------------------------
+ * Generic Overlay Handling
+ */
+
+struct rcar_du_of_overlay {
+	const char *compatible;
+	void *begin;
+	void *end;
+};
+
+#define RCAR_DU_OF_DTB(type, soc)					\
+	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
+	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
+
+#define RCAR_DU_OF_OVERLAY(type, soc)					\
+	{								\
+		.compatible = "renesas,du-" #soc,			\
+		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
+		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
+	}
+
+static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
+					   const char *compatible)
+{
+	const struct rcar_du_of_overlay *dtb = NULL;
+	struct device_node *node = NULL;
+	unsigned int i;
+	int ovcs_id;
+	void *data;
+	void *mem;
+	int ret;
+
+	for (i = 0; dtbs[i].compatible; ++i) {
+		if (!strcmp(dtbs[i].compatible, compatible)) {
+			dtb = &dtbs[i];
+			break;
+		}
+	}
+
+	if (!dtb)
+		return -ENODEV;
+
+	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mem = of_fdt_unflatten_tree(data, NULL, &node);
+	if (!mem) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ovcs_id = 0;
+	ret = of_overlay_apply(node, &ovcs_id);
+
+done:
+	of_node_put(node);
+	kfree(data);
+	kfree(mem);
+
+	return ret;
+}
+
+static int __init rcar_du_of_add_property(struct of_changeset *ocs,
+					  struct device_node *np,
+					  const char *name, const void *value,
+					  int length)
+{
+	struct property *prop;
+	int ret = -ENOMEM;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	prop->name = kstrdup(name, GFP_KERNEL);
+	if (!prop->name)
+		goto out_err;
+
+	prop->value = kmemdup(value, length, GFP_KERNEL);
+	if (!prop->value)
+		goto out_err;
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->length = length;
+
+	ret = of_changeset_add_property(ocs, np, prop);
+	if (!ret)
+		return 0;
+
+out_err:
+	kfree(prop->value);
+	kfree(prop->name);
+	kfree(prop);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * LVDS Overlays
+ */
+
+RCAR_DU_OF_DTB(lvds, r8a7790);
+RCAR_DU_OF_DTB(lvds, r8a7791);
+RCAR_DU_OF_DTB(lvds, r8a7793);
+RCAR_DU_OF_DTB(lvds, r8a7795);
+RCAR_DU_OF_DTB(lvds, r8a7796);
+
+static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
+	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
+	{ /* Sentinel */ },
+};
+
+static struct of_changeset rcar_du_lvds_changeset;
+
+static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
+					     const struct of_phandle_args *clk,
+					     struct device_node *local,
+					     struct device_node *remote)
+{
+	unsigned int psize;
+	unsigned int i;
+	__be32 value[4];
+	int ret;
+
+	/*
+	 * Set the LVDS clocks property. This can't be performed by the overlay
+	 * as the structure of the clock specifier has changed over time, and we
+	 * don't know at compile time which binding version the system we will
+	 * run on uses.
+	 */
+	if (clk->args_count >= ARRAY_SIZE(value) - 1)
+		return;
+
+	of_changeset_init(&rcar_du_lvds_changeset);
+
+	value[0] = cpu_to_be32(clk->np->phandle);
+	for (i = 0; i < clk->args_count; ++i)
+		value[i + 1] = cpu_to_be32(clk->args[i]);
+
+	psize = (clk->args_count + 1) * 4;
+	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
+				      "clocks", value, psize);
+	if (ret < 0)
+		goto done;
+
+	/*
+	 * 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. This can't be performed by the overlay: on the input side the
+	 * overlay would contain a phandle for the DU LVDS output port that
+	 * would clash with the system DT, and on the output side the connection
+	 * is board-specific.
+	 */
+	value[0] = cpu_to_be32(local->phandle);
+	value[1] = cpu_to_be32(remote->phandle);
+
+	for (i = 0; i < 2; ++i) {
+		struct device_node *endpoint;
+
+		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
+		if (!endpoint) {
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
+					      endpoint, "remote-endpoint",
+					      &value[i], sizeof(value[i]));
+		of_node_put(endpoint);
+		if (ret < 0)
+			goto done;
+	}
+
+	ret = of_changeset_apply(&rcar_du_lvds_changeset);
+
+done:
+	if (ret < 0)
+		of_changeset_destroy(&rcar_du_lvds_changeset);
+}
+
+struct lvds_of_data {
+	struct resource res;
+	struct of_phandle_args clkspec;
+	struct device_node *local;
+	struct device_node *remote;
+};
+
+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 lvds_of_data lvds_data[2] = { };
+	struct device_node *lvds_node;
+	struct device_node *soc_node;
+	struct device_node *du_node;
+	char compatible[21];
+	const char *soc_name;
+	unsigned int i;
+	int ret;
+
+	/* Get the DU node and exit if not present or disabled. */
+	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
+	if (!du_node || !of_device_is_available(du_node)) {
+		of_node_put(du_node);
+		return;
+	}
+
+	info = match->data;
+	soc_node = of_get_parent(du_node);
+
+	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
+		goto done;
+
+	/*
+	 * Skip if the LVDS nodes already exists.
+	 *
+	 * The nodes are searched based on the compatible string, which we
+	 * construct from the SoC name found in the DU compatible string. As a
+	 * match has been found we know the compatible string matches the
+	 * expected format and can thus skip some of the string manipulation
+	 * normal safety checks.
+	 */
+	soc_name = strchr(match->compatible, '-') + 1;
+	sprintf(compatible, "renesas,%s-lvds", soc_name);
+	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
+	if (lvds_node) {
+		of_node_put(lvds_node);
+		return;
+	}
+
+	/*
+	 * Parse the DU node and store the register specifier, the clock
+	 * specifier and the local and remote endpoint of the LVDS link for
+	 * later use.
+	 */
+	for (i = 0; i < info->num_lvds; ++i) {
+		struct lvds_of_data *lvds = &lvds_data[i];
+		unsigned int port;
+		char name[7];
+		int index;
+
+		sprintf(name, "lvds.%u", i);
+		index = of_property_match_string(du_node, "clock-names", name);
+		if (index < 0)
+			continue;
+
+		ret = of_parse_phandle_with_args(du_node, "clocks",
+						 "#clock-cells", index,
+						 &lvds->clkspec);
+		if (ret < 0)
+			continue;
+
+		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
+
+		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
+		if (!lvds->local)
+			continue;
+
+		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
+		if (!lvds->remote)
+			continue;
+
+		index = of_property_match_string(du_node, "reg-names", name);
+		if (index < 0)
+			continue;
+
+		of_address_to_resource(du_node, index, &lvds->res);
+	}
+
+	/* Parse and apply the overlay. This will resolve phandles. */
+	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
+				       match->compatible);
+	if (ret < 0)
+		goto done;
+
+	/* Patch the newly created LVDS encoder nodes. */
+	for_each_child_of_node(soc_node, lvds_node) {
+		struct resource res;
+
+		if (!of_device_is_compatible(lvds_node, compatible))
+			continue;
+
+		/* Locate the lvds_data entry based on the resource start. */
+		ret = of_address_to_resource(lvds_node, 0, &res);
+		if (ret < 0)
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
+			if (lvds_data[i].res.start == res.start)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(lvds_data))
+			continue;
+
+		/* Patch the LVDS encoder. */
+		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
+					  lvds_data[i].local,
+					  lvds_data[i].remote);
+	}
+
+done:
+	for (i = 0; i < info->num_lvds; ++i) {
+		of_node_put(lvds_data[i].clkspec.np);
+		of_node_put(lvds_data[i].local);
+		of_node_put(lvds_data[i].remote);
+	}
+
+	of_node_put(soc_node);
+	of_node_put(du_node);
+}
+
+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..c2e65a727e91
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * 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;
+
+#ifdef CONFIG_DRM_RCAR_LVDS
+void __init rcar_du_of_init(const struct of_device_id *of_ids);
+#else
+static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
+#endif /* CONFIG_DRM_RCAR_LVDS */
+
+#endif /* __RCAR_DU_OF_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
new file mode 100644
index 000000000000..f118a6ae7782
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7790-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+
+			lvds@feb94000 {
+				compatible = "renesas,r8a7790-lvds";
+				reg = <0 0xfeb94000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds1_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds1_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+			port@2 {
+				endpoint {
+					remote-endpoint = <&lvds1_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
new file mode 100644
index 000000000000..7d865727928c
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7791-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
new file mode 100644
index 000000000000..bb263711834d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7793-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
new file mode 100644
index 000000000000..9bbf7c9e5ce4
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/soc";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7795-lvds";
+				reg = <0 0xfeb90000 0 0x14>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/soc/display@feb00000/ports";
+		__overlay__ {
+			port@3 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
new file mode 100644
index 000000000000..d16f3e9e08ab
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/soc";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7796-lvds";
+				reg = <0 0xfeb90000 0 0x14>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/soc/display@feb00000/ports";
+		__overlay__ {
+			port@3 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
-- 
Regards,

Laurent Pinchart

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

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

* [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-22 13:13   ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc, Rob Herring, Frank Rowand, devicetree

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 v5:

- Use a private copy of rcar_du_of_changeset_add_property()

Changes since v3:

- Use the OF changeset API
- Use of_graph_get_endpoint_by_regs()
- Replace hardcoded constants by sizeof()

Changes since v2:

- Update the SPDX headers to use C-style comments in header files
- Removed the manually created __local_fixups__ node
- Perform manual fixups on live DT instead of overlay

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                   |   7 +-
 drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
 9 files changed, 661 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_r8a7790.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
+					   rcar_du_of_lvds_r8a7790.dtb.o \
+					   rcar_du_of_lvds_r8a7791.dtb.o \
+					   rcar_du_of_lvds_r8a7793.dtb.o \
+					   rcar_du_of_lvds_r8a7795.dtb.o \
+					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
@@ -0,0 +1,342 @@
+// 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"
+
+/* -----------------------------------------------------------------------------
+ * Generic Overlay Handling
+ */
+
+struct rcar_du_of_overlay {
+	const char *compatible;
+	void *begin;
+	void *end;
+};
+
+#define RCAR_DU_OF_DTB(type, soc)					\
+	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
+	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
+
+#define RCAR_DU_OF_OVERLAY(type, soc)					\
+	{								\
+		.compatible = "renesas,du-" #soc,			\
+		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
+		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
+	}
+
+static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
+					   const char *compatible)
+{
+	const struct rcar_du_of_overlay *dtb = NULL;
+	struct device_node *node = NULL;
+	unsigned int i;
+	int ovcs_id;
+	void *data;
+	void *mem;
+	int ret;
+
+	for (i = 0; dtbs[i].compatible; ++i) {
+		if (!strcmp(dtbs[i].compatible, compatible)) {
+			dtb = &dtbs[i];
+			break;
+		}
+	}
+
+	if (!dtb)
+		return -ENODEV;
+
+	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mem = of_fdt_unflatten_tree(data, NULL, &node);
+	if (!mem) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ovcs_id = 0;
+	ret = of_overlay_apply(node, &ovcs_id);
+
+done:
+	of_node_put(node);
+	kfree(data);
+	kfree(mem);
+
+	return ret;
+}
+
+static int __init rcar_du_of_add_property(struct of_changeset *ocs,
+					  struct device_node *np,
+					  const char *name, const void *value,
+					  int length)
+{
+	struct property *prop;
+	int ret = -ENOMEM;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	prop->name = kstrdup(name, GFP_KERNEL);
+	if (!prop->name)
+		goto out_err;
+
+	prop->value = kmemdup(value, length, GFP_KERNEL);
+	if (!prop->value)
+		goto out_err;
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->length = length;
+
+	ret = of_changeset_add_property(ocs, np, prop);
+	if (!ret)
+		return 0;
+
+out_err:
+	kfree(prop->value);
+	kfree(prop->name);
+	kfree(prop);
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * LVDS Overlays
+ */
+
+RCAR_DU_OF_DTB(lvds, r8a7790);
+RCAR_DU_OF_DTB(lvds, r8a7791);
+RCAR_DU_OF_DTB(lvds, r8a7793);
+RCAR_DU_OF_DTB(lvds, r8a7795);
+RCAR_DU_OF_DTB(lvds, r8a7796);
+
+static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
+	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
+	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
+	{ /* Sentinel */ },
+};
+
+static struct of_changeset rcar_du_lvds_changeset;
+
+static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
+					     const struct of_phandle_args *clk,
+					     struct device_node *local,
+					     struct device_node *remote)
+{
+	unsigned int psize;
+	unsigned int i;
+	__be32 value[4];
+	int ret;
+
+	/*
+	 * Set the LVDS clocks property. This can't be performed by the overlay
+	 * as the structure of the clock specifier has changed over time, and we
+	 * don't know at compile time which binding version the system we will
+	 * run on uses.
+	 */
+	if (clk->args_count >= ARRAY_SIZE(value) - 1)
+		return;
+
+	of_changeset_init(&rcar_du_lvds_changeset);
+
+	value[0] = cpu_to_be32(clk->np->phandle);
+	for (i = 0; i < clk->args_count; ++i)
+		value[i + 1] = cpu_to_be32(clk->args[i]);
+
+	psize = (clk->args_count + 1) * 4;
+	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
+				      "clocks", value, psize);
+	if (ret < 0)
+		goto done;
+
+	/*
+	 * 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. This can't be performed by the overlay: on the input side the
+	 * overlay would contain a phandle for the DU LVDS output port that
+	 * would clash with the system DT, and on the output side the connection
+	 * is board-specific.
+	 */
+	value[0] = cpu_to_be32(local->phandle);
+	value[1] = cpu_to_be32(remote->phandle);
+
+	for (i = 0; i < 2; ++i) {
+		struct device_node *endpoint;
+
+		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
+		if (!endpoint) {
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
+					      endpoint, "remote-endpoint",
+					      &value[i], sizeof(value[i]));
+		of_node_put(endpoint);
+		if (ret < 0)
+			goto done;
+	}
+
+	ret = of_changeset_apply(&rcar_du_lvds_changeset);
+
+done:
+	if (ret < 0)
+		of_changeset_destroy(&rcar_du_lvds_changeset);
+}
+
+struct lvds_of_data {
+	struct resource res;
+	struct of_phandle_args clkspec;
+	struct device_node *local;
+	struct device_node *remote;
+};
+
+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 lvds_of_data lvds_data[2] = { };
+	struct device_node *lvds_node;
+	struct device_node *soc_node;
+	struct device_node *du_node;
+	char compatible[21];
+	const char *soc_name;
+	unsigned int i;
+	int ret;
+
+	/* Get the DU node and exit if not present or disabled. */
+	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
+	if (!du_node || !of_device_is_available(du_node)) {
+		of_node_put(du_node);
+		return;
+	}
+
+	info = match->data;
+	soc_node = of_get_parent(du_node);
+
+	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
+		goto done;
+
+	/*
+	 * Skip if the LVDS nodes already exists.
+	 *
+	 * The nodes are searched based on the compatible string, which we
+	 * construct from the SoC name found in the DU compatible string. As a
+	 * match has been found we know the compatible string matches the
+	 * expected format and can thus skip some of the string manipulation
+	 * normal safety checks.
+	 */
+	soc_name = strchr(match->compatible, '-') + 1;
+	sprintf(compatible, "renesas,%s-lvds", soc_name);
+	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
+	if (lvds_node) {
+		of_node_put(lvds_node);
+		return;
+	}
+
+	/*
+	 * Parse the DU node and store the register specifier, the clock
+	 * specifier and the local and remote endpoint of the LVDS link for
+	 * later use.
+	 */
+	for (i = 0; i < info->num_lvds; ++i) {
+		struct lvds_of_data *lvds = &lvds_data[i];
+		unsigned int port;
+		char name[7];
+		int index;
+
+		sprintf(name, "lvds.%u", i);
+		index = of_property_match_string(du_node, "clock-names", name);
+		if (index < 0)
+			continue;
+
+		ret = of_parse_phandle_with_args(du_node, "clocks",
+						 "#clock-cells", index,
+						 &lvds->clkspec);
+		if (ret < 0)
+			continue;
+
+		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
+
+		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
+		if (!lvds->local)
+			continue;
+
+		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
+		if (!lvds->remote)
+			continue;
+
+		index = of_property_match_string(du_node, "reg-names", name);
+		if (index < 0)
+			continue;
+
+		of_address_to_resource(du_node, index, &lvds->res);
+	}
+
+	/* Parse and apply the overlay. This will resolve phandles. */
+	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
+				       match->compatible);
+	if (ret < 0)
+		goto done;
+
+	/* Patch the newly created LVDS encoder nodes. */
+	for_each_child_of_node(soc_node, lvds_node) {
+		struct resource res;
+
+		if (!of_device_is_compatible(lvds_node, compatible))
+			continue;
+
+		/* Locate the lvds_data entry based on the resource start. */
+		ret = of_address_to_resource(lvds_node, 0, &res);
+		if (ret < 0)
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
+			if (lvds_data[i].res.start == res.start)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(lvds_data))
+			continue;
+
+		/* Patch the LVDS encoder. */
+		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
+					  lvds_data[i].local,
+					  lvds_data[i].remote);
+	}
+
+done:
+	for (i = 0; i < info->num_lvds; ++i) {
+		of_node_put(lvds_data[i].clkspec.np);
+		of_node_put(lvds_data[i].local);
+		of_node_put(lvds_data[i].remote);
+	}
+
+	of_node_put(soc_node);
+	of_node_put(du_node);
+}
+
+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..c2e65a727e91
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * 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;
+
+#ifdef CONFIG_DRM_RCAR_LVDS
+void __init rcar_du_of_init(const struct of_device_id *of_ids);
+#else
+static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
+#endif /* CONFIG_DRM_RCAR_LVDS */
+
+#endif /* __RCAR_DU_OF_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
new file mode 100644
index 000000000000..f118a6ae7782
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7790-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+
+			lvds@feb94000 {
+				compatible = "renesas,r8a7790-lvds";
+				reg = <0 0xfeb94000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds1_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds1_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+			port@2 {
+				endpoint {
+					remote-endpoint = <&lvds1_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
new file mode 100644
index 000000000000..7d865727928c
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7791-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
new file mode 100644
index 000000000000..bb263711834d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7793-lvds";
+				reg = <0 0xfeb90000 0 0x1c>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/display@feb00000/ports";
+		__overlay__ {
+			port@1 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
new file mode 100644
index 000000000000..9bbf7c9e5ce4
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/soc";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7795-lvds";
+				reg = <0 0xfeb90000 0 0x14>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/soc/display@feb00000/ports";
+		__overlay__ {
+			port@3 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
new file mode 100644
index 000000000000..d16f3e9e08ab
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
+ *
+ * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on work from Jyri Sarha <jsarha@ti.com>
+ * Copyright (C) 2015 Texas Instruments
+ */
+
+/dts-v1/;
+/plugin/;
+/ {
+	fragment@0 {
+		target-path = "/soc";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			lvds@feb90000 {
+				compatible = "renesas,r8a7796-lvds";
+				reg = <0 0xfeb90000 0 0x14>;
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						lvds0_input: endpoint {
+						};
+					};
+					port@1 {
+						reg = <1>;
+						lvds0_out: endpoint {
+						};
+					};
+				};
+			};
+		};
+	};
+
+	fragment@1 {
+		target-path = "/soc/display@feb00000/ports";
+		__overlay__ {
+			port@3 {
+				endpoint {
+					remote-endpoint = <&lvds0_input>;
+				};
+			};
+		};
+	};
+};
-- 
Regards,

Laurent Pinchart

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

* [PATCH v6 4/4] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-02-22 13:13 ` Laurent Pinchart
@ 2018-02-22 13:13   ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc

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

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

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

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

Laurent Pinchart

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

* [PATCH v6 4/4] drm: rcar-du: Convert LVDS encoder code to bridge driver
@ 2018-02-22 13:13   ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 13:13 UTC (permalink / raw)
  To: dri-devel; +Cc: linux-renesas-soc

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

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

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

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

Laurent Pinchart

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

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

* Re: [PATCH v6 1/4] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
  2018-02-22 13:13   ` Laurent Pinchart
@ 2018-02-22 13:37     ` Niklas Söderlund
  -1 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 13:37 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-renesas-soc, devicetree, dri-devel

Hi Laurent,

Thanks for your patch.

On 2018-02-22 15:13:33 +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>
> Reviewed-by: Rob Herring <robh@kernel.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

Small typo here s/R8A7791/R8A7793/, with that fixed 

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>


> +  - "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 2afba909724c..13c8ec11135a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4744,6 +4744,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
> 

-- 
Regards,
Niklas Söderlund
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v6 1/4] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings
@ 2018-02-22 13:37     ` Niklas Söderlund
  0 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 13:37 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel, linux-renesas-soc, devicetree

Hi Laurent,

Thanks for your patch.

On 2018-02-22 15:13:33 +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>
> Reviewed-by: Rob Herring <robh@kernel.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

Small typo here s/R8A7791/R8A7793/, with that fixed 

Reviewed-by: Niklas S�derlund <niklas.soderlund+renesas@ragnatech.se>


> +  - "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 2afba909724c..13c8ec11135a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4744,6 +4744,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
> 

-- 
Regards,
Niklas S�derlund

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

* Re: [PATCH v6 2/4] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings
  2018-02-22 13:13   ` Laurent Pinchart
@ 2018-02-22 13:40     ` Niklas Söderlund
  -1 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 13:40 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-renesas-soc, devicetree, dri-devel

Hi Laurent,

Thanks for your patch.

On 2018-02-22 15:13:34 +0200, Laurent Pinchart wrote:
> 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@ideasonboard.com>
> Reviewed-by: Rob Herring <robh@kernel.org>

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

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

-- 
Regards,
Niklas Söderlund
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v6 2/4] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings
@ 2018-02-22 13:40     ` Niklas Söderlund
  0 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 13:40 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel, linux-renesas-soc, devicetree

Hi Laurent,

Thanks for your patch.

On 2018-02-22 15:13:34 +0200, Laurent Pinchart wrote:
> 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@ideasonboard.com>
> Reviewed-by: Rob Herring <robh@kernel.org>

Reviewed-by: Niklas S�derlund <niklas.soderlund+renesas@ragnatech.se>

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

-- 
Regards,
Niklas S�derlund

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

* Re: [PATCH v6 4/4] drm: rcar-du: Convert LVDS encoder code to bridge driver
  2018-02-22 13:13   ` Laurent Pinchart
@ 2018-02-22 14:49     ` Niklas Söderlund
  -1 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 14:49 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: dri-devel, linux-renesas-soc

Hi Laurent,

Thanks for your patch.

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

I'm not so strong when it comes to DRM, but I have done my best to grasp 
this patch. Looking at datasheets and what the code looked before feel 
free to add.

Reviewed-by: Niklas S�derlund <niklas.soderlund+renesas@ragnatech.se>

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

-- 
Regards,
Niklas S�derlund

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

* Re: [PATCH v6 4/4] drm: rcar-du: Convert LVDS encoder code to bridge driver
@ 2018-02-22 14:49     ` Niklas Söderlund
  0 siblings, 0 replies; 38+ messages in thread
From: Niklas Söderlund @ 2018-02-22 14:49 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-renesas-soc, dri-devel

Hi Laurent,

Thanks for your patch.

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

I'm not so strong when it comes to DRM, but I have done my best to grasp 
this patch. Looking at datasheets and what the code looked before feel 
free to add.

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

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

-- 
Regards,
Niklas Söderlund
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
  2018-02-22 13:13 ` Laurent Pinchart
@ 2018-02-22 20:23   ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-22 20:23 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, devicetree

On 02/22/18 05:13, Laurent Pinchart wrote:
> 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 1/4 and 2/4 define new DT bindings for the LVDS
> encoders, and deprecate their description inside the DU bindings. To retain
> backward compatibility with existing DT, patch 3/4 then patch the device tree
> at runtime to convert the legacy bindings to the new ones.
> 
> With the DT side addressed, patch 4/4 converts the LVDS support code to a
> separate bridge driver.
> 
> I decided to go for live DT patching in patch 3/4 because implementing
> support for both the legacy and new bindings in the driver would have been
> very intrusive, and prevented further cleanups. This version relies more
> heavily on overlays to avoid touching the internals of the OF core compared to
> v2, even if manual fixes to the device tree are still needed.
> 
> As all the patches but the last one have been acked, I plan to send a pull
> request by the end of the week if no new issue is discovered.
> 
> Compared to v5, I've dropped the OF changeset halpers series as Frank raised
> concerns about hidding it in the middle of a driver patch series. I've thus
> copied the implementation of of_changeset_add_property_copy() in the driver to
> avoid blocking this series. The function arguments are identical, so when the
> OF changeset helpers will land it will be very easy to drop the private copy
> and use the of_changeset_add_property_copy() helper.

Thank you Laurent.

My issues with that are procedural, and I'll reply later about this in the
v4 patch thread, where I raised the issue.  (For the peanut gallery, I
replied in thread v4 _after_ Laurent sent v5, so Laurent did not ignore
me in v5.)

My technical comments are more relevent than my process comments, in terms
of helping Laurent get his driver submitted, so I will delay the process
comments.

My technical comments will be in reply to patch 3/4.

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

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

* Re: [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
@ 2018-02-22 20:23   ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-22 20:23 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, Rob Herring, devicetree

On 02/22/18 05:13, Laurent Pinchart wrote:
> 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 1/4 and 2/4 define new DT bindings for the LVDS
> encoders, and deprecate their description inside the DU bindings. To retain
> backward compatibility with existing DT, patch 3/4 then patch the device tree
> at runtime to convert the legacy bindings to the new ones.
> 
> With the DT side addressed, patch 4/4 converts the LVDS support code to a
> separate bridge driver.
> 
> I decided to go for live DT patching in patch 3/4 because implementing
> support for both the legacy and new bindings in the driver would have been
> very intrusive, and prevented further cleanups. This version relies more
> heavily on overlays to avoid touching the internals of the OF core compared to
> v2, even if manual fixes to the device tree are still needed.
> 
> As all the patches but the last one have been acked, I plan to send a pull
> request by the end of the week if no new issue is discovered.
> 
> Compared to v5, I've dropped the OF changeset halpers series as Frank raised
> concerns about hidding it in the middle of a driver patch series. I've thus
> copied the implementation of of_changeset_add_property_copy() in the driver to
> avoid blocking this series. The function arguments are identical, so when the
> OF changeset helpers will land it will be very easy to drop the private copy
> and use the of_changeset_add_property_copy() helper.

Thank you Laurent.

My issues with that are procedural, and I'll reply later about this in the
v4 patch thread, where I raised the issue.  (For the peanut gallery, I
replied in thread v4 _after_ Laurent sent v5, so Laurent did not ignore
me in v5.)

My technical comments are more relevent than my process comments, in terms
of helping Laurent get his driver submitted, so I will delay the process
comments.

My technical comments will be in reply to patch 3/4.

-Frank

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

* Re: [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
  2018-02-22 20:23   ` Frank Rowand
@ 2018-02-22 20:27     ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 20:27 UTC (permalink / raw)
  To: Frank Rowand; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

Hi Frank,

On Thursday, 22 February 2018 22:23:20 EET Frank Rowand wrote:
> On 02/22/18 05:13, Laurent Pinchart wrote:
> > 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 1/4 and 2/4 define new DT bindings for the LVDS
> > encoders, and deprecate their description inside the DU bindings. To
> > retain backward compatibility with existing DT, patch 3/4 then patch the
> > device tree at runtime to convert the legacy bindings to the new ones.
> > 
> > With the DT side addressed, patch 4/4 converts the LVDS support code to a
> > separate bridge driver.
> > 
> > I decided to go for live DT patching in patch 3/4 because implementing
> > support for both the legacy and new bindings in the driver would have been
> > very intrusive, and prevented further cleanups. This version relies more
> > heavily on overlays to avoid touching the internals of the OF core
> > compared to v2, even if manual fixes to the device tree are still needed.
> > 
> > As all the patches but the last one have been acked, I plan to send a pull
> > request by the end of the week if no new issue is discovered.
> > 
> > Compared to v5, I've dropped the OF changeset halpers series as Frank
> > raised concerns about hidding it in the middle of a driver patch series.
> > I've thus copied the implementation of of_changeset_add_property_copy()
> > in the driver to avoid blocking this series. The function arguments are
> > identical, so when the OF changeset helpers will land it will be very
> > easy to drop the private copy and use the
> > of_changeset_add_property_copy() helper.
> 
> Thank you Laurent.
> 
> My issues with that are procedural, and I'll reply later about this in the
> v4 patch thread, where I raised the issue.  (For the peanut gallery, I
> replied in thread v4 _after_ Laurent sent v5, so Laurent did not ignore
> me in v5.)

I would have waited for your ack anyway :-)

> My technical comments are more relevent than my process comments, in terms
> of helping Laurent get his driver submitted, so I will delay the process
> comments.

Thank you. 

> My technical comments will be in reply to patch 3/4.

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver
@ 2018-02-22 20:27     ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 20:27 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

Hi Frank,

On Thursday, 22 February 2018 22:23:20 EET Frank Rowand wrote:
> On 02/22/18 05:13, Laurent Pinchart wrote:
> > 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 1/4 and 2/4 define new DT bindings for the LVDS
> > encoders, and deprecate their description inside the DU bindings. To
> > retain backward compatibility with existing DT, patch 3/4 then patch the
> > device tree at runtime to convert the legacy bindings to the new ones.
> > 
> > With the DT side addressed, patch 4/4 converts the LVDS support code to a
> > separate bridge driver.
> > 
> > I decided to go for live DT patching in patch 3/4 because implementing
> > support for both the legacy and new bindings in the driver would have been
> > very intrusive, and prevented further cleanups. This version relies more
> > heavily on overlays to avoid touching the internals of the OF core
> > compared to v2, even if manual fixes to the device tree are still needed.
> > 
> > As all the patches but the last one have been acked, I plan to send a pull
> > request by the end of the week if no new issue is discovered.
> > 
> > Compared to v5, I've dropped the OF changeset halpers series as Frank
> > raised concerns about hidding it in the middle of a driver patch series.
> > I've thus copied the implementation of of_changeset_add_property_copy()
> > in the driver to avoid blocking this series. The function arguments are
> > identical, so when the OF changeset helpers will land it will be very
> > easy to drop the private copy and use the
> > of_changeset_add_property_copy() helper.
> 
> Thank you Laurent.
> 
> My issues with that are procedural, and I'll reply later about this in the
> v4 patch thread, where I raised the issue.  (For the peanut gallery, I
> replied in thread v4 _after_ Laurent sent v5, so Laurent did not ignore
> me in v5.)

I would have waited for your ack anyway :-)

> My technical comments are more relevent than my process comments, in terms
> of helping Laurent get his driver submitted, so I will delay the process
> comments.

Thank you. 

> My technical comments will be in reply to patch 3/4.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-22 13:13   ` Laurent Pinchart
@ 2018-02-22 22:10     ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-22 22:10 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, devicetree

Hi Laurent, Rob,

Thanks for the prompt spin to address my concerns.  There are some small
technical issues.

I did not read the v3 patch until today.  v3 through v6 are still using the
old overlay apply method which uses an expanded device tree as input.

Rob, I don't see my overlay patches in you for-next branch, and I have
not seen an "Applied" message from you.  What is the status of the
overlay patches?

Comments in the patch below.


On 02/22/18 05:13, 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.
> 
> 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 v5:
> 
> - Use a private copy of rcar_du_of_changeset_add_property()
> 
> Changes since v3:
> 
> - Use the OF changeset API
> - Use of_graph_get_endpoint_by_regs()
> - Replace hardcoded constants by sizeof()
> 
> Changes since v2:
> 
> - Update the SPDX headers to use C-style comments in header files
> - Removed the manually created __local_fixups__ node
> - Perform manual fixups on live DT instead of overlay
> 
> 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                   |   7 +-
>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>  9 files changed, 661 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_r8a7790.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
> +					   rcar_du_of_lvds_r8a7790.dtb.o \
> +					   rcar_du_of_lvds_r8a7791.dtb.o \
> +					   rcar_du_of_lvds_r8a7793.dtb.o \
> +					   rcar_du_of_lvds_r8a7795.dtb.o \
> +					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> @@ -0,0 +1,342 @@
> +// 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"
> +
> +/* -----------------------------------------------------------------------------
> + * Generic Overlay Handling
> + */
> +
> +struct rcar_du_of_overlay {
> +	const char *compatible;
> +	void *begin;
> +	void *end;
> +};
> +
> +#define RCAR_DU_OF_DTB(type, soc)					\
> +	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
> +	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
> +
> +#define RCAR_DU_OF_OVERLAY(type, soc)					\
> +	{								\
> +		.compatible = "renesas,du-" #soc,			\
> +		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
> +		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
> +	}
> +
> +static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
> +					   const char *compatible)
> +{
> +	const struct rcar_du_of_overlay *dtb = NULL;
> +	struct device_node *node = NULL;
> +	unsigned int i;
> +	int ovcs_id;
> +	void *data;
> +	void *mem;
> +	int ret;
> +
> +	for (i = 0; dtbs[i].compatible; ++i) {
> +		if (!strcmp(dtbs[i].compatible, compatible)) {
> +			dtb = &dtbs[i];
> +			break;
> +		}
> +	}
> +
> +	if (!dtb)
> +		return -ENODEV;

__If__ my overlay patches are accepted, this block:

> +
> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> +	if (!mem) {
> +		ret = -ENOMEM;
> +		goto done;
> +	}
> +
> +	ovcs_id = 0;
> +	ret = of_overlay_apply(node, &ovcs_id);
> +
> +done:
> +	of_node_put(node);
> +	kfree(data);
> +	kfree(mem);

becomes:

	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);

If my overlay patches do not exist, there are other small errors
in the code block above.  I'll ignore them for the moment.

A quick scan of the rest of the code looks OK.  I'll read through it
more carefully, but wanted to get this reply out without further
delay.

-Frank


> +
> +	return ret;
> +}
> +
> +static int __init rcar_du_of_add_property(struct of_changeset *ocs,
> +					  struct device_node *np,
> +					  const char *name, const void *value,
> +					  int length)
> +{
> +	struct property *prop;
> +	int ret = -ENOMEM;
> +
> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +	if (!prop)
> +		return -ENOMEM;
> +
> +	prop->name = kstrdup(name, GFP_KERNEL);
> +	if (!prop->name)
> +		goto out_err;
> +
> +	prop->value = kmemdup(value, length, GFP_KERNEL);
> +	if (!prop->value)
> +		goto out_err;
> +
> +	of_property_set_flag(prop, OF_DYNAMIC);
> +
> +	prop->length = length;
> +
> +	ret = of_changeset_add_property(ocs, np, prop);
> +	if (!ret)
> +		return 0;
> +
> +out_err:
> +	kfree(prop->value);
> +	kfree(prop->name);
> +	kfree(prop);
> +	return ret;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * LVDS Overlays
> + */
> +
> +RCAR_DU_OF_DTB(lvds, r8a7790);
> +RCAR_DU_OF_DTB(lvds, r8a7791);
> +RCAR_DU_OF_DTB(lvds, r8a7793);
> +RCAR_DU_OF_DTB(lvds, r8a7795);
> +RCAR_DU_OF_DTB(lvds, r8a7796);
> +
> +static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
> +	{ /* Sentinel */ },
> +};
> +
> +static struct of_changeset rcar_du_lvds_changeset;
> +
> +static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
> +					     const struct of_phandle_args *clk,
> +					     struct device_node *local,
> +					     struct device_node *remote)
> +{
> +	unsigned int psize;
> +	unsigned int i;
> +	__be32 value[4];
> +	int ret;
> +
> +	/*
> +	 * Set the LVDS clocks property. This can't be performed by the overlay
> +	 * as the structure of the clock specifier has changed over time, and we
> +	 * don't know at compile time which binding version the system we will
> +	 * run on uses.
> +	 */
> +	if (clk->args_count >= ARRAY_SIZE(value) - 1)
> +		return;
> +
> +	of_changeset_init(&rcar_du_lvds_changeset);
> +
> +	value[0] = cpu_to_be32(clk->np->phandle);
> +	for (i = 0; i < clk->args_count; ++i)
> +		value[i + 1] = cpu_to_be32(clk->args[i]);
> +
> +	psize = (clk->args_count + 1) * 4;
> +	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
> +				      "clocks", value, psize);
> +	if (ret < 0)
> +		goto done;
> +
> +	/*
> +	 * 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. This can't be performed by the overlay: on the input side the
> +	 * overlay would contain a phandle for the DU LVDS output port that
> +	 * would clash with the system DT, and on the output side the connection
> +	 * is board-specific.
> +	 */
> +	value[0] = cpu_to_be32(local->phandle);
> +	value[1] = cpu_to_be32(remote->phandle);
> +
> +	for (i = 0; i < 2; ++i) {
> +		struct device_node *endpoint;
> +
> +		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
> +		if (!endpoint) {
> +			ret = -EINVAL;
> +			goto done;
> +		}
> +
> +		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
> +					      endpoint, "remote-endpoint",
> +					      &value[i], sizeof(value[i]));
> +		of_node_put(endpoint);
> +		if (ret < 0)
> +			goto done;
> +	}
> +
> +	ret = of_changeset_apply(&rcar_du_lvds_changeset);
> +
> +done:
> +	if (ret < 0)
> +		of_changeset_destroy(&rcar_du_lvds_changeset);
> +}
> +
> +struct lvds_of_data {
> +	struct resource res;
> +	struct of_phandle_args clkspec;
> +	struct device_node *local;
> +	struct device_node *remote;
> +};
> +
> +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 lvds_of_data lvds_data[2] = { };
> +	struct device_node *lvds_node;
> +	struct device_node *soc_node;
> +	struct device_node *du_node;
> +	char compatible[21];
> +	const char *soc_name;
> +	unsigned int i;
> +	int ret;
> +
> +	/* Get the DU node and exit if not present or disabled. */
> +	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
> +	if (!du_node || !of_device_is_available(du_node)) {
> +		of_node_put(du_node);
> +		return;
> +	}
> +
> +	info = match->data;
> +	soc_node = of_get_parent(du_node);
> +
> +	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
> +		goto done;
> +
> +	/*
> +	 * Skip if the LVDS nodes already exists.
> +	 *
> +	 * The nodes are searched based on the compatible string, which we
> +	 * construct from the SoC name found in the DU compatible string. As a
> +	 * match has been found we know the compatible string matches the
> +	 * expected format and can thus skip some of the string manipulation
> +	 * normal safety checks.
> +	 */
> +	soc_name = strchr(match->compatible, '-') + 1;
> +	sprintf(compatible, "renesas,%s-lvds", soc_name);
> +	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
> +	if (lvds_node) {
> +		of_node_put(lvds_node);
> +		return;
> +	}
> +
> +	/*
> +	 * Parse the DU node and store the register specifier, the clock
> +	 * specifier and the local and remote endpoint of the LVDS link for
> +	 * later use.
> +	 */
> +	for (i = 0; i < info->num_lvds; ++i) {
> +		struct lvds_of_data *lvds = &lvds_data[i];
> +		unsigned int port;
> +		char name[7];
> +		int index;
> +
> +		sprintf(name, "lvds.%u", i);
> +		index = of_property_match_string(du_node, "clock-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		ret = of_parse_phandle_with_args(du_node, "clocks",
> +						 "#clock-cells", index,
> +						 &lvds->clkspec);
> +		if (ret < 0)
> +			continue;
> +
> +		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> +
> +		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
> +		if (!lvds->local)
> +			continue;
> +
> +		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
> +		if (!lvds->remote)
> +			continue;
> +
> +		index = of_property_match_string(du_node, "reg-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		of_address_to_resource(du_node, index, &lvds->res);
> +	}
> +
> +	/* Parse and apply the overlay. This will resolve phandles. */
> +	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
> +				       match->compatible);
> +	if (ret < 0)
> +		goto done;
> +
> +	/* Patch the newly created LVDS encoder nodes. */
> +	for_each_child_of_node(soc_node, lvds_node) {
> +		struct resource res;
> +
> +		if (!of_device_is_compatible(lvds_node, compatible))
> +			continue;
> +
> +		/* Locate the lvds_data entry based on the resource start. */
> +		ret = of_address_to_resource(lvds_node, 0, &res);
> +		if (ret < 0)
> +			continue;
> +
> +		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
> +			if (lvds_data[i].res.start == res.start)
> +				break;
> +		}
> +
> +		if (i == ARRAY_SIZE(lvds_data))
> +			continue;
> +
> +		/* Patch the LVDS encoder. */
> +		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
> +					  lvds_data[i].local,
> +					  lvds_data[i].remote);
> +	}
> +
> +done:
> +	for (i = 0; i < info->num_lvds; ++i) {
> +		of_node_put(lvds_data[i].clkspec.np);
> +		of_node_put(lvds_data[i].local);
> +		of_node_put(lvds_data[i].remote);
> +	}
> +
> +	of_node_put(soc_node);
> +	of_node_put(du_node);
> +}
> +
> +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..c2e65a727e91
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * 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;
> +
> +#ifdef CONFIG_DRM_RCAR_LVDS
> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
> +#else
> +static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
> +#endif /* CONFIG_DRM_RCAR_LVDS */
> +
> +#endif /* __RCAR_DU_OF_H__ */
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> new file mode 100644
> index 000000000000..f118a6ae7782
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7790-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +
> +			lvds@feb94000 {
> +				compatible = "renesas,r8a7790-lvds";
> +				reg = <0 0xfeb94000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds1_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds1_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +			port@2 {
> +				endpoint {
> +					remote-endpoint = <&lvds1_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> new file mode 100644
> index 000000000000..7d865727928c
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7791-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> new file mode 100644
> index 000000000000..bb263711834d
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7793-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> new file mode 100644
> index 000000000000..9bbf7c9e5ce4
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/soc";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7795-lvds";
> +				reg = <0 0xfeb90000 0 0x14>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/soc/display@feb00000/ports";
> +		__overlay__ {
> +			port@3 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
> new file mode 100644
> index 000000000000..d16f3e9e08ab
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/soc";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7796-lvds";
> +				reg = <0 0xfeb90000 0 0x14>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/soc/display@feb00000/ports";
> +		__overlay__ {
> +			port@3 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> 

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-22 22:10     ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-22 22:10 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, Rob Herring, devicetree

Hi Laurent, Rob,

Thanks for the prompt spin to address my concerns.  There are some small
technical issues.

I did not read the v3 patch until today.  v3 through v6 are still using the
old overlay apply method which uses an expanded device tree as input.

Rob, I don't see my overlay patches in you for-next branch, and I have
not seen an "Applied" message from you.  What is the status of the
overlay patches?

Comments in the patch below.


On 02/22/18 05:13, 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.
> 
> 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 v5:
> 
> - Use a private copy of rcar_du_of_changeset_add_property()
> 
> Changes since v3:
> 
> - Use the OF changeset API
> - Use of_graph_get_endpoint_by_regs()
> - Replace hardcoded constants by sizeof()
> 
> Changes since v2:
> 
> - Update the SPDX headers to use C-style comments in header files
> - Removed the manually created __local_fixups__ node
> - Perform manual fixups on live DT instead of overlay
> 
> 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                   |   7 +-
>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>  9 files changed, 661 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_r8a7790.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
> +					   rcar_du_of_lvds_r8a7790.dtb.o \
> +					   rcar_du_of_lvds_r8a7791.dtb.o \
> +					   rcar_du_of_lvds_r8a7793.dtb.o \
> +					   rcar_du_of_lvds_r8a7795.dtb.o \
> +					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> @@ -0,0 +1,342 @@
> +// 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"
> +
> +/* -----------------------------------------------------------------------------
> + * Generic Overlay Handling
> + */
> +
> +struct rcar_du_of_overlay {
> +	const char *compatible;
> +	void *begin;
> +	void *end;
> +};
> +
> +#define RCAR_DU_OF_DTB(type, soc)					\
> +	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
> +	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
> +
> +#define RCAR_DU_OF_OVERLAY(type, soc)					\
> +	{								\
> +		.compatible = "renesas,du-" #soc,			\
> +		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
> +		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
> +	}
> +
> +static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
> +					   const char *compatible)
> +{
> +	const struct rcar_du_of_overlay *dtb = NULL;
> +	struct device_node *node = NULL;
> +	unsigned int i;
> +	int ovcs_id;
> +	void *data;
> +	void *mem;
> +	int ret;
> +
> +	for (i = 0; dtbs[i].compatible; ++i) {
> +		if (!strcmp(dtbs[i].compatible, compatible)) {
> +			dtb = &dtbs[i];
> +			break;
> +		}
> +	}
> +
> +	if (!dtb)
> +		return -ENODEV;

__If__ my overlay patches are accepted, this block:

> +
> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> +	if (!mem) {
> +		ret = -ENOMEM;
> +		goto done;
> +	}
> +
> +	ovcs_id = 0;
> +	ret = of_overlay_apply(node, &ovcs_id);
> +
> +done:
> +	of_node_put(node);
> +	kfree(data);
> +	kfree(mem);

becomes:

	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);

If my overlay patches do not exist, there are other small errors
in the code block above.  I'll ignore them for the moment.

A quick scan of the rest of the code looks OK.  I'll read through it
more carefully, but wanted to get this reply out without further
delay.

-Frank


> +
> +	return ret;
> +}
> +
> +static int __init rcar_du_of_add_property(struct of_changeset *ocs,
> +					  struct device_node *np,
> +					  const char *name, const void *value,
> +					  int length)
> +{
> +	struct property *prop;
> +	int ret = -ENOMEM;
> +
> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +	if (!prop)
> +		return -ENOMEM;
> +
> +	prop->name = kstrdup(name, GFP_KERNEL);
> +	if (!prop->name)
> +		goto out_err;
> +
> +	prop->value = kmemdup(value, length, GFP_KERNEL);
> +	if (!prop->value)
> +		goto out_err;
> +
> +	of_property_set_flag(prop, OF_DYNAMIC);
> +
> +	prop->length = length;
> +
> +	ret = of_changeset_add_property(ocs, np, prop);
> +	if (!ret)
> +		return 0;
> +
> +out_err:
> +	kfree(prop->value);
> +	kfree(prop->name);
> +	kfree(prop);
> +	return ret;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * LVDS Overlays
> + */
> +
> +RCAR_DU_OF_DTB(lvds, r8a7790);
> +RCAR_DU_OF_DTB(lvds, r8a7791);
> +RCAR_DU_OF_DTB(lvds, r8a7793);
> +RCAR_DU_OF_DTB(lvds, r8a7795);
> +RCAR_DU_OF_DTB(lvds, r8a7796);
> +
> +static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
> +	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
> +	{ /* Sentinel */ },
> +};
> +
> +static struct of_changeset rcar_du_lvds_changeset;
> +
> +static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
> +					     const struct of_phandle_args *clk,
> +					     struct device_node *local,
> +					     struct device_node *remote)
> +{
> +	unsigned int psize;
> +	unsigned int i;
> +	__be32 value[4];
> +	int ret;
> +
> +	/*
> +	 * Set the LVDS clocks property. This can't be performed by the overlay
> +	 * as the structure of the clock specifier has changed over time, and we
> +	 * don't know at compile time which binding version the system we will
> +	 * run on uses.
> +	 */
> +	if (clk->args_count >= ARRAY_SIZE(value) - 1)
> +		return;
> +
> +	of_changeset_init(&rcar_du_lvds_changeset);
> +
> +	value[0] = cpu_to_be32(clk->np->phandle);
> +	for (i = 0; i < clk->args_count; ++i)
> +		value[i + 1] = cpu_to_be32(clk->args[i]);
> +
> +	psize = (clk->args_count + 1) * 4;
> +	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
> +				      "clocks", value, psize);
> +	if (ret < 0)
> +		goto done;
> +
> +	/*
> +	 * 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. This can't be performed by the overlay: on the input side the
> +	 * overlay would contain a phandle for the DU LVDS output port that
> +	 * would clash with the system DT, and on the output side the connection
> +	 * is board-specific.
> +	 */
> +	value[0] = cpu_to_be32(local->phandle);
> +	value[1] = cpu_to_be32(remote->phandle);
> +
> +	for (i = 0; i < 2; ++i) {
> +		struct device_node *endpoint;
> +
> +		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
> +		if (!endpoint) {
> +			ret = -EINVAL;
> +			goto done;
> +		}
> +
> +		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
> +					      endpoint, "remote-endpoint",
> +					      &value[i], sizeof(value[i]));
> +		of_node_put(endpoint);
> +		if (ret < 0)
> +			goto done;
> +	}
> +
> +	ret = of_changeset_apply(&rcar_du_lvds_changeset);
> +
> +done:
> +	if (ret < 0)
> +		of_changeset_destroy(&rcar_du_lvds_changeset);
> +}
> +
> +struct lvds_of_data {
> +	struct resource res;
> +	struct of_phandle_args clkspec;
> +	struct device_node *local;
> +	struct device_node *remote;
> +};
> +
> +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 lvds_of_data lvds_data[2] = { };
> +	struct device_node *lvds_node;
> +	struct device_node *soc_node;
> +	struct device_node *du_node;
> +	char compatible[21];
> +	const char *soc_name;
> +	unsigned int i;
> +	int ret;
> +
> +	/* Get the DU node and exit if not present or disabled. */
> +	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
> +	if (!du_node || !of_device_is_available(du_node)) {
> +		of_node_put(du_node);
> +		return;
> +	}
> +
> +	info = match->data;
> +	soc_node = of_get_parent(du_node);
> +
> +	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
> +		goto done;
> +
> +	/*
> +	 * Skip if the LVDS nodes already exists.
> +	 *
> +	 * The nodes are searched based on the compatible string, which we
> +	 * construct from the SoC name found in the DU compatible string. As a
> +	 * match has been found we know the compatible string matches the
> +	 * expected format and can thus skip some of the string manipulation
> +	 * normal safety checks.
> +	 */
> +	soc_name = strchr(match->compatible, '-') + 1;
> +	sprintf(compatible, "renesas,%s-lvds", soc_name);
> +	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
> +	if (lvds_node) {
> +		of_node_put(lvds_node);
> +		return;
> +	}
> +
> +	/*
> +	 * Parse the DU node and store the register specifier, the clock
> +	 * specifier and the local and remote endpoint of the LVDS link for
> +	 * later use.
> +	 */
> +	for (i = 0; i < info->num_lvds; ++i) {
> +		struct lvds_of_data *lvds = &lvds_data[i];
> +		unsigned int port;
> +		char name[7];
> +		int index;
> +
> +		sprintf(name, "lvds.%u", i);
> +		index = of_property_match_string(du_node, "clock-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		ret = of_parse_phandle_with_args(du_node, "clocks",
> +						 "#clock-cells", index,
> +						 &lvds->clkspec);
> +		if (ret < 0)
> +			continue;
> +
> +		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> +
> +		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
> +		if (!lvds->local)
> +			continue;
> +
> +		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
> +		if (!lvds->remote)
> +			continue;
> +
> +		index = of_property_match_string(du_node, "reg-names", name);
> +		if (index < 0)
> +			continue;
> +
> +		of_address_to_resource(du_node, index, &lvds->res);
> +	}
> +
> +	/* Parse and apply the overlay. This will resolve phandles. */
> +	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
> +				       match->compatible);
> +	if (ret < 0)
> +		goto done;
> +
> +	/* Patch the newly created LVDS encoder nodes. */
> +	for_each_child_of_node(soc_node, lvds_node) {
> +		struct resource res;
> +
> +		if (!of_device_is_compatible(lvds_node, compatible))
> +			continue;
> +
> +		/* Locate the lvds_data entry based on the resource start. */
> +		ret = of_address_to_resource(lvds_node, 0, &res);
> +		if (ret < 0)
> +			continue;
> +
> +		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
> +			if (lvds_data[i].res.start == res.start)
> +				break;
> +		}
> +
> +		if (i == ARRAY_SIZE(lvds_data))
> +			continue;
> +
> +		/* Patch the LVDS encoder. */
> +		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
> +					  lvds_data[i].local,
> +					  lvds_data[i].remote);
> +	}
> +
> +done:
> +	for (i = 0; i < info->num_lvds; ++i) {
> +		of_node_put(lvds_data[i].clkspec.np);
> +		of_node_put(lvds_data[i].local);
> +		of_node_put(lvds_data[i].remote);
> +	}
> +
> +	of_node_put(soc_node);
> +	of_node_put(du_node);
> +}
> +
> +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..c2e65a727e91
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * 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;
> +
> +#ifdef CONFIG_DRM_RCAR_LVDS
> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
> +#else
> +static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
> +#endif /* CONFIG_DRM_RCAR_LVDS */
> +
> +#endif /* __RCAR_DU_OF_H__ */
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> new file mode 100644
> index 000000000000..f118a6ae7782
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7790-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +
> +			lvds@feb94000 {
> +				compatible = "renesas,r8a7790-lvds";
> +				reg = <0 0xfeb94000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds1_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds1_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +			port@2 {
> +				endpoint {
> +					remote-endpoint = <&lvds1_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> new file mode 100644
> index 000000000000..7d865727928c
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7791-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> new file mode 100644
> index 000000000000..bb263711834d
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7793-lvds";
> +				reg = <0 0xfeb90000 0 0x1c>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/display@feb00000/ports";
> +		__overlay__ {
> +			port@1 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> new file mode 100644
> index 000000000000..9bbf7c9e5ce4
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/soc";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7795-lvds";
> +				reg = <0 0xfeb90000 0 0x14>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/soc/display@feb00000/ports";
> +		__overlay__ {
> +			port@3 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
> new file mode 100644
> index 000000000000..d16f3e9e08ab
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
> + *
> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * Based on work from Jyri Sarha <jsarha@ti.com>
> + * Copyright (C) 2015 Texas Instruments
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> +	fragment@0 {
> +		target-path = "/soc";
> +		__overlay__ {
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +
> +			lvds@feb90000 {
> +				compatible = "renesas,r8a7796-lvds";
> +				reg = <0 0xfeb90000 0 0x14>;
> +
> +				ports {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +
> +					port@0 {
> +						reg = <0>;
> +						lvds0_input: endpoint {
> +						};
> +					};
> +					port@1 {
> +						reg = <1>;
> +						lvds0_out: endpoint {
> +						};
> +					};
> +				};
> +			};
> +		};
> +	};
> +
> +	fragment@1 {
> +		target-path = "/soc/display@feb00000/ports";
> +		__overlay__ {
> +			port@3 {
> +				endpoint {
> +					remote-endpoint = <&lvds0_input>;
> +				};
> +			};
> +		};
> +	};
> +};
> 

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-22 22:10     ` Frank Rowand
@ 2018-02-22 22:22       ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 22:22 UTC (permalink / raw)
  To: Frank Rowand; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

Hi Frank,

On Friday, 23 February 2018 00:10:17 EET Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> On 02/22/18 05:13, 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.
> > 
> > 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 v5:
> > 
> > - Use a private copy of rcar_du_of_changeset_add_property()
> > 
> > Changes since v3:
> > 
> > - Use the OF changeset API
> > - Use of_graph_get_endpoint_by_regs()
> > - Replace hardcoded constants by sizeof()
> > 
> > Changes since v2:
> > 
> > - Update the SPDX headers to use C-style comments in header files
> > - Removed the manually created __local_fixups__ node
> > - Perform manual fixups on live DT instead of overlay
> > 
> > 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                   |   7 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 ++++++++++++++++
> >  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >  9 files changed, 661 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_r8a7790.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts

[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..ac442ddfed16
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c

[snip]

> > +static int __init rcar_du_of_apply_overlay(const struct
> > rcar_du_of_overlay *dtbs,
> > +					   const char *compatible)
> > +{
> > +	const struct rcar_du_of_overlay *dtb = NULL;
> > +	struct device_node *node = NULL;
> > +	unsigned int i;
> > +	int ovcs_id;
> > +	void *data;
> > +	void *mem;
> > +	int ret;
> > +
> > +	for (i = 0; dtbs[i].compatible; ++i) {
> > +		if (!strcmp(dtbs[i].compatible, compatible)) {
> > +			dtb = &dtbs[i];
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (!dtb)
> > +		return -ENODEV;
> 
> __If__ my overlay patches are accepted, this block:
> 
> > +
> > +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> > +	if (!data)
> > +		return -ENOMEM;
> > +
> > +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> > +	if (!mem) {
> > +		ret = -ENOMEM;
> > +		goto done;
> > +	}
> > +
> > +	ovcs_id = 0;
> > +	ret = of_overlay_apply(node, &ovcs_id);
> > +
> > +done:
> > +	of_node_put(node);
> > +	kfree(data);
> > +	kfree(mem);
> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);

I tried to rework this patch in a way that would make switching to FDT 
overlays easy, and I'm glad to hear I haven't done a too bad job :-)

Are your patches scheduled for merge in v4.17 ? If so, is it possible to get 
apply them in a stable branch on top of v4.16-rc1 that can be merged as a 
dependency for this series ? There are changes to the Renesas DT queued for 
merge in v4.17 that would make delaying this patch series to v4.18 quite 
painful.

> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.

Thank you.

> > +
> > +	return ret;
> > +}

[snip]

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-22 22:22       ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-22 22:22 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

Hi Frank,

On Friday, 23 February 2018 00:10:17 EET Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> On 02/22/18 05:13, 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.
> > 
> > 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 v5:
> > 
> > - Use a private copy of rcar_du_of_changeset_add_property()
> > 
> > Changes since v3:
> > 
> > - Use the OF changeset API
> > - Use of_graph_get_endpoint_by_regs()
> > - Replace hardcoded constants by sizeof()
> > 
> > Changes since v2:
> > 
> > - Update the SPDX headers to use C-style comments in header files
> > - Removed the manually created __local_fixups__ node
> > - Perform manual fixups on live DT instead of overlay
> > 
> > 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                   |   7 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 ++++++++++++++++
> >  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >  9 files changed, 661 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_r8a7790.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts

[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..ac442ddfed16
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c

[snip]

> > +static int __init rcar_du_of_apply_overlay(const struct
> > rcar_du_of_overlay *dtbs,
> > +					   const char *compatible)
> > +{
> > +	const struct rcar_du_of_overlay *dtb = NULL;
> > +	struct device_node *node = NULL;
> > +	unsigned int i;
> > +	int ovcs_id;
> > +	void *data;
> > +	void *mem;
> > +	int ret;
> > +
> > +	for (i = 0; dtbs[i].compatible; ++i) {
> > +		if (!strcmp(dtbs[i].compatible, compatible)) {
> > +			dtb = &dtbs[i];
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (!dtb)
> > +		return -ENODEV;
> 
> __If__ my overlay patches are accepted, this block:
> 
> > +
> > +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> > +	if (!data)
> > +		return -ENOMEM;
> > +
> > +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> > +	if (!mem) {
> > +		ret = -ENOMEM;
> > +		goto done;
> > +	}
> > +
> > +	ovcs_id = 0;
> > +	ret = of_overlay_apply(node, &ovcs_id);
> > +
> > +done:
> > +	of_node_put(node);
> > +	kfree(data);
> > +	kfree(mem);
> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);

I tried to rework this patch in a way that would make switching to FDT 
overlays easy, and I'm glad to hear I haven't done a too bad job :-)

Are your patches scheduled for merge in v4.17 ? If so, is it possible to get 
apply them in a stable branch on top of v4.16-rc1 that can be merged as a 
dependency for this series ? There are changes to the Renesas DT queued for 
merge in v4.17 that would make delaying this patch series to v4.18 quite 
painful.

> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.

Thank you.

> > +
> > +	return ret;
> > +}

[snip]

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-22 22:10     ` Frank Rowand
@ 2018-02-23  2:38       ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-23  2:38 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, devicetree

On 02/22/18 14:10, Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> 
> On 02/22/18 05:13, 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.
>>
>> 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 v5:
>>
>> - Use a private copy of rcar_du_of_changeset_add_property()
>>
>> Changes since v3:
>>
>> - Use the OF changeset API
>> - Use of_graph_get_endpoint_by_regs()
>> - Replace hardcoded constants by sizeof()
>>
>> Changes since v2:
>>
>> - Update the SPDX headers to use C-style comments in header files
>> - Removed the manually created __local_fixups__ node
>> - Perform manual fixups on live DT instead of overlay
>>
>> 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                   |   7 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>  9 files changed, 661 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_r8a7790.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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

< snip >

> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> 
> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.

< snip >

I was hoping to be able to convert the .dts files to use sugar syntax
instead of hand coding the fragment nodes, but for this specific set
of files I failed, since the labels that would have been required do
not already exist in the base .dts files that that overlays would be
applied against.

Oh well.  It was an interesting exercise anyway, trying to be crafty.

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-23  2:38       ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-23  2:38 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, Rob Herring, devicetree

On 02/22/18 14:10, Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> 
> On 02/22/18 05:13, 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.
>>
>> 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 v5:
>>
>> - Use a private copy of rcar_du_of_changeset_add_property()
>>
>> Changes since v3:
>>
>> - Use the OF changeset API
>> - Use of_graph_get_endpoint_by_regs()
>> - Replace hardcoded constants by sizeof()
>>
>> Changes since v2:
>>
>> - Update the SPDX headers to use C-style comments in header files
>> - Removed the manually created __local_fixups__ node
>> - Perform manual fixups on live DT instead of overlay
>>
>> 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                   |   7 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>  9 files changed, 661 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_r8a7790.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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

< snip >

> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> 
> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.

< snip >

I was hoping to be able to convert the .dts files to use sugar syntax
instead of hand coding the fragment nodes, but for this specific set
of files I failed, since the labels that would have been required do
not already exist in the base .dts files that that overlays would be
applied against.

Oh well.  It was an interesting exercise anyway, trying to be crafty.

-Frank

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-23  2:38       ` Frank Rowand
@ 2018-02-23  9:00         ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-23  9:00 UTC (permalink / raw)
  To: Frank Rowand; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

Hi Frank,

On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
> On 02/22/18 14:10, Frank Rowand wrote:
> > Hi Laurent, Rob,
> > 
> > Thanks for the prompt spin to address my concerns.  There are some small
> > technical issues.
> > 
> > I did not read the v3 patch until today.  v3 through v6 are still using
> > the old overlay apply method which uses an expanded device tree as input.
> > 
> > Rob, I don't see my overlay patches in you for-next branch, and I have
> > not seen an "Applied" message from you.  What is the status of the
> > overlay patches?
> > 
> > Comments in the patch below.
> > 
> > On 02/22/18 05:13, 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.
> >> 
> >> 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 v5:
> >> 
> >> - Use a private copy of rcar_du_of_changeset_add_property()
> >> 
> >> Changes since v3:
> >> 
> >> - Use the OF changeset API
> >> - Use of_graph_get_endpoint_by_regs()
> >> - Replace hardcoded constants by sizeof()
> >> 
> >> Changes since v2:
> >> 
> >> - Update the SPDX headers to use C-style comments in header files
> >> - Removed the manually created __local_fixups__ node
> >> - Perform manual fixups on live DT instead of overlay
> >> 
> >> 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                   |   7 +-
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>  9 files changed, 661 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_r8a7790.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
> 
> < snip >
> 
> > becomes:
> > 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> > 
> > If my overlay patches do not exist, there are other small errors
> > in the code block above.  I'll ignore them for the moment.
> > 
> > A quick scan of the rest of the code looks OK.  I'll read through it
> > more carefully, but wanted to get this reply out without further
> > delay.
> 
> < snip >
> 
> I was hoping to be able to convert the .dts files to use sugar syntax
> instead of hand coding the fragment nodes, but for this specific set
> of files I failed, since the labels that would have been required do
> not already exist in the base .dts files that that overlays would be
> applied against.

And even if they existed in the base .dts in the kernel sources, there's no 
guarantee that the .dtb on the systems we want to patch would contain symbol, 
so that wouldn't have been an option anyway, would it ?

> Oh well.  It was an interesting exercise anyway, trying to be crafty.

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-23  9:00         ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-23  9:00 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

Hi Frank,

On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
> On 02/22/18 14:10, Frank Rowand wrote:
> > Hi Laurent, Rob,
> > 
> > Thanks for the prompt spin to address my concerns.  There are some small
> > technical issues.
> > 
> > I did not read the v3 patch until today.  v3 through v6 are still using
> > the old overlay apply method which uses an expanded device tree as input.
> > 
> > Rob, I don't see my overlay patches in you for-next branch, and I have
> > not seen an "Applied" message from you.  What is the status of the
> > overlay patches?
> > 
> > Comments in the patch below.
> > 
> > On 02/22/18 05:13, 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.
> >> 
> >> 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 v5:
> >> 
> >> - Use a private copy of rcar_du_of_changeset_add_property()
> >> 
> >> Changes since v3:
> >> 
> >> - Use the OF changeset API
> >> - Use of_graph_get_endpoint_by_regs()
> >> - Replace hardcoded constants by sizeof()
> >> 
> >> Changes since v2:
> >> 
> >> - Update the SPDX headers to use C-style comments in header files
> >> - Removed the manually created __local_fixups__ node
> >> - Perform manual fixups on live DT instead of overlay
> >> 
> >> 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                   |   7 +-
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>  9 files changed, 661 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_r8a7790.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
> 
> < snip >
> 
> > becomes:
> > 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> > 
> > If my overlay patches do not exist, there are other small errors
> > in the code block above.  I'll ignore them for the moment.
> > 
> > A quick scan of the rest of the code looks OK.  I'll read through it
> > more carefully, but wanted to get this reply out without further
> > delay.
> 
> < snip >
> 
> I was hoping to be able to convert the .dts files to use sugar syntax
> instead of hand coding the fragment nodes, but for this specific set
> of files I failed, since the labels that would have been required do
> not already exist in the base .dts files that that overlays would be
> applied against.

And even if they existed in the base .dts in the kernel sources, there's no 
guarantee that the .dtb on the systems we want to patch would contain symbol, 
so that wouldn't have been an option anyway, would it ?

> Oh well.  It was an interesting exercise anyway, trying to be crafty.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-23  9:00         ` Laurent Pinchart
@ 2018-02-23 19:43           ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-23 19:43 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

On 02/23/18 01:00, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
>> On 02/22/18 14:10, Frank Rowand wrote:
>>> Hi Laurent, Rob,
>>>
>>> Thanks for the prompt spin to address my concerns.  There are some small
>>> technical issues.
>>>
>>> I did not read the v3 patch until today.  v3 through v6 are still using
>>> the old overlay apply method which uses an expanded device tree as input.
>>>
>>> Rob, I don't see my overlay patches in you for-next branch, and I have
>>> not seen an "Applied" message from you.  What is the status of the
>>> overlay patches?
>>>
>>> Comments in the patch below.
>>>
>>> On 02/22/18 05:13, 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.
>>>>
>>>> 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 v5:
>>>>
>>>> - Use a private copy of rcar_du_of_changeset_add_property()
>>>>
>>>> Changes since v3:
>>>>
>>>> - Use the OF changeset API
>>>> - Use of_graph_get_endpoint_by_regs()
>>>> - Replace hardcoded constants by sizeof()
>>>>
>>>> Changes since v2:
>>>>
>>>> - Update the SPDX headers to use C-style comments in header files
>>>> - Removed the manually created __local_fixups__ node
>>>> - Perform manual fixups on live DT instead of overlay
>>>>
>>>> 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                   |   7 +-
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>>>  9 files changed, 661 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_r8a7790.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
>>
>> < snip >
>>
>>> becomes:
>>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
>>>
>>> If my overlay patches do not exist, there are other small errors
>>> in the code block above.  I'll ignore them for the moment.
>>>
>>> A quick scan of the rest of the code looks OK.  I'll read through it
>>> more carefully, but wanted to get this reply out without further
>>> delay.
>>
>> < snip >
>>
>> I was hoping to be able to convert the .dts files to use sugar syntax
>> instead of hand coding the fragment nodes, but for this specific set
>> of files I failed, since the labels that would have been required do
>> not already exist in the base .dts files that that overlays would be
>> applied against.
> 
> And even if they existed in the base .dts in the kernel sources, there's no 
> guarantee that the .dtb on the systems we want to patch would contain symbol, 
> so that wouldn't have been an option anyway, would it ?

Correct.  And even more troublesome is that some of the fragments are
targeted at node "/", which dtc does not even allow a label on (at the
moment).


> 
>> Oh well.  It was an interesting exercise anyway, trying to be crafty.
> 

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-23 19:43           ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-23 19:43 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

On 02/23/18 01:00, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
>> On 02/22/18 14:10, Frank Rowand wrote:
>>> Hi Laurent, Rob,
>>>
>>> Thanks for the prompt spin to address my concerns.  There are some small
>>> technical issues.
>>>
>>> I did not read the v3 patch until today.  v3 through v6 are still using
>>> the old overlay apply method which uses an expanded device tree as input.
>>>
>>> Rob, I don't see my overlay patches in you for-next branch, and I have
>>> not seen an "Applied" message from you.  What is the status of the
>>> overlay patches?
>>>
>>> Comments in the patch below.
>>>
>>> On 02/22/18 05:13, 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.
>>>>
>>>> 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 v5:
>>>>
>>>> - Use a private copy of rcar_du_of_changeset_add_property()
>>>>
>>>> Changes since v3:
>>>>
>>>> - Use the OF changeset API
>>>> - Use of_graph_get_endpoint_by_regs()
>>>> - Replace hardcoded constants by sizeof()
>>>>
>>>> Changes since v2:
>>>>
>>>> - Update the SPDX headers to use C-style comments in header files
>>>> - Removed the manually created __local_fixups__ node
>>>> - Perform manual fixups on live DT instead of overlay
>>>>
>>>> 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                   |   7 +-
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>>>  9 files changed, 661 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_r8a7790.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
>>
>> < snip >
>>
>>> becomes:
>>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
>>>
>>> If my overlay patches do not exist, there are other small errors
>>> in the code block above.  I'll ignore them for the moment.
>>>
>>> A quick scan of the rest of the code looks OK.  I'll read through it
>>> more carefully, but wanted to get this reply out without further
>>> delay.
>>
>> < snip >
>>
>> I was hoping to be able to convert the .dts files to use sugar syntax
>> instead of hand coding the fragment nodes, but for this specific set
>> of files I failed, since the labels that would have been required do
>> not already exist in the base .dts files that that overlays would be
>> applied against.
> 
> And even if they existed in the base .dts in the kernel sources, there's no 
> guarantee that the .dtb on the systems we want to patch would contain symbol, 
> so that wouldn't have been an option anyway, would it ?

Correct.  And even more troublesome is that some of the fragments are
targeted at node "/", which dtc does not even allow a label on (at the
moment).


> 
>> Oh well.  It was an interesting exercise anyway, trying to be crafty.
> 

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-23 19:43           ` Frank Rowand
@ 2018-02-23 19:56             ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-23 19:56 UTC (permalink / raw)
  To: Frank Rowand; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

Hi Frank,

On Friday, 23 February 2018 21:43:17 EET Frank Rowand wrote:
> On 02/23/18 01:00, Laurent Pinchart wrote:
> > On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
> >> On 02/22/18 14:10, Frank Rowand wrote:
> >>> Hi Laurent, Rob,
> >>> 
> >>> Thanks for the prompt spin to address my concerns.  There are some small
> >>> technical issues.
> >>> 
> >>> I did not read the v3 patch until today.  v3 through v6 are still using
> >>> the old overlay apply method which uses an expanded device tree as
> >>> input.
> >>> 
> >>> Rob, I don't see my overlay patches in you for-next branch, and I have
> >>> not seen an "Applied" message from you.  What is the status of the
> >>> overlay patches?
> >>> 
> >>> Comments in the patch below.
> >>> 
> >>> On 02/22/18 05:13, 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.
> >>>> 
> >>>> 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 v5:
> >>>> 
> >>>> - Use a private copy of rcar_du_of_changeset_add_property()
> >>>> 
> >>>> Changes since v3:
> >>>> 
> >>>> - Use the OF changeset API
> >>>> - Use of_graph_get_endpoint_by_regs()
> >>>> - Replace hardcoded constants by sizeof()
> >>>> 
> >>>> Changes since v2:
> >>>> 
> >>>> - Update the SPDX headers to use C-style comments in header files
> >>>> - Removed the manually created __local_fixups__ node
> >>>> - Perform manual fixups on live DT instead of overlay
> >>>> 
> >>>> 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                   |   7 +-
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>>>  9 files changed, 661 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_r8a7790.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
> >> 
> >> < snip >
> >> 
> >>> becomes:
> >>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> >>> 
> >>> If my overlay patches do not exist, there are other small errors
> >>> in the code block above.  I'll ignore them for the moment.

If you have time to not ignore them I'd appreciate your comments :-) I'd like 
to get this patch series merged in v4.17, and for that I want to be prepared 
to submit it on top of your overlay patches if they make it to mainline, or 
without them if they don't.

> >>> A quick scan of the rest of the code looks OK.  I'll read through it
> >>> more carefully, but wanted to get this reply out without further
> >>> delay.
> >> 
> >> < snip >
> >> 
> >> I was hoping to be able to convert the .dts files to use sugar syntax
> >> instead of hand coding the fragment nodes, but for this specific set
> >> of files I failed, since the labels that would have been required do
> >> not already exist in the base .dts files that that overlays would be
> >> applied against.
> > 
> > And even if they existed in the base .dts in the kernel sources, there's
> > no guarantee that the .dtb on the systems we want to patch would contain
> > symbol, so that wouldn't have been an option anyway, would it ?
> 
> Correct.  And even more troublesome is that some of the fragments are
> targeted at node "/", which dtc does not even allow a label on (at the
> moment).
> 
> >> Oh well.  It was an interesting exercise anyway, trying to be crafty.

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-23 19:56             ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-23 19:56 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

Hi Frank,

On Friday, 23 February 2018 21:43:17 EET Frank Rowand wrote:
> On 02/23/18 01:00, Laurent Pinchart wrote:
> > On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
> >> On 02/22/18 14:10, Frank Rowand wrote:
> >>> Hi Laurent, Rob,
> >>> 
> >>> Thanks for the prompt spin to address my concerns.  There are some small
> >>> technical issues.
> >>> 
> >>> I did not read the v3 patch until today.  v3 through v6 are still using
> >>> the old overlay apply method which uses an expanded device tree as
> >>> input.
> >>> 
> >>> Rob, I don't see my overlay patches in you for-next branch, and I have
> >>> not seen an "Applied" message from you.  What is the status of the
> >>> overlay patches?
> >>> 
> >>> Comments in the patch below.
> >>> 
> >>> On 02/22/18 05:13, 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.
> >>>> 
> >>>> 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 v5:
> >>>> 
> >>>> - Use a private copy of rcar_du_of_changeset_add_property()
> >>>> 
> >>>> Changes since v3:
> >>>> 
> >>>> - Use the OF changeset API
> >>>> - Use of_graph_get_endpoint_by_regs()
> >>>> - Replace hardcoded constants by sizeof()
> >>>> 
> >>>> Changes since v2:
> >>>> 
> >>>> - Update the SPDX headers to use C-style comments in header files
> >>>> - Removed the manually created __local_fixups__ node
> >>>> - Perform manual fixups on live DT instead of overlay
> >>>> 
> >>>> 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                   |   7 +-
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++
> >>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>>>  9 files changed, 661 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_r8a7790.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
> >> 
> >> < snip >
> >> 
> >>> becomes:
> >>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> >>> 
> >>> If my overlay patches do not exist, there are other small errors
> >>> in the code block above.  I'll ignore them for the moment.

If you have time to not ignore them I'd appreciate your comments :-) I'd like 
to get this patch series merged in v4.17, and for that I want to be prepared 
to submit it on top of your overlay patches if they make it to mainline, or 
without them if they don't.

> >>> A quick scan of the rest of the code looks OK.  I'll read through it
> >>> more carefully, but wanted to get this reply out without further
> >>> delay.
> >> 
> >> < snip >
> >> 
> >> I was hoping to be able to convert the .dts files to use sugar syntax
> >> instead of hand coding the fragment nodes, but for this specific set
> >> of files I failed, since the labels that would have been required do
> >> not already exist in the base .dts files that that overlays would be
> >> applied against.
> > 
> > And even if they existed in the base .dts in the kernel sources, there's
> > no guarantee that the .dtb on the systems we want to patch would contain
> > symbol, so that wouldn't have been an option anyway, would it ?
> 
> Correct.  And even more troublesome is that some of the fragments are
> targeted at node "/", which dtc does not even allow a label on (at the
> moment).
> 
> >> Oh well.  It was an interesting exercise anyway, trying to be crafty.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-23 19:56             ` Laurent Pinchart
@ 2018-02-24 22:09               ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-24 22:09 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

On 02/23/18 11:56, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Friday, 23 February 2018 21:43:17 EET Frank Rowand wrote:
>> On 02/23/18 01:00, Laurent Pinchart wrote:
>>> On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
>>>> On 02/22/18 14:10, Frank Rowand wrote:
>>>>> Hi Laurent, Rob,
>>>>>
>>>>> Thanks for the prompt spin to address my concerns.  There are some small
>>>>> technical issues.
>>>>>
>>>>> I did not read the v3 patch until today.  v3 through v6 are still using
>>>>> the old overlay apply method which uses an expanded device tree as
>>>>> input.
>>>>>
>>>>> Rob, I don't see my overlay patches in you for-next branch, and I have
>>>>> not seen an "Applied" message from you.  What is the status of the
>>>>> overlay patches?
>>>>>
>>>>> Comments in the patch below.
>>>>>
>>>>> On 02/22/18 05:13, 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.
>>>>>>
>>>>>> 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 v5:
>>>>>>
>>>>>> - Use a private copy of rcar_du_of_changeset_add_property()
>>>>>>
>>>>>> Changes since v3:
>>>>>>
>>>>>> - Use the OF changeset API
>>>>>> - Use of_graph_get_endpoint_by_regs()
>>>>>> - Replace hardcoded constants by sizeof()
>>>>>>
>>>>>> Changes since v2:
>>>>>>
>>>>>> - Update the SPDX headers to use C-style comments in header files
>>>>>> - Removed the manually created __local_fixups__ node
>>>>>> - Perform manual fixups on live DT instead of overlay
>>>>>>
>>>>>> 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                   |   7 +-
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>>>>>  9 files changed, 661 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_r8a7790.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
>>>>
>>>> < snip >
>>>>
>>>>> becomes:
>>>>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
>>>>>
>>>>> If my overlay patches do not exist, there are other small errors
>>>>> in the code block above.  I'll ignore them for the moment.
> 
> If you have time to not ignore them I'd appreciate your comments :-) I'd like 
> to get this patch series merged in v4.17, and for that I want to be prepared 
> to submit it on top of your overlay patches if they make it to mainline, or 
> without them if they don't.

< snip >

OK, I will.  I did the research to verify my memory, so I just need to type
it in.  I'll reply to an email several layers back in this thread that
I did not snip the code out of, so I can comment in line in the code.

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-24 22:09               ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-24 22:09 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

On 02/23/18 11:56, Laurent Pinchart wrote:
> Hi Frank,
> 
> On Friday, 23 February 2018 21:43:17 EET Frank Rowand wrote:
>> On 02/23/18 01:00, Laurent Pinchart wrote:
>>> On Friday, 23 February 2018 04:38:06 EET Frank Rowand wrote:
>>>> On 02/22/18 14:10, Frank Rowand wrote:
>>>>> Hi Laurent, Rob,
>>>>>
>>>>> Thanks for the prompt spin to address my concerns.  There are some small
>>>>> technical issues.
>>>>>
>>>>> I did not read the v3 patch until today.  v3 through v6 are still using
>>>>> the old overlay apply method which uses an expanded device tree as
>>>>> input.
>>>>>
>>>>> Rob, I don't see my overlay patches in you for-next branch, and I have
>>>>> not seen an "Applied" message from you.  What is the status of the
>>>>> overlay patches?
>>>>>
>>>>> Comments in the patch below.
>>>>>
>>>>> On 02/22/18 05:13, 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.
>>>>>>
>>>>>> 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 v5:
>>>>>>
>>>>>> - Use a private copy of rcar_du_of_changeset_add_property()
>>>>>>
>>>>>> Changes since v3:
>>>>>>
>>>>>> - Use the OF changeset API
>>>>>> - Use of_graph_get_endpoint_by_regs()
>>>>>> - Replace hardcoded constants by sizeof()
>>>>>>
>>>>>> Changes since v2:
>>>>>>
>>>>>> - Update the SPDX headers to use C-style comments in header files
>>>>>> - Removed the manually created __local_fixups__ node
>>>>>> - Perform manual fixups on live DT instead of overlay
>>>>>>
>>>>>> 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                   |   7 +-
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++
>>>>>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>>>>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>>>>>  9 files changed, 661 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_r8a7790.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>>>>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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
>>>>
>>>> < snip >
>>>>
>>>>> becomes:
>>>>> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
>>>>>
>>>>> If my overlay patches do not exist, there are other small errors
>>>>> in the code block above.  I'll ignore them for the moment.
> 
> If you have time to not ignore them I'd appreciate your comments :-) I'd like 
> to get this patch series merged in v4.17, and for that I want to be prepared 
> to submit it on top of your overlay patches if they make it to mainline, or 
> without them if they don't.

< snip >

OK, I will.  I did the research to verify my memory, so I just need to type
it in.  I'll reply to an email several layers back in this thread that
I did not snip the code out of, so I can comment in line in the code.

-Frank

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-22 22:10     ` Frank Rowand
@ 2018-02-24 22:42       ` Frank Rowand
  -1 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-24 22:42 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, devicetree

On 02/22/18 14:10, Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> 
> On 02/22/18 05:13, 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.
>>
>> 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 v5:
>>
>> - Use a private copy of rcar_du_of_changeset_add_property()
>>
>> Changes since v3:
>>
>> - Use the OF changeset API
>> - Use of_graph_get_endpoint_by_regs()
>> - Replace hardcoded constants by sizeof()
>>
>> Changes since v2:
>>
>> - Update the SPDX headers to use C-style comments in header files
>> - Removed the manually created __local_fixups__ node
>> - Perform manual fixups on live DT instead of overlay
>>
>> 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                   |   7 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>  9 files changed, 661 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_r8a7790.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
>> --- a/drivers/gpu/drm/rcar-du/Makefile
>> +++ b/drivers/gpu/drm/rcar-du/Makefile
>> @@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
>> +					   rcar_du_of_lvds_r8a7790.dtb.o \
>> +					   rcar_du_of_lvds_r8a7791.dtb.o \
>> +					   rcar_du_of_lvds_r8a7793.dtb.o \
>> +					   rcar_du_of_lvds_r8a7795.dtb.o \
>> +					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
>> @@ -0,0 +1,342 @@
>> +// 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"
>> +
>> +/* -----------------------------------------------------------------------------
>> + * Generic Overlay Handling
>> + */
>> +
>> +struct rcar_du_of_overlay {
>> +	const char *compatible;
>> +	void *begin;
>> +	void *end;
>> +};
>> +
>> +#define RCAR_DU_OF_DTB(type, soc)					\
>> +	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
>> +	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
>> +
>> +#define RCAR_DU_OF_OVERLAY(type, soc)					\
>> +	{								\
>> +		.compatible = "renesas,du-" #soc,			\
>> +		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
>> +		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
>> +	}
>> +
>> +static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
>> +					   const char *compatible)
>> +{
>> +	const struct rcar_du_of_overlay *dtb = NULL;
>> +	struct device_node *node = NULL;
>> +	unsigned int i;
>> +	int ovcs_id;
>> +	void *data;
>> +	void *mem;
>> +	int ret;
>> +
>> +	for (i = 0; dtbs[i].compatible; ++i) {
>> +		if (!strcmp(dtbs[i].compatible, compatible)) {
>> +			dtb = &dtbs[i];
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!dtb)
>> +		return -ENODEV;
> 

I was trying to avoid reviewing this little block of code, because it
meant spending the time to do the research to verify my memory.  I did
the research, so here are the comments...

> __If__ my overlay patches are accepted, this block:
> 
>> +
>> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
>> +	if (!mem) {

>> +		ret = -ENOMEM;

                kfree(data);

This could be done at the tail of the function if you prefer, but
it is easier for me to put it here to show which case it is ok
to kfree().  And if doing the kfree() here, may as well just
return -ENOMEM here instead of going to done.

>> +		goto done;
>> +	}
>> +
>> +	ovcs_id = 0;
>> +	ret = of_overlay_apply(node, &ovcs_id);
>> +
>> +done:

Do not do the of_node_put() or the kfree()s here.  The live
devicetree and the overlay changeset have pointers into them.

Some error values from of_overlay_apply() do allow you to do some
freeing, but since this is at most a temporary piece of code, it
isn't worth all the complexity of trying to figure that out.  The
implications of the various return values from of_overlay_apply()
are a bit of a hairball.

>> +	of_node_put(node);
>> +	kfree(data);
>> +	kfree(mem);

-Frank


> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> 
> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.
> 
> -Frank
> 
> 
>> +
>> +	return ret;
>> +}
>> +
>> +static int __init rcar_du_of_add_property(struct of_changeset *ocs,
>> +					  struct device_node *np,
>> +					  const char *name, const void *value,
>> +					  int length)
>> +{
>> +	struct property *prop;
>> +	int ret = -ENOMEM;
>> +
>> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
>> +	if (!prop)
>> +		return -ENOMEM;
>> +
>> +	prop->name = kstrdup(name, GFP_KERNEL);
>> +	if (!prop->name)
>> +		goto out_err;
>> +
>> +	prop->value = kmemdup(value, length, GFP_KERNEL);
>> +	if (!prop->value)
>> +		goto out_err;
>> +
>> +	of_property_set_flag(prop, OF_DYNAMIC);
>> +
>> +	prop->length = length;
>> +
>> +	ret = of_changeset_add_property(ocs, np, prop);
>> +	if (!ret)
>> +		return 0;
>> +
>> +out_err:
>> +	kfree(prop->value);
>> +	kfree(prop->name);
>> +	kfree(prop);
>> +	return ret;
>> +}
>> +
>> +/* -----------------------------------------------------------------------------
>> + * LVDS Overlays
>> + */
>> +
>> +RCAR_DU_OF_DTB(lvds, r8a7790);
>> +RCAR_DU_OF_DTB(lvds, r8a7791);
>> +RCAR_DU_OF_DTB(lvds, r8a7793);
>> +RCAR_DU_OF_DTB(lvds, r8a7795);
>> +RCAR_DU_OF_DTB(lvds, r8a7796);
>> +
>> +static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
>> +	{ /* Sentinel */ },
>> +};
>> +
>> +static struct of_changeset rcar_du_lvds_changeset;
>> +
>> +static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
>> +					     const struct of_phandle_args *clk,
>> +					     struct device_node *local,
>> +					     struct device_node *remote)
>> +{
>> +	unsigned int psize;
>> +	unsigned int i;
>> +	__be32 value[4];
>> +	int ret;
>> +
>> +	/*
>> +	 * Set the LVDS clocks property. This can't be performed by the overlay
>> +	 * as the structure of the clock specifier has changed over time, and we
>> +	 * don't know at compile time which binding version the system we will
>> +	 * run on uses.
>> +	 */
>> +	if (clk->args_count >= ARRAY_SIZE(value) - 1)
>> +		return;
>> +
>> +	of_changeset_init(&rcar_du_lvds_changeset);
>> +
>> +	value[0] = cpu_to_be32(clk->np->phandle);
>> +	for (i = 0; i < clk->args_count; ++i)
>> +		value[i + 1] = cpu_to_be32(clk->args[i]);
>> +
>> +	psize = (clk->args_count + 1) * 4;
>> +	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
>> +				      "clocks", value, psize);
>> +	if (ret < 0)
>> +		goto done;
>> +
>> +	/*
>> +	 * 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. This can't be performed by the overlay: on the input side the
>> +	 * overlay would contain a phandle for the DU LVDS output port that
>> +	 * would clash with the system DT, and on the output side the connection
>> +	 * is board-specific.
>> +	 */
>> +	value[0] = cpu_to_be32(local->phandle);
>> +	value[1] = cpu_to_be32(remote->phandle);
>> +
>> +	for (i = 0; i < 2; ++i) {
>> +		struct device_node *endpoint;
>> +
>> +		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
>> +		if (!endpoint) {
>> +			ret = -EINVAL;
>> +			goto done;
>> +		}
>> +
>> +		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
>> +					      endpoint, "remote-endpoint",
>> +					      &value[i], sizeof(value[i]));
>> +		of_node_put(endpoint);
>> +		if (ret < 0)
>> +			goto done;
>> +	}
>> +
>> +	ret = of_changeset_apply(&rcar_du_lvds_changeset);
>> +
>> +done:
>> +	if (ret < 0)
>> +		of_changeset_destroy(&rcar_du_lvds_changeset);
>> +}
>> +
>> +struct lvds_of_data {
>> +	struct resource res;
>> +	struct of_phandle_args clkspec;
>> +	struct device_node *local;
>> +	struct device_node *remote;
>> +};
>> +
>> +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 lvds_of_data lvds_data[2] = { };
>> +	struct device_node *lvds_node;
>> +	struct device_node *soc_node;
>> +	struct device_node *du_node;
>> +	char compatible[21];
>> +	const char *soc_name;
>> +	unsigned int i;
>> +	int ret;
>> +
>> +	/* Get the DU node and exit if not present or disabled. */
>> +	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
>> +	if (!du_node || !of_device_is_available(du_node)) {
>> +		of_node_put(du_node);
>> +		return;
>> +	}
>> +
>> +	info = match->data;
>> +	soc_node = of_get_parent(du_node);
>> +
>> +	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
>> +		goto done;
>> +
>> +	/*
>> +	 * Skip if the LVDS nodes already exists.
>> +	 *
>> +	 * The nodes are searched based on the compatible string, which we
>> +	 * construct from the SoC name found in the DU compatible string. As a
>> +	 * match has been found we know the compatible string matches the
>> +	 * expected format and can thus skip some of the string manipulation
>> +	 * normal safety checks.
>> +	 */
>> +	soc_name = strchr(match->compatible, '-') + 1;
>> +	sprintf(compatible, "renesas,%s-lvds", soc_name);
>> +	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
>> +	if (lvds_node) {
>> +		of_node_put(lvds_node);
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * Parse the DU node and store the register specifier, the clock
>> +	 * specifier and the local and remote endpoint of the LVDS link for
>> +	 * later use.
>> +	 */
>> +	for (i = 0; i < info->num_lvds; ++i) {
>> +		struct lvds_of_data *lvds = &lvds_data[i];
>> +		unsigned int port;
>> +		char name[7];
>> +		int index;
>> +
>> +		sprintf(name, "lvds.%u", i);
>> +		index = of_property_match_string(du_node, "clock-names", name);
>> +		if (index < 0)
>> +			continue;
>> +
>> +		ret = of_parse_phandle_with_args(du_node, "clocks",
>> +						 "#clock-cells", index,
>> +						 &lvds->clkspec);
>> +		if (ret < 0)
>> +			continue;
>> +
>> +		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
>> +
>> +		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
>> +		if (!lvds->local)
>> +			continue;
>> +
>> +		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
>> +		if (!lvds->remote)
>> +			continue;
>> +
>> +		index = of_property_match_string(du_node, "reg-names", name);
>> +		if (index < 0)
>> +			continue;
>> +
>> +		of_address_to_resource(du_node, index, &lvds->res);
>> +	}
>> +
>> +	/* Parse and apply the overlay. This will resolve phandles. */
>> +	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
>> +				       match->compatible);
>> +	if (ret < 0)
>> +		goto done;
>> +
>> +	/* Patch the newly created LVDS encoder nodes. */
>> +	for_each_child_of_node(soc_node, lvds_node) {
>> +		struct resource res;
>> +
>> +		if (!of_device_is_compatible(lvds_node, compatible))
>> +			continue;
>> +
>> +		/* Locate the lvds_data entry based on the resource start. */
>> +		ret = of_address_to_resource(lvds_node, 0, &res);
>> +		if (ret < 0)
>> +			continue;
>> +
>> +		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
>> +			if (lvds_data[i].res.start == res.start)
>> +				break;
>> +		}
>> +
>> +		if (i == ARRAY_SIZE(lvds_data))
>> +			continue;
>> +
>> +		/* Patch the LVDS encoder. */
>> +		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
>> +					  lvds_data[i].local,
>> +					  lvds_data[i].remote);
>> +	}
>> +
>> +done:
>> +	for (i = 0; i < info->num_lvds; ++i) {
>> +		of_node_put(lvds_data[i].clkspec.np);
>> +		of_node_put(lvds_data[i].local);
>> +		of_node_put(lvds_data[i].remote);
>> +	}
>> +
>> +	of_node_put(soc_node);
>> +	of_node_put(du_node);
>> +}
>> +
>> +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..c2e65a727e91
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * 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;
>> +
>> +#ifdef CONFIG_DRM_RCAR_LVDS
>> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
>> +#else
>> +static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
>> +#endif /* CONFIG_DRM_RCAR_LVDS */
>> +
>> +#endif /* __RCAR_DU_OF_H__ */
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
>> new file mode 100644
>> index 000000000000..f118a6ae7782
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
>> @@ -0,0 +1,79 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7790-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +
>> +			lvds@feb94000 {
>> +				compatible = "renesas,r8a7790-lvds";
>> +				reg = <0 0xfeb94000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds1_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds1_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +			port@2 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds1_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>> new file mode 100644
>> index 000000000000..7d865727928c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7791-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>> new file mode 100644
>> index 000000000000..bb263711834d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7793-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>> new file mode 100644
>> index 000000000000..9bbf7c9e5ce4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/soc";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7795-lvds";
>> +				reg = <0 0xfeb90000 0 0x14>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/soc/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@3 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
>> new file mode 100644
>> index 000000000000..d16f3e9e08ab
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/soc";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7796-lvds";
>> +				reg = <0 0xfeb90000 0 0x14>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/soc/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@3 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>>
> 
> 

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-24 22:42       ` Frank Rowand
  0 siblings, 0 replies; 38+ messages in thread
From: Frank Rowand @ 2018-02-24 22:42 UTC (permalink / raw)
  To: Laurent Pinchart, dri-devel; +Cc: linux-renesas-soc, Rob Herring, devicetree

On 02/22/18 14:10, Frank Rowand wrote:
> Hi Laurent, Rob,
> 
> Thanks for the prompt spin to address my concerns.  There are some small
> technical issues.
> 
> I did not read the v3 patch until today.  v3 through v6 are still using the
> old overlay apply method which uses an expanded device tree as input.
> 
> Rob, I don't see my overlay patches in you for-next branch, and I have
> not seen an "Applied" message from you.  What is the status of the
> overlay patches?
> 
> Comments in the patch below.
> 
> 
> On 02/22/18 05:13, 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.
>>
>> 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 v5:
>>
>> - Use a private copy of rcar_du_of_changeset_add_property()
>>
>> Changes since v3:
>>
>> - Use the OF changeset API
>> - Use of_graph_get_endpoint_by_regs()
>> - Replace hardcoded constants by sizeof()
>>
>> Changes since v2:
>>
>> - Update the SPDX headers to use C-style comments in header files
>> - Removed the manually created __local_fixups__ node
>> - Perform manual fixups on live DT instead of overlay
>>
>> 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                   |   7 +-
>>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++++++++
>>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
>>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
>>  9 files changed, 661 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_r8a7790.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.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..86b337b4be5d 100644
>> --- a/drivers/gpu/drm/rcar-du/Makefile
>> +++ b/drivers/gpu/drm/rcar-du/Makefile
>> @@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.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.o \
>> +					   rcar_du_of_lvds_r8a7790.dtb.o \
>> +					   rcar_du_of_lvds_r8a7791.dtb.o \
>> +					   rcar_du_of_lvds_r8a7793.dtb.o \
>> +					   rcar_du_of_lvds_r8a7795.dtb.o \
>> +					   rcar_du_of_lvds_r8a7796.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..ac442ddfed16
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
>> @@ -0,0 +1,342 @@
>> +// 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"
>> +
>> +/* -----------------------------------------------------------------------------
>> + * Generic Overlay Handling
>> + */
>> +
>> +struct rcar_du_of_overlay {
>> +	const char *compatible;
>> +	void *begin;
>> +	void *end;
>> +};
>> +
>> +#define RCAR_DU_OF_DTB(type, soc)					\
>> +	extern char __dtb_rcar_du_of_##type##_##soc##_begin[];		\
>> +	extern char __dtb_rcar_du_of_##type##_##soc##_end[]
>> +
>> +#define RCAR_DU_OF_OVERLAY(type, soc)					\
>> +	{								\
>> +		.compatible = "renesas,du-" #soc,			\
>> +		.begin = __dtb_rcar_du_of_##type##_##soc##_begin,	\
>> +		.end = __dtb_rcar_du_of_##type##_##soc##_end,		\
>> +	}
>> +
>> +static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs,
>> +					   const char *compatible)
>> +{
>> +	const struct rcar_du_of_overlay *dtb = NULL;
>> +	struct device_node *node = NULL;
>> +	unsigned int i;
>> +	int ovcs_id;
>> +	void *data;
>> +	void *mem;
>> +	int ret;
>> +
>> +	for (i = 0; dtbs[i].compatible; ++i) {
>> +		if (!strcmp(dtbs[i].compatible, compatible)) {
>> +			dtb = &dtbs[i];
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!dtb)
>> +		return -ENODEV;
> 

I was trying to avoid reviewing this little block of code, because it
meant spending the time to do the research to verify my memory.  I did
the research, so here are the comments...

> __If__ my overlay patches are accepted, this block:
> 
>> +
>> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
>> +	if (!mem) {

>> +		ret = -ENOMEM;

                kfree(data);

This could be done at the tail of the function if you prefer, but
it is easier for me to put it here to show which case it is ok
to kfree().  And if doing the kfree() here, may as well just
return -ENOMEM here instead of going to done.

>> +		goto done;
>> +	}
>> +
>> +	ovcs_id = 0;
>> +	ret = of_overlay_apply(node, &ovcs_id);
>> +
>> +done:

Do not do the of_node_put() or the kfree()s here.  The live
devicetree and the overlay changeset have pointers into them.

Some error values from of_overlay_apply() do allow you to do some
freeing, but since this is at most a temporary piece of code, it
isn't worth all the complexity of trying to figure that out.  The
implications of the various return values from of_overlay_apply()
are a bit of a hairball.

>> +	of_node_put(node);
>> +	kfree(data);
>> +	kfree(mem);

-Frank


> 
> becomes:
> 
> 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> 
> If my overlay patches do not exist, there are other small errors
> in the code block above.  I'll ignore them for the moment.
> 
> A quick scan of the rest of the code looks OK.  I'll read through it
> more carefully, but wanted to get this reply out without further
> delay.
> 
> -Frank
> 
> 
>> +
>> +	return ret;
>> +}
>> +
>> +static int __init rcar_du_of_add_property(struct of_changeset *ocs,
>> +					  struct device_node *np,
>> +					  const char *name, const void *value,
>> +					  int length)
>> +{
>> +	struct property *prop;
>> +	int ret = -ENOMEM;
>> +
>> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
>> +	if (!prop)
>> +		return -ENOMEM;
>> +
>> +	prop->name = kstrdup(name, GFP_KERNEL);
>> +	if (!prop->name)
>> +		goto out_err;
>> +
>> +	prop->value = kmemdup(value, length, GFP_KERNEL);
>> +	if (!prop->value)
>> +		goto out_err;
>> +
>> +	of_property_set_flag(prop, OF_DYNAMIC);
>> +
>> +	prop->length = length;
>> +
>> +	ret = of_changeset_add_property(ocs, np, prop);
>> +	if (!ret)
>> +		return 0;
>> +
>> +out_err:
>> +	kfree(prop->value);
>> +	kfree(prop->name);
>> +	kfree(prop);
>> +	return ret;
>> +}
>> +
>> +/* -----------------------------------------------------------------------------
>> + * LVDS Overlays
>> + */
>> +
>> +RCAR_DU_OF_DTB(lvds, r8a7790);
>> +RCAR_DU_OF_DTB(lvds, r8a7791);
>> +RCAR_DU_OF_DTB(lvds, r8a7793);
>> +RCAR_DU_OF_DTB(lvds, r8a7795);
>> +RCAR_DU_OF_DTB(lvds, r8a7796);
>> +
>> +static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = {
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7790),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7791),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7793),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7795),
>> +	RCAR_DU_OF_OVERLAY(lvds, r8a7796),
>> +	{ /* Sentinel */ },
>> +};
>> +
>> +static struct of_changeset rcar_du_lvds_changeset;
>> +
>> +static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds,
>> +					     const struct of_phandle_args *clk,
>> +					     struct device_node *local,
>> +					     struct device_node *remote)
>> +{
>> +	unsigned int psize;
>> +	unsigned int i;
>> +	__be32 value[4];
>> +	int ret;
>> +
>> +	/*
>> +	 * Set the LVDS clocks property. This can't be performed by the overlay
>> +	 * as the structure of the clock specifier has changed over time, and we
>> +	 * don't know at compile time which binding version the system we will
>> +	 * run on uses.
>> +	 */
>> +	if (clk->args_count >= ARRAY_SIZE(value) - 1)
>> +		return;
>> +
>> +	of_changeset_init(&rcar_du_lvds_changeset);
>> +
>> +	value[0] = cpu_to_be32(clk->np->phandle);
>> +	for (i = 0; i < clk->args_count; ++i)
>> +		value[i + 1] = cpu_to_be32(clk->args[i]);
>> +
>> +	psize = (clk->args_count + 1) * 4;
>> +	ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds,
>> +				      "clocks", value, psize);
>> +	if (ret < 0)
>> +		goto done;
>> +
>> +	/*
>> +	 * 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. This can't be performed by the overlay: on the input side the
>> +	 * overlay would contain a phandle for the DU LVDS output port that
>> +	 * would clash with the system DT, and on the output side the connection
>> +	 * is board-specific.
>> +	 */
>> +	value[0] = cpu_to_be32(local->phandle);
>> +	value[1] = cpu_to_be32(remote->phandle);
>> +
>> +	for (i = 0; i < 2; ++i) {
>> +		struct device_node *endpoint;
>> +
>> +		endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0);
>> +		if (!endpoint) {
>> +			ret = -EINVAL;
>> +			goto done;
>> +		}
>> +
>> +		ret = rcar_du_of_add_property(&rcar_du_lvds_changeset,
>> +					      endpoint, "remote-endpoint",
>> +					      &value[i], sizeof(value[i]));
>> +		of_node_put(endpoint);
>> +		if (ret < 0)
>> +			goto done;
>> +	}
>> +
>> +	ret = of_changeset_apply(&rcar_du_lvds_changeset);
>> +
>> +done:
>> +	if (ret < 0)
>> +		of_changeset_destroy(&rcar_du_lvds_changeset);
>> +}
>> +
>> +struct lvds_of_data {
>> +	struct resource res;
>> +	struct of_phandle_args clkspec;
>> +	struct device_node *local;
>> +	struct device_node *remote;
>> +};
>> +
>> +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 lvds_of_data lvds_data[2] = { };
>> +	struct device_node *lvds_node;
>> +	struct device_node *soc_node;
>> +	struct device_node *du_node;
>> +	char compatible[21];
>> +	const char *soc_name;
>> +	unsigned int i;
>> +	int ret;
>> +
>> +	/* Get the DU node and exit if not present or disabled. */
>> +	du_node = of_find_matching_node_and_match(NULL, of_ids, &match);
>> +	if (!du_node || !of_device_is_available(du_node)) {
>> +		of_node_put(du_node);
>> +		return;
>> +	}
>> +
>> +	info = match->data;
>> +	soc_node = of_get_parent(du_node);
>> +
>> +	if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data)))
>> +		goto done;
>> +
>> +	/*
>> +	 * Skip if the LVDS nodes already exists.
>> +	 *
>> +	 * The nodes are searched based on the compatible string, which we
>> +	 * construct from the SoC name found in the DU compatible string. As a
>> +	 * match has been found we know the compatible string matches the
>> +	 * expected format and can thus skip some of the string manipulation
>> +	 * normal safety checks.
>> +	 */
>> +	soc_name = strchr(match->compatible, '-') + 1;
>> +	sprintf(compatible, "renesas,%s-lvds", soc_name);
>> +	lvds_node = of_find_compatible_node(NULL, NULL, compatible);
>> +	if (lvds_node) {
>> +		of_node_put(lvds_node);
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * Parse the DU node and store the register specifier, the clock
>> +	 * specifier and the local and remote endpoint of the LVDS link for
>> +	 * later use.
>> +	 */
>> +	for (i = 0; i < info->num_lvds; ++i) {
>> +		struct lvds_of_data *lvds = &lvds_data[i];
>> +		unsigned int port;
>> +		char name[7];
>> +		int index;
>> +
>> +		sprintf(name, "lvds.%u", i);
>> +		index = of_property_match_string(du_node, "clock-names", name);
>> +		if (index < 0)
>> +			continue;
>> +
>> +		ret = of_parse_phandle_with_args(du_node, "clocks",
>> +						 "#clock-cells", index,
>> +						 &lvds->clkspec);
>> +		if (ret < 0)
>> +			continue;
>> +
>> +		port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
>> +
>> +		lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0);
>> +		if (!lvds->local)
>> +			continue;
>> +
>> +		lvds->remote = of_graph_get_remote_endpoint(lvds->local);
>> +		if (!lvds->remote)
>> +			continue;
>> +
>> +		index = of_property_match_string(du_node, "reg-names", name);
>> +		if (index < 0)
>> +			continue;
>> +
>> +		of_address_to_resource(du_node, index, &lvds->res);
>> +	}
>> +
>> +	/* Parse and apply the overlay. This will resolve phandles. */
>> +	ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays,
>> +				       match->compatible);
>> +	if (ret < 0)
>> +		goto done;
>> +
>> +	/* Patch the newly created LVDS encoder nodes. */
>> +	for_each_child_of_node(soc_node, lvds_node) {
>> +		struct resource res;
>> +
>> +		if (!of_device_is_compatible(lvds_node, compatible))
>> +			continue;
>> +
>> +		/* Locate the lvds_data entry based on the resource start. */
>> +		ret = of_address_to_resource(lvds_node, 0, &res);
>> +		if (ret < 0)
>> +			continue;
>> +
>> +		for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) {
>> +			if (lvds_data[i].res.start == res.start)
>> +				break;
>> +		}
>> +
>> +		if (i == ARRAY_SIZE(lvds_data))
>> +			continue;
>> +
>> +		/* Patch the LVDS encoder. */
>> +		rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec,
>> +					  lvds_data[i].local,
>> +					  lvds_data[i].remote);
>> +	}
>> +
>> +done:
>> +	for (i = 0; i < info->num_lvds; ++i) {
>> +		of_node_put(lvds_data[i].clkspec.np);
>> +		of_node_put(lvds_data[i].local);
>> +		of_node_put(lvds_data[i].remote);
>> +	}
>> +
>> +	of_node_put(soc_node);
>> +	of_node_put(du_node);
>> +}
>> +
>> +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..c2e65a727e91
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * 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;
>> +
>> +#ifdef CONFIG_DRM_RCAR_LVDS
>> +void __init rcar_du_of_init(const struct of_device_id *of_ids);
>> +#else
>> +static inline void rcar_du_of_init(const struct of_device_id *of_ids) { }
>> +#endif /* CONFIG_DRM_RCAR_LVDS */
>> +
>> +#endif /* __RCAR_DU_OF_H__ */
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
>> new file mode 100644
>> index 000000000000..f118a6ae7782
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
>> @@ -0,0 +1,79 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7790-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +
>> +			lvds@feb94000 {
>> +				compatible = "renesas,r8a7790-lvds";
>> +				reg = <0 0xfeb94000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds1_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds1_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +			port@2 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds1_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>> new file mode 100644
>> index 000000000000..7d865727928c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7791-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>> new file mode 100644
>> index 000000000000..bb263711834d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7793-lvds";
>> +				reg = <0 0xfeb90000 0 0x1c>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@1 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>> new file mode 100644
>> index 000000000000..9bbf7c9e5ce4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/soc";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7795-lvds";
>> +				reg = <0 0xfeb90000 0 0x14>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/soc/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@3 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
>> new file mode 100644
>> index 000000000000..d16f3e9e08ab
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
>> @@ -0,0 +1,53 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796
>> + *
>> + * Copyright (C) 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> + *
>> + * Based on work from Jyri Sarha <jsarha@ti.com>
>> + * Copyright (C) 2015 Texas Instruments
>> + */
>> +
>> +/dts-v1/;
>> +/plugin/;
>> +/ {
>> +	fragment@0 {
>> +		target-path = "/soc";
>> +		__overlay__ {
>> +			#address-cells = <2>;
>> +			#size-cells = <2>;
>> +
>> +			lvds@feb90000 {
>> +				compatible = "renesas,r8a7796-lvds";
>> +				reg = <0 0xfeb90000 0 0x14>;
>> +
>> +				ports {
>> +					#address-cells = <1>;
>> +					#size-cells = <0>;
>> +
>> +					port@0 {
>> +						reg = <0>;
>> +						lvds0_input: endpoint {
>> +						};
>> +					};
>> +					port@1 {
>> +						reg = <1>;
>> +						lvds0_out: endpoint {
>> +						};
>> +					};
>> +				};
>> +			};
>> +		};
>> +	};
>> +
>> +	fragment@1 {
>> +		target-path = "/soc/display@feb00000/ports";
>> +		__overlay__ {
>> +			port@3 {
>> +				endpoint {
>> +					remote-endpoint = <&lvds0_input>;
>> +				};
>> +			};
>> +		};
>> +	};
>> +};
>>
> 
> 

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
  2018-02-24 22:42       ` Frank Rowand
@ 2018-02-25 11:33         ` Laurent Pinchart
  -1 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-25 11:33 UTC (permalink / raw)
  To: Frank Rowand; +Cc: linux-renesas-soc, Laurent Pinchart, dri-devel, devicetree

Hi Frank,

On Sunday, 25 February 2018 00:42:47 EET Frank Rowand wrote:
> On 02/22/18 14:10, Frank Rowand wrote:
> > Hi Laurent, Rob,
> > 
> > Thanks for the prompt spin to address my concerns.  There are some small
> > technical issues.
> > 
> > I did not read the v3 patch until today.  v3 through v6 are still using
> > the old overlay apply method which uses an expanded device tree as input.
> > 
> > Rob, I don't see my overlay patches in you for-next branch, and I have
> > not seen an "Applied" message from you.  What is the status of the
> > overlay patches?
> > 
> > Comments in the patch below.
> > 
> > On 02/22/18 05:13, 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.
> >> 
> >> 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 v5:
> >> 
> >> - Use a private copy of rcar_du_of_changeset_add_property()
> >> 
> >> Changes since v3:
> >> 
> >> - Use the OF changeset API
> >> - Use of_graph_get_endpoint_by_regs()
> >> - Replace hardcoded constants by sizeof()
> >> 
> >> Changes since v2:
> >> 
> >> - Update the SPDX headers to use C-style comments in header files
> >> - Removed the manually created __local_fixups__ node
> >> - Perform manual fixups on live DT instead of overlay
> >> 
> >> 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                   |   7 +-
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>  9 files changed, 661 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_r8a7790.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts

[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..ac442ddfed16
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c

[snip]

> >> +static int __init rcar_du_of_apply_overlay(const struct
> >> rcar_du_of_overlay *dtbs,
> >> +					   const char *compatible)
> >> +{
> >> +	const struct rcar_du_of_overlay *dtb = NULL;
> >> +	struct device_node *node = NULL;
> >> +	unsigned int i;
> >> +	int ovcs_id;
> >> +	void *data;
> >> +	void *mem;
> >> +	int ret;
> >> +
> >> +	for (i = 0; dtbs[i].compatible; ++i) {
> >> +		if (!strcmp(dtbs[i].compatible, compatible)) {
> >> +			dtb = &dtbs[i];
> >> +			break;
> >> +		}
> >> +	}
> >> +
> >> +	if (!dtb)
> >> +		return -ENODEV;
> 
> I was trying to avoid reviewing this little block of code, because it
> meant spending the time to do the research to verify my memory.  I did
> the research, so here are the comments...

Thank you.

> > __If__ my overlay patches are accepted, this block:
> >> +
> >> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> >> +	if (!data)
> >> +		return -ENOMEM;
> >> +
> >> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> >> +	if (!mem) {
> >> 
> >> +		ret = -ENOMEM;
> 
>                 kfree(data);
> 
> This could be done at the tail of the function if you prefer, but
> it is easier for me to put it here to show which case it is ok
> to kfree().  And if doing the kfree() here, may as well just
> return -ENOMEM here instead of going to done.
> 
> >> +		goto done;
> >> +	}
> >> +
> >> +	ovcs_id = 0;
> >> +	ret = of_overlay_apply(node, &ovcs_id);
> >> +
> 
> >> +done:
> Do not do the of_node_put() or the kfree()s here.  The live
> devicetree and the overlay changeset have pointers into them.
> 
> Some error values from of_overlay_apply() do allow you to do some
> freeing, but since this is at most a temporary piece of code, it
> isn't worth all the complexity of trying to figure that out.  The
> implications of the various return values from of_overlay_apply()
> are a bit of a hairball.
> 
> >> +	of_node_put(node);
> >> +	kfree(data);
> >> +	kfree(mem);

OK, I'll remove the error handling code here and add a kfree(data) if 
of_fdt_unflatten_tree() fails. Thank you.

> > becomes:
> > 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> > 
> > If my overlay patches do not exist, there are other small errors
> > in the code block above.  I'll ignore them for the moment.
> > 
> > A quick scan of the rest of the code looks OK.  I'll read through it
> > more carefully, but wanted to get this reply out without further
> > delay.
> > 
> > -Frank
> > 
> >> +
> >> +	return ret;
> >> +}

[snip]

-- 
Regards,

Laurent Pinchart

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

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

* Re: [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
@ 2018-02-25 11:33         ` Laurent Pinchart
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Pinchart @ 2018-02-25 11:33 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Rob Herring, devicetree

Hi Frank,

On Sunday, 25 February 2018 00:42:47 EET Frank Rowand wrote:
> On 02/22/18 14:10, Frank Rowand wrote:
> > Hi Laurent, Rob,
> > 
> > Thanks for the prompt spin to address my concerns.  There are some small
> > technical issues.
> > 
> > I did not read the v3 patch until today.  v3 through v6 are still using
> > the old overlay apply method which uses an expanded device tree as input.
> > 
> > Rob, I don't see my overlay patches in you for-next branch, and I have
> > not seen an "Applied" message from you.  What is the status of the
> > overlay patches?
> > 
> > Comments in the patch below.
> > 
> > On 02/22/18 05:13, 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.
> >> 
> >> 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 v5:
> >> 
> >> - Use a private copy of rcar_du_of_changeset_add_property()
> >> 
> >> Changes since v3:
> >> 
> >> - Use the OF changeset API
> >> - Use of_graph_get_endpoint_by_regs()
> >> - Replace hardcoded constants by sizeof()
> >> 
> >> Changes since v2:
> >> 
> >> - Update the SPDX headers to use C-style comments in header files
> >> - Removed the manually created __local_fixups__ node
> >> - Perform manual fixups on live DT instead of overlay
> >> 
> >> 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                   |   7 +-
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.c               | 342 +++++++++++++++
> >>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  79 +++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  53 ++++
> >>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  53 ++++
> >>  9 files changed, 661 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_r8a7790.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> >>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts

[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..ac442ddfed16
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c

[snip]

> >> +static int __init rcar_du_of_apply_overlay(const struct
> >> rcar_du_of_overlay *dtbs,
> >> +					   const char *compatible)
> >> +{
> >> +	const struct rcar_du_of_overlay *dtb = NULL;
> >> +	struct device_node *node = NULL;
> >> +	unsigned int i;
> >> +	int ovcs_id;
> >> +	void *data;
> >> +	void *mem;
> >> +	int ret;
> >> +
> >> +	for (i = 0; dtbs[i].compatible; ++i) {
> >> +		if (!strcmp(dtbs[i].compatible, compatible)) {
> >> +			dtb = &dtbs[i];
> >> +			break;
> >> +		}
> >> +	}
> >> +
> >> +	if (!dtb)
> >> +		return -ENODEV;
> 
> I was trying to avoid reviewing this little block of code, because it
> meant spending the time to do the research to verify my memory.  I did
> the research, so here are the comments...

Thank you.

> > __If__ my overlay patches are accepted, this block:
> >> +
> >> +	data = kmemdup(dtb->begin, dtb->end - dtb->begin, GFP_KERNEL);
> >> +	if (!data)
> >> +		return -ENOMEM;
> >> +
> >> +	mem = of_fdt_unflatten_tree(data, NULL, &node);
> >> +	if (!mem) {
> >> 
> >> +		ret = -ENOMEM;
> 
>                 kfree(data);
> 
> This could be done at the tail of the function if you prefer, but
> it is easier for me to put it here to show which case it is ok
> to kfree().  And if doing the kfree() here, may as well just
> return -ENOMEM here instead of going to done.
> 
> >> +		goto done;
> >> +	}
> >> +
> >> +	ovcs_id = 0;
> >> +	ret = of_overlay_apply(node, &ovcs_id);
> >> +
> 
> >> +done:
> Do not do the of_node_put() or the kfree()s here.  The live
> devicetree and the overlay changeset have pointers into them.
> 
> Some error values from of_overlay_apply() do allow you to do some
> freeing, but since this is at most a temporary piece of code, it
> isn't worth all the complexity of trying to figure that out.  The
> implications of the various return values from of_overlay_apply()
> are a bit of a hairball.
> 
> >> +	of_node_put(node);
> >> +	kfree(data);
> >> +	kfree(mem);

OK, I'll remove the error handling code here and add a kfree(data) if 
of_fdt_unflatten_tree() fails. Thank you.

> > becomes:
> > 	ret = of_overlay_fdt_apply(dtb->begin, &ovcs_id);
> > 
> > If my overlay patches do not exist, there are other small errors
> > in the code block above.  I'll ignore them for the moment.
> > 
> > A quick scan of the rest of the code looks OK.  I'll read through it
> > more carefully, but wanted to get this reply out without further
> > delay.
> > 
> > -Frank
> > 
> >> +
> >> +	return ret;
> >> +}

[snip]

-- 
Regards,

Laurent Pinchart

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

end of thread, other threads:[~2018-02-25 11:33 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-22 13:13 [PATCH v6 0/4] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
2018-02-22 13:13 ` Laurent Pinchart
2018-02-22 13:13 ` [PATCH v6 1/4] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
2018-02-22 13:13   ` Laurent Pinchart
2018-02-22 13:37   ` Niklas Söderlund
2018-02-22 13:37     ` Niklas Söderlund
2018-02-22 13:13 ` [PATCH v6 2/4] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings Laurent Pinchart
2018-02-22 13:13   ` Laurent Pinchart
2018-02-22 13:40   ` Niklas Söderlund
2018-02-22 13:40     ` Niklas Söderlund
2018-02-22 13:13 ` [PATCH v6 3/4] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
2018-02-22 13:13   ` Laurent Pinchart
2018-02-22 22:10   ` Frank Rowand
2018-02-22 22:10     ` Frank Rowand
2018-02-22 22:22     ` Laurent Pinchart
2018-02-22 22:22       ` Laurent Pinchart
2018-02-23  2:38     ` Frank Rowand
2018-02-23  2:38       ` Frank Rowand
2018-02-23  9:00       ` Laurent Pinchart
2018-02-23  9:00         ` Laurent Pinchart
2018-02-23 19:43         ` Frank Rowand
2018-02-23 19:43           ` Frank Rowand
2018-02-23 19:56           ` Laurent Pinchart
2018-02-23 19:56             ` Laurent Pinchart
2018-02-24 22:09             ` Frank Rowand
2018-02-24 22:09               ` Frank Rowand
2018-02-24 22:42     ` Frank Rowand
2018-02-24 22:42       ` Frank Rowand
2018-02-25 11:33       ` Laurent Pinchart
2018-02-25 11:33         ` Laurent Pinchart
2018-02-22 13:13 ` [PATCH v6 4/4] drm: rcar-du: Convert LVDS encoder code to bridge driver Laurent Pinchart
2018-02-22 13:13   ` Laurent Pinchart
2018-02-22 14:49   ` Niklas Söderlund
2018-02-22 14:49     ` Niklas Söderlund
2018-02-22 20:23 ` [PATCH v6 0/4] R-Car DU: Convert LVDS " Frank Rowand
2018-02-22 20:23   ` Frank Rowand
2018-02-22 20:27   ` Laurent Pinchart
2018-02-22 20:27     ` Laurent Pinchart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.