summaryrefslogtreecommitdiff
path: root/drivers/media/platform/xilinx/xilinx-vipp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/xilinx/xilinx-vipp.c')
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c275
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[] = {