diff options
Diffstat (limited to 'drivers/media/platform/xilinx/xilinx-vipp.c')
| -rw-r--r-- | drivers/media/platform/xilinx/xilinx-vipp.c | 275 |
1 files changed, 115 insertions, 160 deletions
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index ac4704388920..30675f681410 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Xilinx Video IP Composite Device * @@ -6,10 +7,6 @@ * * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.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. */ #include <linux/list.h> @@ -32,34 +29,44 @@ /** * struct xvip_graph_entity - Entity in the video graph - * @list: list entry in a graph entities list - * @node: the entity's DT node - * @entity: media entity, from the corresponding V4L2 subdev * @asd: subdev asynchronous registration information + * @entity: media entity, from the corresponding V4L2 subdev * @subdev: V4L2 subdev */ struct xvip_graph_entity { - struct list_head list; - struct device_node *node; + struct v4l2_async_connection asd; /* must be first */ struct media_entity *entity; - - struct v4l2_async_subdev asd; struct v4l2_subdev *subdev; }; +static inline struct xvip_graph_entity * +to_xvip_entity(struct v4l2_async_connection *asd) +{ + return container_of(asd, struct xvip_graph_entity, asd); +} + /* ----------------------------------------------------------------------------- * Graph Management */ static struct xvip_graph_entity * xvip_graph_find_entity(struct xvip_composite_device *xdev, - const struct device_node *node) + const struct fwnode_handle *fwnode) { struct xvip_graph_entity *entity; + struct v4l2_async_connection *asd; + struct list_head *lists[] = { + &xdev->notifier.done_list, + &xdev->notifier.waiting_list + }; + unsigned int i; - list_for_each_entry(entity, &xdev->entities, list) { - if (entity->node == node) - return entity; + for (i = 0; i < ARRAY_SIZE(lists); i++) { + list_for_each_entry(asd, lists[i], asc_entry) { + entity = to_xvip_entity(asd); + if (entity->asd.match.fwnode == fwnode) + return entity; + } } return NULL; @@ -75,27 +82,24 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, struct media_pad *remote_pad; struct xvip_graph_entity *ent; struct v4l2_fwnode_link link; - struct device_node *ep = NULL; - struct device_node *next; + struct fwnode_handle *ep = NULL; int ret = 0; dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); while (1) { /* Get the next endpoint and parse its link. */ - next = of_graph_get_next_endpoint(entity->node, ep); - if (next == NULL) + ep = fwnode_graph_get_next_endpoint(entity->asd.match.fwnode, + ep); + if (ep == NULL) break; - of_node_put(ep); - ep = next; - - dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + dev_dbg(xdev->dev, "processing endpoint %p\n", ep); - ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); + ret = v4l2_fwnode_parse_link(ep, &link); if (ret < 0) { - dev_err(xdev->dev, "failed to parse link for %s\n", - ep->full_name); + dev_err(xdev->dev, "failed to parse link for %p\n", + ep); continue; } @@ -103,9 +107,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, * the link. */ if (link.local_port >= local->num_pads) { - dev_err(xdev->dev, "invalid port number %u for %s\n", - link.local_port, - to_of_node(link.local_node)->full_name); + dev_err(xdev->dev, "invalid port number %u for %p\n", + link.local_port, link.local_node); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -114,28 +117,25 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, local_pad = &local->pads[link.local_port]; if (local_pad->flags & MEDIA_PAD_FL_SINK) { - dev_dbg(xdev->dev, "skipping sink port %s:%u\n", - to_of_node(link.local_node)->full_name, - link.local_port); + dev_dbg(xdev->dev, "skipping sink port %p:%u\n", + link.local_node, link.local_port); v4l2_fwnode_put_link(&link); continue; } /* Skip DMA engines, they will be processed separately. */ if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) { - dev_dbg(xdev->dev, "skipping DMA port %s:%u\n", - to_of_node(link.local_node)->full_name, - link.local_port); + dev_dbg(xdev->dev, "skipping DMA port %p:%u\n", + link.local_node, link.local_port); v4l2_fwnode_put_link(&link); continue; } /* Find the remote entity. */ - ent = xvip_graph_find_entity(xdev, - to_of_node(link.remote_node)); + ent = xvip_graph_find_entity(xdev, link.remote_node); if (ent == NULL) { - dev_err(xdev->dev, "no entity found for %s\n", - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "no entity found for %p\n", + link.remote_node); v4l2_fwnode_put_link(&link); ret = -ENODEV; break; @@ -144,9 +144,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, remote = ent->entity; if (link.remote_port >= remote->num_pads) { - dev_err(xdev->dev, "invalid port number %u on %s\n", - link.remote_port, - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "invalid port number %u on %p\n", + link.remote_port, link.remote_node); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -173,7 +172,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, } } - of_node_put(ep); + fwnode_handle_put(ep); return ret; } @@ -200,28 +199,19 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev) struct media_pad *sink_pad; struct xvip_graph_entity *ent; struct v4l2_fwnode_link link; - struct device_node *ep = NULL; - struct device_node *next; + struct device_node *ep; struct xvip_dma *dma; int ret = 0; dev_dbg(xdev->dev, "creating links for DMA engines\n"); - while (1) { - /* Get the next endpoint and parse its link. */ - next = of_graph_get_next_endpoint(node, ep); - if (next == NULL) - break; - - of_node_put(ep); - ep = next; - - dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + for_each_endpoint_of_node(node, ep) { + dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep); ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); if (ret < 0) { - dev_err(xdev->dev, "failed to parse link for %s\n", - ep->full_name); + dev_err(xdev->dev, "failed to parse link for %pOF\n", + ep); continue; } @@ -239,20 +229,19 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev) dma->video.name); /* Find the remote entity. */ - ent = xvip_graph_find_entity(xdev, - to_of_node(link.remote_node)); + ent = xvip_graph_find_entity(xdev, link.remote_node); if (ent == NULL) { - dev_err(xdev->dev, "no entity found for %s\n", - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "no entity found for %pOF\n", + to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -ENODEV; break; } if (link.remote_port >= ent->entity->num_pads) { - dev_err(xdev->dev, "invalid port number %u on %s\n", + dev_err(xdev->dev, "invalid port number %u on %pOF\n", link.remote_port, - to_of_node(link.remote_node)->full_name); + to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -298,12 +287,14 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) struct xvip_composite_device *xdev = container_of(notifier, struct xvip_composite_device, notifier); struct xvip_graph_entity *entity; + struct v4l2_async_connection *asd; int ret; dev_dbg(xdev->dev, "notify complete, all subdevs registered\n"); /* Create links for every entity. */ - list_for_each_entry(entity, &xdev->entities, list) { + list_for_each_entry(asd, &xdev->notifier.done_list, asc_entry) { + entity = to_xvip_entity(asd); ret = xvip_graph_build_one(xdev, entity); if (ret < 0) return ret; @@ -323,86 +314,75 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) + struct v4l2_async_connection *asc) { - struct xvip_composite_device *xdev = - container_of(notifier, struct xvip_composite_device, notifier); - struct xvip_graph_entity *entity; - - /* Locate the entity corresponding to the bound subdev and store the - * subdev pointer. - */ - list_for_each_entry(entity, &xdev->entities, list) { - if (entity->node != subdev->dev->of_node) - continue; - - if (entity->subdev) { - dev_err(xdev->dev, "duplicate subdev for node %s\n", - entity->node->full_name); - return -EINVAL; - } + struct xvip_graph_entity *entity = to_xvip_entity(asc); - dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); - entity->entity = &subdev->entity; - entity->subdev = subdev; - return 0; - } + entity->entity = &subdev->entity; + entity->subdev = subdev; - dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); - return -EINVAL; + return 0; } +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { + .bound = xvip_graph_notify_bound, + .complete = xvip_graph_notify_complete, +}; + static int xvip_graph_parse_one(struct xvip_composite_device *xdev, - struct device_node *node) + struct fwnode_handle *fwnode) { - struct xvip_graph_entity *entity; - struct device_node *remote; - struct device_node *ep = NULL; + struct fwnode_handle *remote; + struct fwnode_handle *ep = NULL; int ret = 0; - dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); + dev_dbg(xdev->dev, "parsing node %p\n", fwnode); while (1) { - ep = of_graph_get_next_endpoint(node, ep); + struct xvip_graph_entity *xge; + + ep = fwnode_graph_get_next_endpoint(fwnode, ep); if (ep == NULL) break; - dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); + dev_dbg(xdev->dev, "handling endpoint %p\n", ep); - remote = of_graph_get_remote_port_parent(ep); + remote = fwnode_graph_get_remote_port_parent(ep); if (remote == NULL) { ret = -EINVAL; - break; + goto err_notifier_cleanup; } + fwnode_handle_put(ep); + /* Skip entities that we have already processed. */ - if (remote == xdev->dev->of_node || + if (remote == of_fwnode_handle(xdev->dev->of_node) || xvip_graph_find_entity(xdev, remote)) { - of_node_put(remote); + fwnode_handle_put(remote); continue; } - entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL); - if (entity == NULL) { - of_node_put(remote); - ret = -ENOMEM; - break; + xge = v4l2_async_nf_add_fwnode(&xdev->notifier, remote, + struct xvip_graph_entity); + fwnode_handle_put(remote); + if (IS_ERR(xge)) { + ret = PTR_ERR(xge); + goto err_notifier_cleanup; } - - entity->node = remote; - entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - entity->asd.match.fwnode.fwnode = of_fwnode_handle(remote); - list_add_tail(&entity->list, &xdev->entities); - xdev->num_subdevs++; } - of_node_put(ep); + return 0; + +err_notifier_cleanup: + v4l2_async_nf_cleanup(&xdev->notifier); + fwnode_handle_put(ep); return ret; } static int xvip_graph_parse(struct xvip_composite_device *xdev) { struct xvip_graph_entity *entity; + struct v4l2_async_connection *asd; int ret; /* @@ -411,14 +391,17 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev) * loop will handle entities added at the end of the list while walking * the links. */ - ret = xvip_graph_parse_one(xdev, xdev->dev->of_node); + ret = xvip_graph_parse_one(xdev, of_fwnode_handle(xdev->dev->of_node)); if (ret < 0) return 0; - list_for_each_entry(entity, &xdev->entities, list) { - ret = xvip_graph_parse_one(xdev, entity->node); - if (ret < 0) + list_for_each_entry(asd, &xdev->notifier.waiting_list, asc_entry) { + entity = to_xvip_entity(asd); + ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode); + if (ret < 0) { + v4l2_async_nf_cleanup(&xdev->notifier); break; + } } return ret; @@ -452,8 +435,7 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, ret = xvip_dma_init(xdev, dma, type, index); if (ret < 0) { - dev_err(xdev->dev, "%s initialization failed\n", - node->full_name); + dev_err(xdev->dev, "%pOF initialization failed\n", node); return ret; } @@ -468,8 +450,7 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, static int xvip_graph_dma_init(struct xvip_composite_device *xdev) { struct device_node *ports; - struct device_node *port; - int ret; + int ret = 0; ports = of_get_child_by_name(xdev->dev->of_node, "ports"); if (ports == NULL) { @@ -477,30 +458,23 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev) return -EINVAL; } - for_each_child_of_node(ports, port) { + for_each_child_of_node_scoped(ports, port) { ret = xvip_graph_dma_init_one(xdev, port); - if (ret < 0) { - of_node_put(port); - return ret; - } + if (ret) + break; } - return 0; + of_node_put(ports); + return ret; } static void xvip_graph_cleanup(struct xvip_composite_device *xdev) { - struct xvip_graph_entity *entityp; - struct xvip_graph_entity *entity; struct xvip_dma *dmap; struct xvip_dma *dma; - v4l2_async_notifier_unregister(&xdev->notifier); - - list_for_each_entry_safe(entity, entityp, &xdev->entities, list) { - of_node_put(entity->node); - list_del(&entity->list); - } + v4l2_async_nf_unregister(&xdev->notifier); + v4l2_async_nf_cleanup(&xdev->notifier); list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { xvip_dma_cleanup(dma); @@ -510,10 +484,6 @@ static void xvip_graph_cleanup(struct xvip_composite_device *xdev) static int xvip_graph_init(struct xvip_composite_device *xdev) { - struct xvip_graph_entity *entity; - struct v4l2_async_subdev **subdevs = NULL; - unsigned int num_subdevs; - unsigned int i; int ret; /* Init the DMA channels. */ @@ -523,6 +493,8 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) goto done; } + v4l2_async_nf_init(&xdev->notifier, &xdev->v4l2_dev); + /* Parse the graph to extract a list of subdevice DT nodes. */ ret = xvip_graph_parse(xdev); if (ret < 0) { @@ -530,30 +502,16 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) goto done; } - if (!xdev->num_subdevs) { + if (list_empty(&xdev->notifier.waiting_list)) { dev_err(xdev->dev, "no subdev found in graph\n"); + ret = -ENOENT; goto done; } /* Register the subdevices notifier. */ - num_subdevs = xdev->num_subdevs; - subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, - GFP_KERNEL); - if (subdevs == NULL) { - ret = -ENOMEM; - goto done; - } + xdev->notifier.ops = &xvip_graph_notify_ops; - i = 0; - list_for_each_entry(entity, &xdev->entities, list) - subdevs[i++] = &entity->asd; - - xdev->notifier.subdevs = subdevs; - xdev->notifier.num_subdevs = num_subdevs; - xdev->notifier.bound = xvip_graph_notify_bound; - xdev->notifier.complete = xvip_graph_notify_complete; - - ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); + ret = v4l2_async_nf_register(&xdev->notifier); if (ret < 0) { dev_err(xdev->dev, "notifier registration failed\n"); goto done; @@ -584,7 +542,7 @@ static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) int ret; xdev->media_dev.dev = xdev->dev; - strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device", + strscpy(xdev->media_dev.model, "Xilinx Video Composite Device", sizeof(xdev->media_dev.model)); xdev->media_dev.hw_revision = 0; @@ -616,7 +574,6 @@ static int xvip_composite_probe(struct platform_device *pdev) return -ENOMEM; xdev->dev = &pdev->dev; - INIT_LIST_HEAD(&xdev->entities); INIT_LIST_HEAD(&xdev->dmas); ret = xvip_composite_v4l2_init(xdev); @@ -638,14 +595,12 @@ error: return ret; } -static int xvip_composite_remove(struct platform_device *pdev) +static void xvip_composite_remove(struct platform_device *pdev) { struct xvip_composite_device *xdev = platform_get_drvdata(pdev); xvip_graph_cleanup(xdev); xvip_composite_v4l2_cleanup(xdev); - - return 0; } static const struct of_device_id xvip_composite_of_id_table[] = { |
