Commit 0d3c81e8 authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Mauro Carvalho Chehab
Browse files

media: v4l2-mc: add v4l2_create_fwnode_links helpers



Add functions to create media links between source and sink subdevices,
based on the fwnode endpoint connections between them:

v4l2_create_fwnode_links_to_pad() - create links from a source subdev to
                                    a single sink pad based on fwnode
                                    endpoint connections.

v4l2_create_fwnode_links() - create all links from a source to sink subdev
                             based on fwnode endpoint connections.

These functions can be used in a sink's v4l2-async notifier subdev
bound callback to make the links from the bound subdev.

Signed-off-by: default avatarSteve Longerbeam <slongerbeam@gmail.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 8fe784b9
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -309,6 +309,101 @@ int v4l_vb2q_enable_media_source(struct vb2_queue *q)
}
EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);

int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
				    struct media_pad *sink)
{
	struct fwnode_handle *endpoint;
	struct v4l2_subdev *sink_sd;

	if (!(sink->flags & MEDIA_PAD_FL_SINK) ||
	    !is_media_entity_v4l2_subdev(sink->entity))
		return -EINVAL;

	sink_sd = media_entity_to_v4l2_subdev(sink->entity);

	fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
		struct fwnode_handle *remote_ep;
		int src_idx, sink_idx, ret;
		struct media_pad *src;

		src_idx = media_entity_get_fwnode_pad(&src_sd->entity,
						      endpoint,
						      MEDIA_PAD_FL_SOURCE);
		if (src_idx < 0)
			continue;

		remote_ep = fwnode_graph_get_remote_endpoint(endpoint);
		if (!remote_ep)
			continue;

		/*
		 * ask the sink to verify it owns the remote endpoint,
		 * and translate to a sink pad.
		 */
		sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity,
						       remote_ep,
						       MEDIA_PAD_FL_SINK);
		fwnode_handle_put(remote_ep);

		if (sink_idx < 0 || sink_idx != sink->index)
			continue;

		/*
		 * the source endpoint corresponds to one of its source pads,
		 * the source endpoint connects to an endpoint at the sink
		 * entity, and the sink endpoint corresponds to the sink
		 * pad requested, so we have found an endpoint connection
		 * that works, create the media link for it.
		 */

		src = &src_sd->entity.pads[src_idx];

		/* skip if link already exists */
		if (media_entity_find_link(src, sink))
			continue;

		dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n",
			src_sd->entity.name, src_idx,
			sink_sd->entity.name, sink_idx);

		ret = media_create_pad_link(&src_sd->entity, src_idx,
					    &sink_sd->entity, sink_idx, 0);
		if (ret) {
			dev_err(sink_sd->dev,
				"link %s:%d -> %s:%d failed with %d\n",
				src_sd->entity.name, src_idx,
				sink_sd->entity.name, sink_idx, ret);

			fwnode_handle_put(endpoint);
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad);

int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
			     struct v4l2_subdev *sink_sd)
{
	unsigned int i;

	for (i = 0; i < sink_sd->entity.num_pads; i++) {
		struct media_pad *pad = &sink_sd->entity.pads[i];
		int ret;

		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			continue;

		ret = v4l2_create_fwnode_links_to_pad(src_sd, pad);
		if (ret)
			return ret;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);

/* -----------------------------------------------------------------------------
 * Pipeline power management
 *
+48 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include <media/media-device.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-subdev.h>
#include <linux/types.h>

/* We don't need to include pci.h or usb.h here */
@@ -84,6 +85,53 @@ void v4l_disable_media_source(struct video_device *vdev);
 */
int v4l_vb2q_enable_media_source(struct vb2_queue *q);

/**
 * v4l2_create_fwnode_links_to_pad - Create fwnode-based links from a
 *                                   source subdev to a sink subdev pad.
 *
 * @src_sd - pointer to a source subdev
 * @sink - pointer to a subdev sink pad
 *
 * This function searches for fwnode endpoint connections from a source
 * subdevice to a single sink pad, and if suitable connections are found,
 * translates them into media links to that pad. The function can be
 * called by the sink subdevice, in its v4l2-async notifier subdev bound
 * callback, to create links from a bound source subdevice.
 *
 * .. note::
 *
 *    Any sink subdevice that calls this function must implement the
 *    .get_fwnode_pad media operation in order to verify endpoints passed
 *    to the sink are owned by the sink.
 *
 * Return 0 on success or a negative error code on failure.
 */
int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
				    struct media_pad *sink);

/**
 * v4l2_create_fwnode_links - Create fwnode-based links from a source
 *                            subdev to a sink subdev.
 *
 * @src_sd - pointer to a source subdevice
 * @sink_sd - pointer to a sink subdevice
 *
 * This function searches for any and all fwnode endpoint connections
 * between source and sink subdevices, and translates them into media
 * links. The function can be called by the sink subdevice, in its
 * v4l2-async notifier subdev bound callback, to create all links from
 * a bound source subdevice.
 *
 * .. note::
 *
 *    Any sink subdevice that calls this function must implement the
 *    .get_fwnode_pad media operation in order to verify endpoints passed
 *    to the sink are owned by the sink.
 *
 * Return 0 on success or a negative error code on failure.
 */
int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
			     struct v4l2_subdev *sink_sd);

/**
 * v4l2_pipeline_pm_get - Increase the use count of a pipeline