diff mbox

[10/26] OMAPDSS: add of helpers

Message ID 1386160133-24026-11-git-send-email-tomi.valkeinen@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tomi Valkeinen Dec. 4, 2013, 12:28 p.m. UTC
Add helpers to get ports and endpoints from DT data.

While all the functions in dss-of.c might be useful for panel drivers if
they need to parse full port/endpoint data, at the moment we only need a
few of them outside dss-of.c, so only those functions are exported.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/Makefile |   2 +-
 drivers/video/omap2/dss/dss-of.c | 160 +++++++++++++++++++++++++++++++++++++++
 include/video/omapdss.h          |   6 ++
 3 files changed, 167 insertions(+), 1 deletion(-)
 create mode 100644 drivers/video/omap2/dss/dss-of.c

Comments

Laurent Pinchart Dec. 11, 2013, 11:19 p.m. UTC | #1
Hi Tomi,

On Wednesday 04 December 2013 14:28:37 Tomi Valkeinen wrote:
> Add helpers to get ports and endpoints from DT data.
> 
> While all the functions in dss-of.c might be useful for panel drivers if
> they need to parse full port/endpoint data, at the moment we only need a
> few of them outside dss-of.c, so only those functions are exported.

I totally understand that it was easier to add this code to the OMAP DSS 
driver, but I believe we should refactor the existing drivers/media/v4l2-
core/v4l2-of.c and move it to a non V4L2-specific location (what about 
drivers/media ?) sooner rather than later. That's on my to-do list for 
Saturday.

> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
>  drivers/video/omap2/dss/Makefile |   2 +-
>  drivers/video/omap2/dss/dss-of.c | 160 ++++++++++++++++++++++++++++++++++++
>  include/video/omapdss.h          |   6 ++
>  3 files changed, 167 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/video/omap2/dss/dss-of.c
> 
> diff --git a/drivers/video/omap2/dss/Makefile
> b/drivers/video/omap2/dss/Makefile index d3aa91bdd6a8..8aec8bda27cc 100644
> --- a/drivers/video/omap2/dss/Makefile
> +++ b/drivers/video/omap2/dss/Makefile
> @@ -1,7 +1,7 @@
>  obj-$(CONFIG_OMAP2_DSS) += omapdss.o
>  # Core DSS files
>  omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
> -	output.o
> +	output.o dss-of.o
>  # DSS compat layer files
>  omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
>  	dispc-compat.o display-sysfs.o
> diff --git a/drivers/video/omap2/dss/dss-of.c
> b/drivers/video/omap2/dss/dss-of.c new file mode 100644
> index 000000000000..9aa61d4bdb3d
> --- /dev/null
> +++ b/drivers/video/omap2/dss/dss-of.c
> @@ -0,0 +1,160 @@
> +/*
> + * Copyright (C) 2013 Texas Instruments
> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> by + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> WITHOUT + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> General Public License for + * more details.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/seq_file.h>
> +
> +#include <video/omapdss.h>
> +
> +#include "dss.h"
> +#include "dss_features.h"
> +
> +static struct device_node *
> +omapdss_of_get_next_port(const struct device_node *parent,
> +			 struct device_node *prev)
> +{
> +	struct device_node *port = NULL;
> +
> +	if (!parent)
> +		return NULL;
> +
> +	if (!prev) {
> +		struct device_node *ports;
> +		/*
> +		 * It's the first call, we have to find a port subnode
> +		 * within this node or within an optional 'ports' node.
> +		 */
> +		ports = of_get_child_by_name(parent, "ports");
> +		if (ports)
> +			parent = ports;
> +
> +		port = of_get_child_by_name(parent, "port");
> +
> +		/* release the 'ports' node */
> +		of_node_put(ports);
> +	} else {
> +		struct device_node *ports;
> +
> +		ports = of_get_parent(prev);
> +		if (!ports)
> +			return NULL;
> +
> +		do {
> +			port = of_get_next_child(ports, prev);
> +			if (!port) {
> +				of_node_put(ports);
> +				return NULL;
> +			}
> +			prev = port;
> +		} while (of_node_cmp(port->name, "port") != 0);
> +	}
> +
> +	return port;
> +}
> +
> +static struct device_node *
> +omapdss_of_get_next_endpoint(const struct device_node *parent,
> +			     struct device_node *prev)
> +{
> +	struct device_node *ep = NULL;
> +
> +	if (!parent)
> +		return NULL;
> +
> +	do {
> +		ep = of_get_next_child(parent, prev);
> +		if (!ep)
> +			return NULL;
> +		prev = ep;
> +	} while (of_node_cmp(ep->name, "endpoint") != 0);
> +
> +	return ep;
> +}
> +
> +static struct device_node *
> +omapdss_of_get_remote_device_node(const struct device_node *node)
> +{
> +	struct device_node *np;
> +	int i;
> +
> +	np = of_parse_phandle(node, "remote-endpoint", 0);
> +
> +	if (!np)
> +		return NULL;
> +
> +	np = of_get_next_parent(np);
> +
> +	for (i = 0; i < 3 && np; ++i) {
> +		struct property *prop;
> +
> +		prop = of_find_property(np, "compatible", NULL);
> +
> +		if (prop)
> +			return np;
> +
> +		np = of_get_next_parent(np);
> +	}
> +
> +	return NULL;
> +}
> +
> +struct device_node *
> +omapdss_of_get_first_endpoint(const struct device_node *parent)
> +{
> +	struct device_node *port;
> +	struct device_node *ep;
> +
> +	port = omapdss_of_get_next_port(parent, NULL);
> +	if (port) {
> +		ep = omapdss_of_get_next_endpoint(port, NULL);
> +		of_node_put(port);
> +	} else {
> +		ep = omapdss_of_get_next_endpoint(parent, NULL);
> +	}
> +
> +	return ep;
> +}
> +EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
> +
> +struct omap_dss_device *
> +omapdss_of_find_source_for_first_ep(struct device_node *node)
> +{
> +	struct device_node *ep;
> +	struct device_node *src_node;
> +	struct omap_dss_device *src;
> +
> +	ep = omapdss_of_get_first_endpoint(node);
> +	if (!ep)
> +		return ERR_PTR(-EINVAL);
> +
> +	src_node = omapdss_of_get_remote_device_node(ep);
> +
> +	of_node_put(ep);
> +
> +	if (!src_node)
> +		return ERR_PTR(-EINVAL);
> +
> +	src = omap_dss_find_output_by_node(src_node);
> +
> +	of_node_put(src_node);
> +
> +	if (!src)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return src;
> +}
> +EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
> diff --git a/include/video/omapdss.h b/include/video/omapdss.h
> index 3d7c51a6f9ff..c510591df1b8 100644
> --- a/include/video/omapdss.h
> +++ b/include/video/omapdss.h
> @@ -1019,4 +1019,10 @@ static inline bool omapdss_device_is_enabled(struct
> omap_dss_device *dssdev) return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
>  }
> 
> +struct device_node *
> +omapdss_of_get_first_endpoint(const struct device_node *parent);
> +
> +struct omap_dss_device *
> +omapdss_of_find_source_for_first_ep(struct device_node *node);
> +
>  #endif
Tomi Valkeinen Dec. 12, 2013, 7:48 a.m. UTC | #2
On 2013-12-12 01:19, Laurent Pinchart wrote:
> Hi Tomi,
> 
> On Wednesday 04 December 2013 14:28:37 Tomi Valkeinen wrote:
>> Add helpers to get ports and endpoints from DT data.
>>
>> While all the functions in dss-of.c might be useful for panel drivers if
>> they need to parse full port/endpoint data, at the moment we only need a
>> few of them outside dss-of.c, so only those functions are exported.
> 
> I totally understand that it was easier to add this code to the OMAP DSS 
> driver, but I believe we should refactor the existing drivers/media/v4l2-
> core/v4l2-of.c and move it to a non V4L2-specific location (what about 
> drivers/media ?) sooner rather than later. That's on my to-do list for 
> Saturday.

