From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Rob Herring <robh@kernel.org>
Cc: "open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS"
<devicetree@vger.kernel.org>,
Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>,
Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>,
dri-devel <dri-devel@lists.freedesktop.org>,
"open list:MEDIA DRIVERS FOR RENESAS - FCP"
<linux-renesas-soc@vger.kernel.org>,
Geert Uytterhoeven <geert@glider.be>,
Frank Rowand <frowand.list@gmail.com>
Subject: Re: [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes
Date: Mon, 15 Jan 2018 20:01:27 +0200 [thread overview]
Message-ID: <1905364.eR590Hd45s@avalon> (raw)
In-Reply-To: <CAL_JsqK9yWE2nLX3AbSx-U6zAyE3fkYnURBY+r6KkJCogU5_sA@mail.gmail.com>
Hi Rob,
(CC'ing Geert)
On Monday, 15 January 2018 19:09:53 EET Rob Herring wrote:
> +Frank
>
> On Fri, Jan 12, 2018 at 5:14 PM, Laurent Pinchart wrote:
> > The internal LVDS encoders now have their own DT bindings. Before
> > switching the driver infrastructure to those new bindings, implement
> > backward-compatibility through live DT patching.
>
> Uhh, we just got rid of TI's patching and now adding this one. I guess
> it's necessary, but I'd like to know how long we need to keep this?
That's a good question. How long are we supposed to keep DT backward
compatibility for ? I don't think there's a one-size-fits-them-all answer to
this question. Geert, any opinion ? How long do you plan to keep the CPG
(clocks) DT backward compatibility for instance ?
> How many overlays would you need if everything is static (i.e. removing all
> your fixup code)?
Do you mean if I hardcoded support for SoCs individually instead of handling
the differences in code ? At least 5 as that's the number of SoCs that are
impacted, but that wouldn't be enough. Part of the DT structure that is
patched is board-specific, not SoC-specific. That's 10 boards in mainline,
plus all the custom boards out there, and even the development boards
supported in mainline to which a flat panel has been externally connected.
> > Patching is disabled and will be enabled along with support for the new
> > DT bindings in the DU driver.
> >
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > Changes since v1:
> >
> > - Select OF_FLATTREE
> > - Compile LVDS DT bindings patch code when DRM_RCAR_LVDS is selected
> > - Update the SPDX headers to use GPL-2.0 instead of GPL-2.0-only
> > - Turn __dtb_rcar_du_of_lvds_(begin|end) from u8 to char
> > - Pass void begin and end pointers to rcar_du_of_get_overlay()
> > - Use of_get_parent() instead of accessing the parent pointer directly
> > - Find the LVDS endpoints nodes based on the LVDS node instead of the
> > root of the overlay
> > - Update to the <soc>-lvds compatible string format
> > ---
> > drivers/gpu/drm/rcar-du/Kconfig | 2 +
> > drivers/gpu/drm/rcar-du/Makefile | 3 +-
> > drivers/gpu/drm/rcar-du/rcar_du_of.c | 451 +++++++++++++++++++++++
> > drivers/gpu/drm/rcar-du/rcar_du_of.h | 16 +
> > drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts | 82 +++++
> > 5 files changed, 553 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c
> > create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h
> > create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> >
> > diff --git a/drivers/gpu/drm/rcar-du/Kconfig
> > b/drivers/gpu/drm/rcar-du/Kconfig index 5d0b4b7119af..3f83352a7313 100644
> > --- a/drivers/gpu/drm/rcar-du/Kconfig
> > +++ b/drivers/gpu/drm/rcar-du/Kconfig
> > @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS
> > bool "R-Car DU LVDS Encoder Support"
> > depends on DRM_RCAR_DU
> > select DRM_PANEL
> > + select OF_FLATTREE
> > + select OF_OVERLAY
>
> OF_OVERLAY should probably select OF_FLATTREE. I guess in theory, we
> could have an overlay from a non-FDT source...
Up to you, I'll happily drop OF_FLATTREE if it gets selected automatically. If
you think it's a good idea I can submit a patch.
> > help
> > Enable support for the R-Car Display Unit embedded LVDS
> > encoders.
[snip]
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_of.c new file mode 100644
> > index 000000000000..2bf91201fc93
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c
> > @@ -0,0 +1,451 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * rcar_du_of.c - Legacy DT bindings compatibility
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + *
> > + * Based on work from Jyri Sarha <jsarha@ti.com>
> > + * Copyright (C) 2015 Texas Instruments
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_fdt.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/slab.h>
> > +
> > +#include "rcar_du_crtc.h"
> > +#include "rcar_du_drv.h"
> > +
> > +#ifdef CONFIG_DRM_RCAR_LVDS
>
> Why not make compiling this file conditional in the Makefile?
In case I need to patch other DU-related constructs in the future other than
LVDS. I could compile this conditionally in the Makefile for now and change it
later if needed. I have no strong preference.
> > +
> > +struct rcar_du_of_overlay {
> > + struct device_node *np;
> > + void *data;
> > + void *mem;
> > +};
> > +
> > +static void __init rcar_du_of_free_overlay(struct rcar_du_of_overlay
> > *overlay)
> > +{
> > + of_node_put(overlay->np);
> > + kfree(overlay->data);
> > + kfree(overlay->mem);
> > +}
> > +
> > +static int __init rcar_du_of_get_overlay(struct rcar_du_of_overlay
> > *overlay,
> > + void *begin, void
> > *end)
> > +{
> > + const size_t size = end - begin;
> > +
> > + memset(overlay, 0, sizeof(*overlay));
> > +
> > + if (!size)
> > + return -EINVAL;
> > +
> > + overlay->data = kmemdup(begin, size, GFP_KERNEL);
> > + if (!overlay->data)
> > + return -ENOMEM;
> > +
> > + overlay->mem = of_fdt_unflatten_tree(overlay->data, NULL,
> > &overlay->np); + if (!overlay->mem) {
> > + rcar_du_of_free_overlay(overlay);
> > + return -ENOMEM;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static struct device_node __init *
> > +rcar_du_of_find_node_by_path(struct device_node *parent, const char
> > *path)
> > +{
>
> What's wrong with the core function to do this?
I haven't found any function that performs lookup by path starting at a given
root. of_find_node_by_path() operates on an absolute path starting at the root
of the live DT. Is there a function I have missed ?
And of course this should be a core OF function, there's no reason to make it
driver-specific.
> > + parent = of_node_get(parent);
> > + if (!parent)
> > + return NULL;
> > +
> > + while (parent && *path == '/') {
> > + struct device_node *child = NULL;
> > + struct device_node *node;
> > + const char *next;
> > + size_t len;
> > +
> > + /* Skip the initial '/' delimiter and find the next one.
> > */
> > + path++;
> > + next = strchrnul(path, '/');
> > + len = next - path;
> > + if (!len)
> > + goto error;
> > +
> > + for_each_child_of_node(parent, node) {
> > + const char *name = kbasename(node->full_name);
> > +
> > + if (strncmp(path, name, len) == 0 &&
> > + strlen(name) == len) {
> > + child = node;
> > + break;
> > + }
> > + }
> > +
> > + if (!child)
> > + goto error;
> > +
> > + of_node_put(parent);
> > + parent = child;
> > + path = next;
> > + }
> > +
> > + return parent;
> > +
> > +error:
> > + of_node_put(parent);
> > + return NULL;
> > +}
> > +
> > +static int __init rcar_du_of_add_property(struct device_node *np,
> > + const char *name, const void
> > *value,
> > + size_t length)
> > +{
>
> This should be a core function. In fact, IIRC, Pantelis had a patch
> adding functions like this. I believe there were only minor issues and
> I said I would take it even without users, but he never followed up.
I agree, it should be a core function. The reason I implemented it as a
driver-specific function was that I wanted a functional prototype and an
overall agreement on the approach before proposing extensions to the OF API.
> > + struct property *prop;
>
> We want to make struct property opaque, so I don't really want to see
> more users...
If we make this a core function it shouldn't be an issue. We would then also
need a function to update the value of an existing property. That's more
tricky than it might seem, as properties are either fully dynamic or fully
static. We can't have a non-OF_DYNAMIC struct property instance (created when
parsing the FDT) that gets a dynamically-allocated value pointer all of a
sudden.
I see two ways to fix this, either making dynamic memory management more fine-
grained at the property level, or creating a new property to replace the old
one when updating the value. I believe device_node instances suffer from the
same problem.
By the way I believe there are memory leaks in the OF core, as I haven't found
any code that frees OF_DYNAMIC properties. A grep for OF_DYNAMIC or
OF_IS_DYNAMIC returned no check of the flag for properties apart from one
occurrence in arch/sparc/kernel/prom_common.c.
> > +
> > + prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> > + if (!prop)
> > + return -ENOMEM;
> > +
> > + prop->name = kstrdup(name, GFP_KERNEL);
> > + prop->value = kmemdup(value, length, GFP_KERNEL);
> > + prop->length = length;
> > +
> > + if (!prop->name || !prop->value) {
> > + kfree(prop->name);
> > + kfree(prop->value);
> > + kfree(prop);
> > + return -ENOMEM;
> > + }
> > +
> > + of_property_set_flag(prop, OF_DYNAMIC);
> > +
> > + prop->next = np->properties;
> > + np->properties = prop;
> > +
> > + return 0;
> > +}
> > +
> > +/* Free properties allocated dynamically by rcar_du_of_add_property(). */
> > +static void __init rcar_du_of_free_properties(struct device_node *np)
> > +{
> > + while (np->properties) {
> > + struct property *prop = np->properties;
> > +
> > + np->properties = prop->next;
> > +
> > + if (OF_IS_DYNAMIC(prop)) {
> > + kfree(prop->name);
> > + kfree(prop->value);
> > + kfree(prop);
> > + }
> > + }
> > +}
> > +
> > +static int __init rcar_du_of_update_target_path(struct device_node *du,
> > + struct device_node
> > *remote,
> > + struct device_node *np)
> > +{
> > + struct device_node *target = NULL;
> > + struct property **prev;
> > + struct property *prop;
> > + char *path;
> > + int ret;
> > +
> > + for (prop = np->properties, prev = ∝ prop != NULL;
> > + prev = &prop->next, prop = prop->next) {
> > + if (of_prop_cmp(prop->name, "target-path"))
> > + continue;
> > +
> > + if (!of_prop_cmp(prop->value, "soc")) {
> > + target = of_get_parent(du);
> > + break;
> > + }
> > + if (!of_prop_cmp(prop->value, "du")) {
> > + target = of_node_get(du);
> > + break;
> > + }
> > + if (!of_prop_cmp(prop->value, "lvds-sink")) {
> > + target = of_graph_get_port_parent(remote);
> > + break;
> > + }
> > +
> > + return -EINVAL;
> > + }
> > +
> > + if (!target)
> > + return -EINVAL;
> > +
> > + path = kasprintf(GFP_KERNEL, "%pOF", target);
> > + of_node_put(target);
> > + if (!path)
> > + return -ENOMEM;
> > +
> > + /*
> > + * Remove the existing target-path property that has not been
> > + * dynamically allocated and replace it with a new dynamic one to
> > + * ensure that the value will be properly freed.
> > + */
> > + *prev = prop->next;
>
> You are leaking prev. prev should be moved the deleted property list.
> But then you shouldn't be mucking with properties at this level in the
> first place.
If we implement an OF function to update the value of a property I won't need
to, and I'd be fine with that.
What I need for this patch series is three new functions to
- lookup a node by path starting at a given node
- add a property
- update the value of an existing property
I can submit proposals if we agree that those functions should be implemented.
I'd like to know how you would like to handle the last two though: we have
lots of type-specific property read functions, I don't think we should
duplicate all that for write given the number of expected users. Maybe the
property add and update functions should just take a void pointer and a length
for the value ?
> > + ret = rcar_du_of_add_property(np, "target-path", path,
> > + strlen(path) + 1);
> > + if (ret < 0) {
> > + kfree(path);
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +extern char __dtb_rcar_du_of_lvds_begin[];
> > +extern char __dtb_rcar_du_of_lvds_end[];
> > +
> > +static void __init rcar_du_of_lvds_patch_one(struct device_node *du,
> > + unsigned int port_id,
> > + const struct resource *res,
> > + const __be32 *reg,
> > + const struct of_phandle_args
> > *clkspec,
> > + struct device_node
> > *local,
> > + struct device_node
> > *remote)
> > +{
> > + struct rcar_du_of_overlay overlay;
> > + struct device_node *du_port_fixup;
> > + struct device_node *du_port;
> > + struct device_node *lvds_endpoints[2];
> > + struct device_node *lvds;
> > + struct device_node *fragment;
> > + struct device_node *bus;
> > + struct property *prop;
> > + const char *compatible;
> > + const char *soc_suffix;
> > + unsigned int psize;
> > + unsigned int i;
> > + __be32 value[4];
> > + char name[23];
> > + int ovcs_id;
> > + int ret;
> > +
> > + /* Skip if the LVDS node already exists. */
> > + sprintf(name, "lvds@%llx", (u64)res->start);
>
> Fragile. unit-address and res->start are not necessarily the same thing.
I thought the unit address was supposed to be the start address of the first
reg entry ? I can instead loop over all nodes named lvds and compared the reg
address.
In practice I think this should work. This function is only called if the
device tree implements the legacy bindings (otherwise there's no "lvds.*" reg-
names entry) and we thus have no existing lvds@* node at boot time. The
purpose of this check is to avoid patching the same device tree twice if the
module is removed an reinserted. I thus control the unit address as I generate
it myself.
> > + bus = of_get_parent(du);
> > + lvds = of_get_child_by_name(bus, name);
> > + of_node_put(bus);
> > + if (lvds) {
> > + of_node_put(lvds);
> > + return;
> > + }
> > +
> > + /* Parse the overlay. */
> > + ret = rcar_du_of_get_overlay(&overlay,
> > __dtb_rcar_du_of_lvds_begin,
> > + __dtb_rcar_du_of_lvds_end);
> > + if (ret < 0)
> > + return;
> > +
> > + /*
> > + * Patch the LVDS and DU port nodes names and the associated fixup
> > + * entries.
> > + */
> > + lvds = rcar_du_of_find_node_by_path(overlay.np,
> > + "/fragment@0/__overlay__/lvds");
> > + lvds_endpoints[0] = rcar_du_of_find_node_by_path(lvds,
> > + "/ports/port@0/endpoint");
> > + lvds_endpoints[1] = rcar_du_of_find_node_by_path(lvds,
> > + "/ports/port@1/endpoint");
> > + du_port = rcar_du_of_find_node_by_path(overlay.np,
> > + "/fragment@1/__overlay__/ports/port@0");
> > + du_port_fixup = rcar_du_of_find_node_by_path(overlay.np,
> > + "/__local_fixups__/fragment@1/__overlay__/ports/port@0");
> > + if (!lvds || !lvds_endpoints[0] || !lvds_endpoints[1] ||
> > + !du_port || !du_port_fixup)
> > + goto out_put_nodes;
> > +
> > + lvds->full_name = kstrdup(name, GFP_KERNEL);
> > +
> > + sprintf(name, "port@%u", port_id);
> > + du_port->full_name = kstrdup(name, GFP_KERNEL);
> > + du_port_fixup->full_name = kstrdup(name, GFP_KERNEL);
> > +
> > + if (!lvds->full_name || !du_port->full_name ||
> > + !du_port_fixup->full_name)
> > + goto out_free_names;
> > +
> > + /* Patch the target paths in all fragments. */
> > + for_each_child_of_node(overlay.np, fragment) {
> > + if (strncmp("fragment@", of_node_full_name(fragment), 9))
> > + continue;
> > +
> > + ret = rcar_du_of_update_target_path(du, remote, fragment);
> > + if (ret < 0) {
> > + of_node_put(fragment);
> > + goto out_free_properties;
> > + }
> > + }
> > +
> > + /*
> > + * Create a compatible string for the LVDS node using the SoC
> > model
> > + * from the DU node.
> > + */
> > + ret = of_property_read_string(du, "compatible", &compatible);
> > + if (ret < 0)
> > + goto out_free_properties;
> > +
> > + soc_suffix = strchr(compatible, '-');
> > + if (!soc_suffix || strlen(soc_suffix) > 10)
> > + goto out_free_properties;
> > +
> > + psize = sprintf(name, "renesas,%s-lvds", soc_suffix + 1) + 1;
> > + ret = rcar_du_of_add_property(lvds, "compatible", name, psize);
> > + if (ret < 0)
> > + goto out_free_properties;
> > +
> > + /* Copy the LVDS reg and clocks properties from the DU node. */
> > + psize = (of_n_addr_cells(du) + of_n_size_cells(du)) * 4;
> > + ret = rcar_du_of_add_property(lvds, "reg", reg, psize);
> > + if (ret < 0)
> > + goto out_free_properties;
> > +
> > + if (clkspec->args_count >= ARRAY_SIZE(value) - 1)
> > + goto out_free_properties;
> > +
> > + value[0] = cpu_to_be32(clkspec->np->phandle);
> > + for (i = 0; i < clkspec->args_count; ++i)
> > + value[i + 1] = cpu_to_be32(clkspec->args[i]);
> > +
> > + psize = (clkspec->args_count + 1) * 4;
> > + ret = rcar_du_of_add_property(lvds, "clocks", value, psize);
> > + if (ret < 0)
> > + goto out_free_properties;
> > +
> > + /*
> > + * Insert the node in the OF graph: patch the LVDS ports
> > remote-endpoint
> > + * properties to point to the endpoints of the sibling nodes in
> > the
> > + * graph.
> > + */
> > + prop = of_find_property(lvds_endpoints[0], "remote-endpoint",
> > NULL);
> > + if (!prop)
> > + goto out_free_properties;
> > +
> > + *(__be32 *)prop->value = cpu_to_be32(local->phandle);
> > +
> > + prop = of_find_property(lvds_endpoints[1], "remote-endpoint",
> > NULL);
> > + if (!prop)
> > + goto out_free_properties;
> > +
> > + *(__be32 *)prop->value = cpu_to_be32(remote->phandle);
> > +
> > + /* Apply the overlay, this will resolve phandles. */
> > + ovcs_id = 0;
> > + ret = of_overlay_apply(overlay.np, &ovcs_id);
> > +
> > + /* We're done, free all allocated memory. */
> > +out_free_properties:
> > + rcar_du_of_free_properties(lvds);
> > + rcar_du_of_free_properties(du_port);
> > + rcar_du_of_free_properties(du_port_fixup);
> > +out_free_names:
> > + kfree(lvds->full_name);
> > + kfree(du_port->full_name);
> > + kfree(du_port_fixup->full_name);
> > +out_put_nodes:
> > + of_node_put(lvds);
> > + of_node_put(lvds_endpoints[0]);
> > + of_node_put(lvds_endpoints[1]);
> > + of_node_put(du_port);
> > + of_node_put(du_port_fixup);
> > +
> > + rcar_du_of_free_overlay(&overlay);
> > +}
> > +
> > +static void __init rcar_du_of_lvds_patch(const struct of_device_id
> > *of_ids)
> > +{
> > + const struct rcar_du_device_info *info;
> > + const struct of_device_id *match;
> > + struct device_node *du;
> > + unsigned int i;
> > + int ret;
> > +
> > + /* Get the DU node and exit if not present or disabled. */
> > + du = of_find_matching_node_and_match(NULL, of_ids, &match);
> > + if (!du || !of_device_is_available(du))
> > + goto done;
> > +
> > + info = match->data;
> > +
> > + /* Patch every LVDS encoder. */
> > + for (i = 0; i < info->num_lvds; ++i) {
> > + struct of_phandle_args clkspec;
> > + struct device_node *local, *remote;
> > + struct resource res;
> > + unsigned int port_id;
> > + const __be32 *reg;
> > + char name[7];
> > + int index;
> > +
> > + /*
> > + * Retrieve the register specifier, the clock specifier
> > and the
> > + * local and remote endpoints of the LVDS link.
> > + */
> > + sprintf(name, "lvds.%u", i);
> > + index = of_property_match_string(du, "reg-names", name);
> > + if (index < 0)
> > + continue;
> > +
> > + reg = of_get_address(du, index, NULL, NULL);
> > + if (!reg)
> > + continue;
> > +
> > + ret = of_address_to_resource(du, index, &res);
> > + if (ret < 0)
> > + continue;
> > +
> > + index = of_property_match_string(du, "clock-names", name);
> > + if (index < 0)
> > + continue;
> > +
> > + ret = of_parse_phandle_with_args(du, "clocks",
> > "#clock-cells",
> > + index, &clkspec);
> > + if (ret < 0)
> > + continue;
> > +
> > + port_id = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port;
> > +
> > + local = of_graph_get_endpoint_by_regs(du, port_id, 0);
> > + if (!local) {
> > + of_node_put(clkspec.np);
> > + continue;
> > + }
> > +
> > + remote = of_graph_get_remote_endpoint(local);
> > + if (!remote) {
> > + of_node_put(local);
> > + of_node_put(clkspec.np);
> > + continue;
> > + }
> > +
> > + /* Patch the LVDS encoder. */
> > + rcar_du_of_lvds_patch_one(du, port_id, &res, reg,
> > &clkspec,
> > + local, remote);
> > +
> > + of_node_put(clkspec.np);
> > + of_node_put(remote);
> > + of_node_put(local);
> > + }
> > +
> > +done:
> > + of_node_put(du);
> > +}
> > +#else
> > +static void __init rcar_du_of_lvds_patch(const struct of_device_id
> > *of_ids)
> > +{
> > +}
> > +#endif /* CONFIG_DRM_RCAR_LVDS */
> > +
> > +void __init rcar_du_of_init(const struct of_device_id *of_ids)
> > +{
> > + rcar_du_of_lvds_patch(of_ids);
> > +}
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h
> > b/drivers/gpu/drm/rcar-du/rcar_du_of.h new file mode 100644
> > index 000000000000..7105eaef58c6
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h
> > @@ -0,0 +1,16 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> The guidelines say headers should be C style. This is due to headers
> getting included by assembly code.
My bad, I'll fix that.
> > +/*
> > + * rcar_du_of.h - Legacy DT bindings compatibility
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + */
> > +#ifndef __RCAR_DU_OF_H__
> > +#define __RCAR_DU_OF_H__
> > +
> > +#include <linux/init.h>
> > +
> > +struct of_device_id;
> > +
> > +void __init rcar_du_of_init(const struct of_device_id *of_ids);
> > +
> > +#endif /* __RCAR_DU_OF_H__ */
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts new file mode 100644
> > index 000000000000..bc75c7a1c3bd
> > --- /dev/null
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds.dts
> > @@ -0,0 +1,82 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * rcar_du_of_lvds.dts - Legacy LVDS DT bindings conversion
> > + *
> > + * Copyright (C) 2018 Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com>
> > + *
> > + * Based on work from Jyri Sarha <jsarha@ti.com>
> > + * Copyright (C) 2015 Texas Instruments
> > + */
> > +
> > +/*
> > + * The target-paths, lvds node name, DU port number and LVDS remote
> > endpoints
> > + * will be patched dynamically at runtime.
> > + */
> > +
> > +/dts-v1/;
> > +/ {
> > + fragment@0 {
> > + target-path = "soc";
>
> I don't really like this abuse of target-path that isn't really a
> valid path. I don't debate the need, but we just need a standard way
> to handle this.
I agree it's a bit of a hack, I just couldn't think of a better way. Proposals
are welcome :-)
> Perhaps we need to allow target-path to be a string list. That gets
> back to my question on how many static combinations you have. I'd
> prefer duplication of overlays with simple applying code to coding a
> bunch of matching and fixups.
See my answer above, I don't think static overlays would be a good option. For
fragments 0 and 1 we could use one overlay per SoC, which could be manageable,
but fragment 2 is board-specific.
> > + __overlay__ {
> > + lvds {
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + port@0 {
> > + reg = <0>;
> > + lvds_input: endpoint {
> > + remote-endpoint =
> > <0>; + };
> > + };
> > +
> > + port@1 {
> > + reg = <1>;
> > + lvds_output: endpoint {
> > + remote-endpoint =
> > <0>;
> > + };
> > + };
> > + };
> > + };
> > + };
> > + };
> > +
> > + fragment@1 {
> > + target-path = "du";
> > + __overlay__ {
> > + ports {
> > + port@0 {
> > + endpoint {
> > + remote-endpoint =
> > <&lvds_input>;
> > + };
> > + };
> > + };
> > + };
> > + };
> > +
> > + fragment@2 {
> > + target-path = "lvds-sink";
> > + __overlay__ {
> > + remote-endpoint = <&lvds_output>;
> > + };
> > + };
> > +
> > + __local_fixups__ {
>
> dtc generates this now.
Ah, nice to know. I'll retest without the manual __local_fixups__.
> > + fragment@1 {
> > + __overlay__ {
> > + ports {
> > + port@0 {
> > + endpoint {
> > + remote-endpoint =
> > <0>; + };
> > + };
> > + };
> > + };
> > + };
> > + fragment@2 {
> > + __overlay__ {
> > + remote-endpoint = <0>;
> > + };
> > + };
> > + };
> > +};
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2018-01-15 18:01 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-12 23:14 [PATCH v2 00/12] R-Car DU: Convert LVDS code to bridge driver Laurent Pinchart
[not found] ` <20180112231430.26943-1-laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
2018-01-12 23:14 ` [PATCH v2 01/12] dt-bindings: display: renesas: Add R-Car LVDS encoder DT bindings Laurent Pinchart
2018-01-19 22:47 ` Rob Herring
2018-01-12 23:14 ` [PATCH v2 02/12] dt-bindings: display: renesas: Deprecate LVDS support in the DU bindings Laurent Pinchart
2018-01-12 23:14 ` [PATCH v2 03/12] drm: rcar-du: Fix legacy DT to create LVDS encoder nodes Laurent Pinchart
2018-01-15 17:09 ` Rob Herring
2018-01-15 18:01 ` Laurent Pinchart [this message]
2018-01-16 8:56 ` Geert Uytterhoeven
[not found] ` <CAMuHMdUNcKOod1KCAGSBeMr52PWKqkJo0AWmSNk76t0=Zvu0gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 10:23 ` Laurent Pinchart
2018-01-16 15:08 ` Rob Herring
[not found] ` <CAL_JsqJuzXgx-ntbHdYiabi7DUyT8y0Vxj-c5KBmf+Gk+EWtMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 15:31 ` Geert Uytterhoeven
2018-01-15 19:12 ` Frank Rowand
2018-01-15 19:22 ` Laurent Pinchart
2018-01-15 20:12 ` Frank Rowand
[not found] ` <444f1b6b-fa57-da7c-08fd-51b28cdb5fff-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-01-15 20:29 ` Laurent Pinchart
2018-01-15 23:46 ` Frank Rowand
2018-01-15 23:57 ` Frank Rowand
2018-01-16 14:35 ` Rob Herring
[not found] ` <CAL_JsqKD_VKMrfi42hZ3eHPAMWBwryV0g_cXDUeyaKfPP99LmA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 16:32 ` Laurent Pinchart
2018-01-16 16:54 ` Rob Herring
[not found] ` <CAL_Jsq+4X17Q+wva0R6sPHY02TJ5+E5vE8Y98+DB5VF2MdFy0g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-01-16 20:35 ` Laurent Pinchart
2018-01-21 9:35 ` Sergei Shtylyov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1905364.eR590Hd45s@avalon \
--to=laurent.pinchart@ideasonboard.com \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=frowand.list@gmail.com \
--cc=geert@glider.be \
--cc=laurent.pinchart+renesas@ideasonboard.com \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sergei.shtylyov@cogentembedded.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).