[PATCH 04/22] media: Move v4l2_fwnode_parse_link from v4l2 to driver base
From: Steve Longerbeam
Date: Mon Aug 05 2019 - 19:36:42 EST
There is nothing v4l2-specific about v4l2_fwnode_{parse|put}_link().
Make these functions more generally available by moving them to driver
base, with the appropriate name changes to the functions and struct.
In the process embed a 'struct fwnode_endpoint' in 'struct fwnode_link'
for both sides of the link, and make use of fwnode_graph_parse_endpoint()
to fully parse both endpoints. Rename members local_node and
remote_node to more descriptive local_port_parent and
remote_port_parent.
Signed-off-by: Steve Longerbeam <slongerbeam@xxxxxxxxx>
---
drivers/base/property.c | 63 +++++++++++++++++++
drivers/media/platform/xilinx/xilinx-vipp.c | 69 +++++++++++----------
drivers/media/v4l2-core/v4l2-fwnode.c | 39 ------------
drivers/staging/media/imx/imx-media-of.c | 49 +++++++--------
include/linux/fwnode.h | 14 +++++
include/linux/property.h | 5 ++
include/media/v4l2-fwnode.h | 44 -------------
7 files changed, 141 insertions(+), 142 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 81bd01ed4042..dd82cd150d84 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1100,6 +1100,69 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
+/**
+ * fwnode_graph_parse_link() - parse a link between two endpoints
+ * @local_endpoint: the endpoint's fwnode at the local end of the link
+ * @link: pointer to the fwnode link data structure
+ *
+ * Fill the link structure with the parsed local and remote endpoint info
+ * and the local and remote port parent nodes.
+ *
+ * A reference is taken to both the local and remote port parent nodes,
+ * the caller must use fwnode_graph_put_link() to drop the references
+ * when done with the link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode
+ * can't be found.
+ */
+int fwnode_graph_parse_link(struct fwnode_handle *local_endpoint,
+ struct fwnode_link *link)
+{
+ struct fwnode_handle *remote_endpoint;
+ int ret;
+
+ memset(link, 0, sizeof(*link));
+
+ ret = fwnode_graph_parse_endpoint(local_endpoint, &link->local);
+ if (ret < 0)
+ return ret;
+
+ remote_endpoint = fwnode_graph_get_remote_endpoint(local_endpoint);
+ if (!remote_endpoint)
+ return -ENOLINK;
+
+ ret = fwnode_graph_parse_endpoint(remote_endpoint, &link->remote);
+ if (ret < 0) {
+ fwnode_handle_put(remote_endpoint);
+ return ret;
+ }
+
+ link->local_port_parent =
+ fwnode_graph_get_port_parent(local_endpoint);
+ link->remote_port_parent =
+ fwnode_graph_get_port_parent(remote_endpoint);
+
+ fwnode_handle_put(remote_endpoint);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_parse_link);
+
+/**
+ * fwnode_graph_put_link() - drop references to port parent nodes in a link
+ * @link: pointer to the fwnode link data structure
+ *
+ * Drop references to the local and remote port parent nodes in the link.
+ * This function must be called on every link parsed with
+ * fwnode_graph_parse_link().
+ */
+void fwnode_graph_put_link(struct fwnode_link *link)
+{
+ fwnode_handle_put(link->local_port_parent);
+ fwnode_handle_put(link->remote_port_parent);
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_put_link);
+
const void *device_get_match_data(struct device *dev)
{
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index cc2856efea59..9c0dfc694478 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -74,7 +74,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
struct media_pad *local_pad;
struct media_pad *remote_pad;
struct xvip_graph_entity *ent;
- struct v4l2_fwnode_link link;
+ struct fwnode_link link;
struct fwnode_handle *ep = NULL;
int ret = 0;
@@ -89,7 +89,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
dev_dbg(xdev->dev, "processing endpoint %p\n", ep);
- ret = v4l2_fwnode_parse_link(ep, &link);
+ ret = fwnode_graph_parse_link(ep, &link);
if (ret < 0) {
dev_err(xdev->dev, "failed to parse link for %p\n",
ep);
@@ -99,54 +99,55 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
/* Skip sink ports, they will be processed from the other end of
* the link.
*/
- if (link.local_port >= local->num_pads) {
+ if (link.local.port >= local->num_pads) {
dev_err(xdev->dev, "invalid port number %u for %p\n",
- link.local_port, link.local_node);
- v4l2_fwnode_put_link(&link);
+ link.local.port, link.local_port_parent);
+ fwnode_graph_put_link(&link);
ret = -EINVAL;
break;
}
- local_pad = &local->pads[link.local_port];
+ local_pad = &local->pads[link.local.port];
if (local_pad->flags & MEDIA_PAD_FL_SINK) {
dev_dbg(xdev->dev, "skipping sink port %p:%u\n",
- link.local_node, link.local_port);
- v4l2_fwnode_put_link(&link);
+ link.local_port_parent, link.local.port);
+ fwnode_graph_put_link(&link);
continue;
}
/* Skip DMA engines, they will be processed separately. */
- if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) {
+ if (link.remote_port_parent ==
+ of_fwnode_handle(xdev->dev->of_node)) {
dev_dbg(xdev->dev, "skipping DMA port %p:%u\n",
- link.local_node, link.local_port);
- v4l2_fwnode_put_link(&link);
+ link.local_port_parent, link.local.port);
+ fwnode_graph_put_link(&link);
continue;
}
/* Find the remote entity. */
- ent = xvip_graph_find_entity(xdev, link.remote_node);
+ ent = xvip_graph_find_entity(xdev, link.remote_port_parent);
if (ent == NULL) {
dev_err(xdev->dev, "no entity found for %p\n",
- link.remote_node);
- v4l2_fwnode_put_link(&link);
+ link.remote_port_parent);
+ fwnode_graph_put_link(&link);
ret = -ENODEV;
break;
}
remote = ent->entity;
- if (link.remote_port >= remote->num_pads) {
+ if (link.remote.port >= remote->num_pads) {
dev_err(xdev->dev, "invalid port number %u on %p\n",
- link.remote_port, link.remote_node);
- v4l2_fwnode_put_link(&link);
+ link.remote.port, link.remote_port_parent);
+ fwnode_graph_put_link(&link);
ret = -EINVAL;
break;
}
- remote_pad = &remote->pads[link.remote_port];
+ remote_pad = &remote->pads[link.remote.port];
- v4l2_fwnode_put_link(&link);
+ fwnode_graph_put_link(&link);
/* Create the media link. */
dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
@@ -191,7 +192,7 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
struct media_pad *source_pad;
struct media_pad *sink_pad;
struct xvip_graph_entity *ent;
- struct v4l2_fwnode_link link;
+ struct fwnode_link link;
struct device_node *ep = NULL;
struct xvip_dma *dma;
int ret = 0;
@@ -206,7 +207,7 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep);
- ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
+ ret = fwnode_graph_parse_link(of_fwnode_handle(ep), &link);
if (ret < 0) {
dev_err(xdev->dev, "failed to parse link for %pOF\n",
ep);
@@ -214,11 +215,11 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
}
/* Find the DMA engine. */
- dma = xvip_graph_find_dma(xdev, link.local_port);
+ dma = xvip_graph_find_dma(xdev, link.local.port);
if (dma == NULL) {
dev_err(xdev->dev, "no DMA engine found for port %u\n",
- link.local_port);
- v4l2_fwnode_put_link(&link);
+ link.local.port);
+ fwnode_graph_put_link(&link);
ret = -EINVAL;
break;
}
@@ -227,20 +228,20 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
dma->video.name);
/* Find the remote entity. */
- ent = xvip_graph_find_entity(xdev, link.remote_node);
+ ent = xvip_graph_find_entity(xdev, link.remote_port_parent);
if (ent == NULL) {
dev_err(xdev->dev, "no entity found for %pOF\n",
- to_of_node(link.remote_node));
- v4l2_fwnode_put_link(&link);
+ to_of_node(link.remote_port_parent));
+ fwnode_graph_put_link(&link);
ret = -ENODEV;
break;
}
- if (link.remote_port >= ent->entity->num_pads) {
+ if (link.remote.port >= ent->entity->num_pads) {
dev_err(xdev->dev, "invalid port number %u on %pOF\n",
- link.remote_port,
- to_of_node(link.remote_node));
- v4l2_fwnode_put_link(&link);
+ link.remote.port,
+ to_of_node(link.remote_port_parent));
+ fwnode_graph_put_link(&link);
ret = -EINVAL;
break;
}
@@ -249,15 +250,15 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
source = &dma->video.entity;
source_pad = &dma->pad;
sink = ent->entity;
- sink_pad = &sink->pads[link.remote_port];
+ sink_pad = &sink->pads[link.remote.port];
} else {
source = ent->entity;
- source_pad = &source->pads[link.remote_port];
+ source_pad = &source->pads[link.remote.port];
sink = &dma->video.entity;
sink_pad = &dma->pad;
}
- v4l2_fwnode_put_link(&link);
+ fwnode_graph_put_link(&link);
/* Create the media link. */
dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 3bd1888787eb..5d4ce4aa3fdc 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -556,45 +556,6 @@ int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
-int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
- struct v4l2_fwnode_link *link)
-{
- const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
- struct fwnode_handle *fwnode;
-
- memset(link, 0, sizeof(*link));
-
- fwnode = fwnode_get_parent(__fwnode);
- fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
- fwnode = fwnode_get_next_parent(fwnode);
- if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
- fwnode = fwnode_get_next_parent(fwnode);
- link->local_node = fwnode;
-
- fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
- if (!fwnode) {
- fwnode_handle_put(fwnode);
- return -ENOLINK;
- }
-
- fwnode = fwnode_get_parent(fwnode);
- fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
- fwnode = fwnode_get_next_parent(fwnode);
- if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
- fwnode = fwnode_get_next_parent(fwnode);
- link->remote_node = fwnode;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
-
-void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
-{
- fwnode_handle_put(link->local_node);
- fwnode_handle_put(link->remote_node);
-}
-EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
-
static int
v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
struct v4l2_async_notifier *notifier,
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 2d3efd2a6dde..736c954a8ff5 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -84,28 +84,29 @@ EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs);
*/
static int create_of_link(struct imx_media_dev *imxmd,
struct v4l2_subdev *sd,
- struct v4l2_fwnode_link *link)
+ struct fwnode_link *link)
{
struct v4l2_subdev *remote, *src, *sink;
int src_pad, sink_pad;
- if (link->local_port >= sd->entity.num_pads)
+ if (link->local.port >= sd->entity.num_pads)
return -EINVAL;
- remote = imx_media_find_subdev_by_fwnode(imxmd, link->remote_node);
+ remote = imx_media_find_subdev_by_fwnode(imxmd,
+ link->remote_port_parent);
if (!remote)
return 0;
- if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
+ if (sd->entity.pads[link->local.port].flags & MEDIA_PAD_FL_SINK) {
src = remote;
- src_pad = link->remote_port;
+ src_pad = link->remote.port;
sink = sd;
- sink_pad = link->local_port;
+ sink_pad = link->local.port;
} else {
src = sd;
- src_pad = link->local_port;
+ src_pad = link->local.port;
sink = remote;
- sink_pad = link->remote_port;
+ sink_pad = link->remote.port;
}
/* make sure link doesn't already exist before creating */
@@ -126,17 +127,17 @@ static int create_of_link(struct imx_media_dev *imxmd,
int imx_media_create_of_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *sd)
{
- struct v4l2_fwnode_link link;
- struct device_node *ep;
+ struct fwnode_handle *endpoint;
+ struct fwnode_link link;
int ret;
- for_each_endpoint_of_node(sd->dev->of_node, ep) {
- ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
+ fwnode_graph_for_each_endpoint(dev_fwnode(sd->dev), endpoint) {
+ ret = fwnode_graph_parse_link(endpoint, &link);
if (ret)
continue;
ret = create_of_link(imxmd, sd, &link);
- v4l2_fwnode_put_link(&link);
+ fwnode_graph_put_link(&link);
if (ret)
return ret;
}
@@ -152,35 +153,33 @@ EXPORT_SYMBOL_GPL(imx_media_create_of_links);
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *csi)
{
- struct device_node *csi_np = csi->dev->of_node;
- struct device_node *ep;
+ struct fwnode_handle *csi_np = dev_fwnode(csi->dev);
+ struct fwnode_handle *csi_ep;
- for_each_child_of_node(csi_np, ep) {
- struct fwnode_handle *fwnode, *csi_ep;
- struct v4l2_fwnode_link link;
+ fwnode_for_each_child_node(csi_np, csi_ep) {
+ struct fwnode_handle *fwnode;
+ struct fwnode_link link;
int ret;
memset(&link, 0, sizeof(link));
- link.local_node = of_fwnode_handle(csi_np);
- link.local_port = CSI_SINK_PAD;
-
- csi_ep = of_fwnode_handle(ep);
+ link.local_port_parent = csi_np;
+ link.local.port = CSI_SINK_PAD;
fwnode = fwnode_graph_get_remote_endpoint(csi_ep);
if (!fwnode)
continue;
fwnode = fwnode_get_parent(fwnode);
- fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
+ fwnode_property_read_u32(fwnode, "reg", &link.remote.port);
fwnode = fwnode_get_next_parent(fwnode);
if (is_of_node(fwnode) &&
of_node_name_eq(to_of_node(fwnode), "ports"))
fwnode = fwnode_get_next_parent(fwnode);
- link.remote_node = fwnode;
+ link.remote_port_parent = fwnode;
ret = create_of_link(imxmd, csi, &link);
- fwnode_handle_put(link.remote_node);
+ fwnode_handle_put(link.remote_port_parent);
if (ret)
return ret;
}
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index a11c8c56c78b..c2063ae2affe 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -31,6 +31,20 @@ struct fwnode_endpoint {
const struct fwnode_handle *local_fwnode;
};
+/**
+ * struct fwnode_link - a link between two fwnode graph endpoints
+ * @local: parsed local endpoint of the link
+ * @local_port_parent: port parent fwnode of local endpoint
+ * @remote: parsed remote endpoint of the link
+ * @remote_port_parent: port parent fwnode of the remote endpoint
+ */
+struct fwnode_link {
+ struct fwnode_endpoint local;
+ struct fwnode_handle *local_port_parent;
+ struct fwnode_endpoint remote;
+ struct fwnode_handle *remote_port_parent;
+};
+
#define NR_FWNODE_REFERENCE_ARGS 8
/**
diff --git a/include/linux/property.h b/include/linux/property.h
index 5a910ad79591..3923906fc314 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -374,6 +374,11 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint);
+int fwnode_graph_parse_link(struct fwnode_handle *fwnode,
+ struct fwnode_link *link);
+
+void fwnode_graph_put_link(struct fwnode_link *link);
+
/* -------------------------------------------------------------------------- */
/* Software fwnode support - when HW description is incomplete or missing */
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index f6a7bcd13197..f81f8bf34526 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -109,20 +109,6 @@ struct v4l2_fwnode_endpoint {
unsigned int nr_of_link_frequencies;
};
-/**
- * struct v4l2_fwnode_link - a link between two endpoints
- * @local_node: pointer to device_node of this endpoint
- * @local_port: identifier of the port this endpoint belongs to
- * @remote_node: pointer to device_node of the remote endpoint
- * @remote_port: identifier of the port the remote endpoint belongs to
- */
-struct v4l2_fwnode_link {
- struct fwnode_handle *local_node;
- unsigned int local_port;
- struct fwnode_handle *remote_node;
- unsigned int remote_port;
-};
-
/**
* v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
* @fwnode: pointer to the endpoint's fwnode handle
@@ -203,36 +189,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep);
-/**
- * v4l2_fwnode_parse_link() - parse a link between two endpoints
- * @fwnode: pointer to the endpoint's fwnode at the local end of the link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Fill the link structure with the local and remote nodes and port numbers.
- * The local_node and remote_node fields are set to point to the local and
- * remote port's parent nodes respectively (the port parent node being the
- * parent node of the port node if that node isn't a 'ports' node, or the
- * grand-parent node of the port node otherwise).
- *
- * A reference is taken to both the local and remote nodes, the caller must use
- * v4l2_fwnode_put_link() to drop the references when done with the
- * link.
- *
- * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
- * found.
- */
-int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
- struct v4l2_fwnode_link *link);
-
-/**
- * v4l2_fwnode_put_link() - drop references to nodes in a link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Drop references to the local and remote nodes in the link. This function
- * must be called on every link parsed with v4l2_fwnode_parse_link().
- */
-void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
-
/**
* typedef parse_endpoint_func - Driver's callback function to be called on
* each V4L2 fwnode endpoint.
--
2.17.1