diff mbox

[v3,03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes

Message ID 20180215000415.19077-4-laurent.pinchart+renesas@ideasonboard.com (mailing list archive)
State New, archived
Headers show

Commit Message

Laurent Pinchart Feb. 15, 2018, 12:04 a.m. UTC
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 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               | 374 +++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  81 +++++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  55 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  55 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  55 +++
 .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  55 +++
 9 files changed, 703 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

Comments

Geert Uytterhoeven Feb. 15, 2018, 9:18 a.m. UTC | #1
Hi Laurent,

On Thu, Feb 15, 2018 at 1:04 AM, Laurent Pinchart
<laurent.pinchart+renesas@ideasonboard.com> wrote:
> The internal LVDS encoders now have their own DT bindings. Before
> switching the driver infrastructure to those new bindings, implement
> backward-compatibility through live DT patching.
>
> 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>

Thanks for your patch!

> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> @@ -0,0 +1,81 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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";

Does this work now there can be an "soc" subnode, too?

Your code obtains the right parent:

    soc_node = of_get_parent(du_node);

but the overlay is applied without considering that, if I'm not mistaken.

Gr{oetje,eeting}s,

                        Geert

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

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Laurent Pinchart Feb. 15, 2018, 11:03 a.m. UTC | #2
Hi Geert,

On Thursday, 15 February 2018 11:18:25 EET Geert Uytterhoeven wrote:
> On Thu, Feb 15, 2018 at 1:04 AM, 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>
> 
> Thanks for your patch!
> 
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> > @@ -0,0 +1,81 @@
> > +// 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
> > + */
> > +
> > +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> > +
> > +/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";
> 
> Does this work now there can be an "soc" subnode, too?
> 
> Your code obtains the right parent:
> 
>     soc_node = of_get_parent(du_node);
> 
> but the overlay is applied without considering that, if I'm not mistaken.

Correct, and as I can't modify the target-path in the overlay dynamically 
anymore, I can't take this into account. I could duplicate the r8a7790 and 
r8a7791 overlays in two versions to handle this, but as the soc subnode isn't 
in mainline yet, I'd rather get this patch series merged with the current 
implementation in v4.17 to not have to handle this issue :-)
Geert Uytterhoeven Feb. 15, 2018, 11:32 a.m. UTC | #3
Hi Laurent,