I agree. I just didn't want to go that way yet =).

Have you thought of the API? You had one version in your CDF series, but
I think that was a bit too limited (I don't remember right now how), so
I wrote my own versions.

What I tried to do here is to add simple ways for the drivers to iterate
the ports and endpoints with omapdss_of_get_next_port and
omapdss_of_get_next_endpoint.

But I'm not sure what the use pattern would be. If in most of the cases
the driver always goes through all the ports and all the endpoints, we
could as well have a helper function that goes through all the endpoints
in all the ports, and returns both the port and endpoint for each iteration.

 Tomi
Laurent Pinchart Dec. 13, 2013, 2:37 a.m. UTC | #3
Hi Tomi,

On Thursday 12 December 2013 09:48:30 Tomi Valkeinen wrote:
> On 2013-12-12 01:19, Laurent Pinchart wrote:
> > On Wednesday 04 December 2013 14:28:37 Tomi Valkeinen wrote:
> >> Add helpers to get ports and endpoints from DT data.
> >> 
> >> While all the functions in dss-of.c might be useful for panel drivers if
> >> they need to parse full port/endpoint data, at the moment we only need a
> >> few of them outside dss-of.c, so only those functions are exported.
> > 
> > I totally understand that it was easier to add this code to the OMAP DSS
> > driver, but I believe we should refactor the existing drivers/media/v4l2-
> > core/v4l2-of.c and move it to a non V4L2-specific location (what about
> > drivers/media ?) sooner rather than later. That's on my to-do list for
> > Saturday.
> 
> I agree. I just didn't want to go that way yet =).
> 
> Have you thought of the API? You had one version in your CDF series, but
> I think that was a bit too limited (I don't remember right now how), so
> I wrote my own versions.
> 
> What I tried to do here is to add simple ways for the drivers to iterate
> the ports and endpoints with omapdss_of_get_next_port and
> omapdss_of_get_next_endpoint.
> 
> But I'm not sure what the use pattern would be. If in most of the cases
> the driver always goes through all the ports and all the endpoints, we
> could as well have a helper function that goes through all the endpoints
> in all the ports, and returns both the port and endpoint for each iteration.

My plan is to keep it simple. I'll take the V4L2 code and add helpers needed 
by this patch series and by my Renesas KMS drivers. I'll then see whether 
refactoring makes sense, and will post the result. We will then add new 
helpers whenever needed on a case by case basis.
diff mbox

Patch

diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index d3aa91bdd6a8..8aec8bda27cc 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,7 +1,7 @@ 
 obj-$(CONFIG_OMAP2_DSS) += omapdss.o
 # Core DSS files
 omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
-	output.o
+	output.o dss-of.o
 # DSS compat layer files
 omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
 	dispc-compat.o display-sysfs.o
diff --git a/drivers/video/omap2/dss/dss-of.c b/drivers/video/omap2/dss/dss-of.c
new file mode 100644
index 000000000000..9aa61d4bdb3d
--- /dev/null
+++ b/drivers/video/omap2/dss/dss-of.c
@@ -0,0 +1,160 @@ 
+/*
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/seq_file.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static struct device_node *
+omapdss_of_get_next_port(const struct device_node *parent,
+			 struct device_node *prev)
+{
+	struct device_node *port = NULL;
+
+	if (!parent)
+		return NULL;
+
+	if (!prev) {
+		struct device_node *ports;
+		/*
+		 * It's the first call, we have to find a port subnode
+		 * within this node or within an optional 'ports' node.
+		 */
+		ports = of_get_child_by_name(parent, "ports");
+		if (ports)
+			parent = ports;
+
+		port = of_get_child_by_name(parent, "port");
+
+		/* release the 'ports' node */
+		of_node_put(ports);
+	} else {
+		struct device_node *ports;
+
+		ports = of_get_parent(prev);
+		if (!ports)
+			return NULL;
+
+		do {
+			port = of_get_next_child(ports, prev);
+			if (!port) {
+				of_node_put(ports);
+				return NULL;
+			}
+			prev = port;
+		} while (of_node_cmp(port->name, "port") != 0);
+	}
+
+	return port;
+}
+
+static struct device_node *
+omapdss_of_get_next_endpoint(const struct device_node *parent,
+			     struct device_node *prev)
+{
+	struct device_node *ep = NULL;
+
+	if (!parent)
+		return NULL;
+
+	do {
+		ep = of_get_next_child(parent, prev);
+		if (!ep)
+			return NULL;
+		prev = ep;
+	} while (of_node_cmp(ep->name, "endpoint") != 0);
+
+	return ep;
+}
+
+static struct device_node *
+omapdss_of_get_remote_device_node(const struct device_node *node)
+{
+	struct device_node *np;
+	int i;
+
+	np = of_parse_phandle(node, "remote-endpoint", 0);
+
+	if (!np)
+		return NULL;
+
+	np = of_get_next_parent(np);
+
+	for (i = 0; i < 3 && np; ++i) {
+		struct property *prop;
+
+		prop = of_find_property(np, "compatible", NULL);
+
+		if (prop)
+			return np;
+
+		np = of_get_next_parent(np);
+	}
+
+	return NULL;
+}
+
+struct device_node *
+omapdss_of_get_first_endpoint(const struct device_node *parent)
+{
+	struct device_node *port;
+	struct device_node *ep;
+
+	port = omapdss_of_get_next_port(parent, NULL);
+	if (port) {
+		ep = omapdss_of_get_next_endpoint(port, NULL);
+		of_node_put(port);
+	} else {
+		ep = omapdss_of_get_next_endpoint(parent, NULL);
+	}
+
+	return ep;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
+
+struct omap_dss_device *
+omapdss_of_find_source_for_first_ep(struct device_node *node)
+{
+	struct device_node *ep;
+	struct device_node *src_node;
+	struct omap_dss_device *src;
+
+	ep = omapdss_of_get_first_endpoint(node);
+	if (!ep)
+		return ERR_PTR(-EINVAL);
+
+	src_node = omapdss_of_get_remote_device_node(ep);
+
+	of_node_put(ep);
+
+	if (!src_node)
+		return ERR_PTR(-EINVAL);
+
+	src = omap_dss_find_output_by_node(src_node);
+
+	of_node_put(src_node);
+
+	if (!src)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	return src;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 3d7c51a6f9ff..c510591df1b8 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -1019,4 +1019,10 @@  static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
 	return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
 }
 
+struct device_node *
+omapdss_of_get_first_endpoint(const struct device_node *parent);
+
+struct omap_dss_device *
+omapdss_of_find_source_for_first_ep(struct device_node *node);
+
 #endif