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 <slongerb...@gmail.com> --- 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