On Thu, Feb 15, 2018 at 12:03 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Thursday, 15 February 2018 11:18:25 EET Geert Uytterhoeven wrote:
>> On Thu, Feb 15, 2018 at 1:04 AM, 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>
>>
>> Thanks for your patch!
>>
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
>> > @@ -0,0 +1,81 @@
>> > +// 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
>> > + */
>> > +
>> > +#include <dt-bindings/clock/renesas-cpg-mssr.h>
>> > +
>> > +/dts-v1/;
>> > +/plugin/;
>> > +/ {

>> > +       fragment@1 {
>> > +               target-path = "/display@feb00000/ports";
>>
>> Does this work now there can be an "soc" subnode, too?
>>
>> Your code obtains the right parent:
>>
>>     soc_node = of_get_parent(du_node);
>>
>> but the overlay is applied without considering that, if I'm not mistaken.
>
> Correct, and as I can't modify the target-path in the overlay dynamically
> anymore, I can't take this into account. I could duplicate the r8a7790 and
> r8a7791 overlays in two versions to handle this, but as the soc subnode isn't
> in mainline yet, I'd rather get this patch series merged with the current
> implementation in v4.17 to not have to handle this issue :-)

That's of course an option.

Gr{oetje,eeting}s,

                        Geert

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

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Rob Herring Feb. 20, 2018, 12:54 a.m. UTC | #4
On Wed, Feb 14, 2018 at 6:04 PM, Laurent Pinchart
<laurent.pinchart+renesas@ideasonboard.com> wrote:
> The internal LVDS encoders now have their own DT bindings. Before
> switching the driver infrastructure to those new bindings, implement
> backward-compatibility through live DT patching.
>
> 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 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

Generally looks fine to me. A few things below.
>
> 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               | 374 +++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_of.h               |  20 ++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  81 +++++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  55 +++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  55 +++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  55 +++
>  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  55 +++
>  9 files changed, 703 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..141f6eda6e98
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> @@ -0,0 +1,374 @@
> +// 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 struct device_node __init *
> +rcar_du_of_find_node_by_path(struct device_node *parent, const char *path)
> +{

I guess I never followed up on the last version. I think a wrapper
around __of_find_node_by_path would work for you here. It can start at
any level. Though maybe it is not needed. See below.

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

So, were you going to revive Pantelis' patch or move this to the core?

> +{
> +       struct property *prop;
> +
> +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +       if (!prop)
> +               return -ENOMEM;
> +
> +       prop->name = kstrdup(name, GFP_KERNEL);
> +       prop->value = kmemdup(value, length, GFP_KERNEL);
> +       prop->length = length;
> +
> +       if (!prop->name || !prop->value) {
> +               kfree(prop->name);
> +               kfree(prop->value);
> +               kfree(prop);
> +               return -ENOMEM;
> +       }
> +
> +       of_property_set_flag(prop, OF_DYNAMIC);
> +
> +       prop->next = np->properties;
> +       np->properties = prop;
> +
> +       return 0;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * 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 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)
> +{
> +       struct device_node *endpoints[2];
> +       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;
> +
> +       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(lvds, "clocks", value, psize);
> +       if (ret < 0)
> +               return;
> +
> +       /*
> +        * 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.
> +        */
> +       endpoints[0] = rcar_du_of_find_node_by_path(lvds,
> +                                                   "/ports/port@0/endpoint");

of_graph_get_endpoint_by_regs() should work here instead or am I
missing something?

> +       endpoints[1] = rcar_du_of_find_node_by_path(lvds,
> +                                                   "/ports/port@1/endpoint");
> +       if (!endpoints[0] || !endpoints[1])
> +               return;
> +
> +       value[0] = cpu_to_be32(local->phandle);
> +       ret = rcar_du_of_add_property(endpoints[0], "remote-endpoint",
> +                                     value, 4);

s/4/sizeof(__be32)/

> +       if (ret < 0)
> +               goto done;
> +
> +       value[0] = cpu_to_be32(remote->phandle);
> +       ret = rcar_du_of_add_property(endpoints[1], "remote-endpoint",
> +                                     value, 4);
> +       if (ret < 0)
> +               goto done;
> +
> +done:
> +       of_node_put(endpoints[0]);
> +       of_node_put(endpoints[1]);
> +}
> +
> +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..6ebb355b652a
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
> @@ -0,0 +1,81 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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..601982bba27d
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
> @@ -0,0 +1,55 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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..1c535954a529
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
> @@ -0,0 +1,55 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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..44e52101ef05
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
> @@ -0,0 +1,55 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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..8f45ebe140bd
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
> @@ -0,0 +1,55 @@
> +// 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
> + */
> +
> +#include <dt-bindings/clock/renesas-cpg-mssr.h>
> +
> +/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
>
Laurent Pinchart Feb. 20, 2018, 9:15 a.m. UTC | #5
Hi Rob,

On Tuesday, 20 February 2018 02:54:00 EET Rob Herring wrote:
> On Wed, Feb 14, 2018 at 6:04 PM, Laurent Pinchart wrote:
> > The internal LVDS encoders now have their own DT bindings. Before
> > switching the driver infrastructure to those new bindings, implement
> > backward-compatibility through live DT patching.
> > 
> > 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 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
> 
> Generally looks fine to me. A few things below.
> 
> > 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               | 374
> >  +++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_of.h              
> >  |  20 ++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts    |  81 +++++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts    |  55 +++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts    |  55 +++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts    |  55 +++
> >  .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts    |  55 +++
> >  9 files changed, 703 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..141f6eda6e98
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c

[snip]

> > +static struct device_node __init *
> > +rcar_du_of_find_node_by_path(struct device_node *parent, const char
> > *path)
> > +{
> 
> I guess I never followed up on the last version. I think a wrapper
> around __of_find_node_by_path would work for you here. It can start at
> any level. Though maybe it is not needed. See below.

You're right, I won't need this function anymore, so I'll drop it. I think 
looking up a node by path starting at a given parent would still be useful, 
but there's no need to add a function without a user.

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

Do you have a pointer to that patch ?

> > +{
> > +       struct property *prop;
> > +
> > +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> > +       if (!prop)
> > +               return -ENOMEM;
> > +
> > +       prop->name = kstrdup(name, GFP_KERNEL);
> > +       prop->value = kmemdup(value, length, GFP_KERNEL);
> > +       prop->length = length;
> > +
> > +       if (!prop->name || !prop->value) {
> > +               kfree(prop->name);
> > +               kfree(prop->value);
> > +               kfree(prop);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       of_property_set_flag(prop, OF_DYNAMIC);
> > +
> > +       prop->next = np->properties;
> > +       np->properties = prop;
> > +
> > +       return 0;
> > +}

[snip]

> > +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)
> > +{
> > +       struct device_node *endpoints[2];
> > +       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;
> > +
> > +       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(lvds, "clocks", value, psize);
> > +       if (ret < 0)
> > +               return;
> > +
> > +       /*
> > +        * 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.
> > +        */
> > +       endpoints[0] = rcar_du_of_find_node_by_path(lvds,
> > +                                                  
> > "/ports/port@0/endpoint");
> 
> of_graph_get_endpoint_by_regs() should work here instead or am I
> missing something?

Good point. The patch series started with a need for a node lookup by path 
function to patch the overlay before applying it, and I failed to see that the 
function wasn't needed anymore in this new version. I've successfully tested 
of_graph_get_endpoint_by_regs(), I'll use that in v4.

> > +       endpoints[1] = rcar_du_of_find_node_by_path(lvds,
> > +                                                  
> > "/ports/port@1/endpoint"); +       if (!endpoints[0] || !endpoints[1])
> > +               return;
> > +
> > +       value[0] = cpu_to_be32(local->phandle);
> > +       ret = rcar_du_of_add_property(endpoints[0], "remote-endpoint",
> > +                                     value, 4);
> 
> s/4/sizeof(__be32)/

Will fix in v4.

> > +       if (ret < 0)
> > +               goto done;
> > +
> > +       value[0] = cpu_to_be32(remote->phandle);
> > +       ret = rcar_du_of_add_property(endpoints[1], "remote-endpoint",
> > +                                     value, 4);
> > +       if (ret < 0)
> > +               goto done;
> > +
> > +done:
> > +       of_node_put(endpoints[0]);
> > +       of_node_put(endpoints[1]);
> > +}

[snip]
Rob Herring Feb. 20, 2018, 2:04 p.m. UTC | #6
On Tue, Feb 20, 2018 at 3:15 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Rob,
>
> On Tuesday, 20 February 2018 02:54:00 EET Rob Herring wrote:
>> On Wed, Feb 14, 2018 at 6:04 PM, Laurent Pinchart wrote:
>> > The internal LVDS encoders now have their own DT bindings. Before
>> > switching the driver infrastructure to those new bindings, implement
>> > backward-compatibility through live DT patching.
>> >
>> > 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>

>> > +static int __init rcar_du_of_add_property(struct device_node *np,
>> > +                                         const char *name, const void
>> > *value,
>> > +                                         size_t length)
>>
>> So, were you going to revive Pantelis' patch or move this to the core?
>
> Do you have a pointer to that patch ?

https://patchwork.kernel.org/patch/9104571/
https://patchwork.kernel.org/patch/9104591/
https://patchwork.kernel.org/patch/9104611/
https://patchwork.kernel.org/patch/9104581/
https://patchwork.kernel.org/patch/9104601/
diff mbox

Patch

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..141f6eda6e98
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
@@ -0,0 +1,374 @@ 
+// 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 struct device_node __init *
+rcar_du_of_find_node_by_path(struct device_node *parent, const char *path)
+{
+	parent = of_node_get(parent);
+	if (!parent)
+		return NULL;
+
+	while (parent && *path == '/') {
+		struct device_node *child = NULL;
+		struct device_node *node;
+		const char *next;
+		size_t len;
+
+		/* Skip the initial '/' delimiter and find the next one. */
+		path++;
+		next = strchrnul(path, '/');
+		len = next - path;
+		if (!len)
+			goto error;
+
+		for_each_child_of_node(parent, node) {
+			const char *name = kbasename(node->full_name);
+
+			if (strncmp(path, name, len) == 0 &&
+			    strlen(name) == len) {
+				child = node;
+				break;
+			}
+		}
+
+		if (!child)
+			goto error;
+
+		of_node_put(parent);
+		parent = child;
+		path = next;
+	}
+
+	return parent;
+
+error:
+	of_node_put(parent);
+	return NULL;
+}
+
+static int __init rcar_du_of_add_property(struct device_node *np,
+					  const char *name, const void *value,
+					  size_t length)
+{
+	struct property *prop;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	prop->name = kstrdup(name, GFP_KERNEL);
+	prop->value = kmemdup(value, length, GFP_KERNEL);
+	prop->length = length;
+
+	if (!prop->name || !prop->value) {
+		kfree(prop->name);
+		kfree(prop->value);
+		kfree(prop);
+		return -ENOMEM;
+	}
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->next = np->properties;
+	np->properties = prop;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * 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 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)
+{
+	struct device_node *endpoints[2];
+	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;
+
+	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(lvds, "clocks", value, psize);
+	if (ret < 0)
+		return;
+
+	/*
+	 * 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.
+	 */
+	endpoints[0] = rcar_du_of_find_node_by_path(lvds,
+						    "/ports/port@0/endpoint");
+	endpoints[1] = rcar_du_of_find_node_by_path(lvds,
+						    "/ports/port@1/endpoint");
+	if (!endpoints[0] || !endpoints[1])
+		return;
+
+	value[0] = cpu_to_be32(local->phandle);
+	ret = rcar_du_of_add_property(endpoints[0], "remote-endpoint",
+				      value, 4);
+	if (ret < 0)
+		goto done;
+
+	value[0] = cpu_to_be32(remote->phandle);
+	ret = rcar_du_of_add_property(endpoints[1], "remote-endpoint",
+				      value, 4);
+	if (ret < 0)
+		goto done;
+
+done:
+	of_node_put(endpoints[0]);
+	of_node_put(endpoints[1]);
+}
+
+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..6ebb355b652a
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts
@@ -0,0 +1,81 @@ 
+// 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
+ */
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/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..601982bba27d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts
@@ -0,0 +1,55 @@ 
+// 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
+ */
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/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..1c535954a529
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts
@@ -0,0 +1,55 @@ 
+// 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
+ */
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/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..44e52101ef05
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts
@@ -0,0 +1,55 @@ 
+// 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
+ */
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/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..8f45ebe140bd
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts
@@ -0,0 +1,55 @@ 
+// 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
+ */
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/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>;
+				};
+			};
+		};
+	};
+};