All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Niklas Söderlund" <niklas.soderlund+renesas@ragnatech.se>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Hans Verkuil <hverkuil@xs4all.nl>,
	linux-media@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org,
	"Kieran Bingham" <kieran.bingham@ideasonboard.com>,
	"Niklas Söderlund" <niklas.soderlund+renesas@ragnatech.se>
Subject: [PATCH v14 28/33] rcar-vin: parse Gen3 OF and setup media graph
Date: Sat, 14 Apr 2018 13:57:21 +0200	[thread overview]
Message-ID: <20180414115726.5075-29-niklas.soderlund+renesas@ragnatech.se> (raw)
In-Reply-To: <20180414115726.5075-1-niklas.soderlund+renesas@ragnatech.se>

The parsing and registering CSI-2 subdevices with the v4l2 async
framework is a collaborative effort shared between the VIN instances
which are part of the group. When the last VIN in the group is probed it
asks all other VINs to parse its share of OF and record the async
subdevices it finds in the notifier belonging to the last probed VIN.

Once all CSI-2 subdevices in this notifier are bound proceed to register
all VIN video devices of the group and crate media device links between
all CSI-2 and VIN entities according to the SoC specific routing
configuration.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/platform/rcar-vin/rcar-core.c | 246 +++++++++++++++++++++++++++-
 drivers/media/platform/rcar-vin/rcar-vin.h  |  12 +-
 2 files changed, 254 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 38eaa246e4c0a7b5..99f6301a778046df 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -27,6 +27,23 @@
 
 #include "rcar-vin.h"
 
+/*
+ * The companion CSI-2 receiver driver (rcar-csi2) is known
+ * and we know it has one source pad (pad 0) and four sink
+ * pads (pad 1-4). So to translate a pad on the remote
+ * CSI-2 receiver to/from the VIN internal channel number simply
+ * subtract/add one from the pad/channel number.
+ */
+#define rvin_group_csi_pad_to_channel(pad) ((pad) - 1)
+#define rvin_group_csi_channel_to_pad(channel) ((channel) + 1)
+
+/*
+ * Not all VINs are created equal, master VINs control the
+ * routing for other VIN's. We can figure out which VIN is
+ * master by looking at a VINs id.
+ */
+#define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4)
+
 /* -----------------------------------------------------------------------------
  * Gen3 CSI2 Group Allocator
  */
@@ -409,6 +426,216 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)
 	return 0;
 }
 
+/* -----------------------------------------------------------------------------
+ * Group async notifier
+ */
+
+static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
+{
+	struct rvin_dev *vin = notifier_to_vin(notifier);
+	const struct rvin_group_route *route;
+	unsigned int i;
+	int ret;
+
+	ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
+	if (ret) {
+		vin_err(vin, "Failed to register subdev nodes\n");
+		return ret;
+	}
+
+	/* Register all video nodes for the group. */
+	for (i = 0; i < RCAR_VIN_NUM; i++) {
+		if (vin->group->vin[i]) {
+			ret = rvin_v4l2_register(vin->group->vin[i]);
+			if (ret)
+				return ret;
+		}
+	}
+
+	/* Create all media device links between VINs and CSI-2's. */
+	mutex_lock(&vin->group->lock);
+	for (route = vin->info->routes; route->mask; route++) {
+		struct media_pad *source_pad, *sink_pad;
+		struct media_entity *source, *sink;
+		unsigned int source_idx;
+
+		/* Check that VIN is part of the group. */
+		if (!vin->group->vin[route->vin])
+			continue;
+
+		/* Check that VIN' master is part of the group. */
+		if (!vin->group->vin[rvin_group_id_to_master(route->vin)])
+			continue;
+
+		/* Check that CSI-2 is part of the group. */
+		if (!vin->group->csi[route->csi].subdev)
+			continue;
+
+		source = &vin->group->csi[route->csi].subdev->entity;
+		source_idx = rvin_group_csi_channel_to_pad(route->channel);
+		source_pad = &source->pads[source_idx];
+
+		sink = &vin->group->vin[route->vin]->vdev.entity;
+		sink_pad = &sink->pads[0];
+
+		/* Skip if link already exists. */
+		if (media_entity_find_link(source_pad, sink_pad))
+			continue;
+
+		ret = media_create_pad_link(source, source_idx, sink, 0, 0);
+		if (ret) {
+			vin_err(vin, "Error adding link from %s to %s\n",
+				source->name, sink->name);
+			break;
+		}
+	}
+	mutex_unlock(&vin->group->lock);
+
+	return ret;
+}
+
+static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
+				     struct v4l2_subdev *subdev,
+				     struct v4l2_async_subdev *asd)
+{
+	struct rvin_dev *vin = notifier_to_vin(notifier);
+	unsigned int i;
+
+	for (i = 0; i < RCAR_VIN_NUM; i++)
+		if (vin->group->vin[i])
+			rvin_v4l2_unregister(vin->group->vin[i]);
+
+	mutex_lock(&vin->group->lock);
+
+	for (i = 0; i < RVIN_CSI_MAX; i++) {
+		if (vin->group->csi[i].fwnode != asd->match.fwnode)
+			continue;
+		vin->group->csi[i].subdev = NULL;
+		vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i);
+		break;
+	}
+
+	mutex_unlock(&vin->group->lock);
+}
+
+static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *subdev,
+				   struct v4l2_async_subdev *asd)
+{
+	struct rvin_dev *vin = notifier_to_vin(notifier);
+	unsigned int i;
+
+	mutex_lock(&vin->group->lock);
+
+	for (i = 0; i < RVIN_CSI_MAX; i++) {
+		if (vin->group->csi[i].fwnode != asd->match.fwnode)
+			continue;
+		vin->group->csi[i].subdev = subdev;
+		vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i);
+		break;
+	}
+
+	mutex_unlock(&vin->group->lock);
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations rvin_group_notify_ops = {
+	.bound = rvin_group_notify_bound,
+	.unbind = rvin_group_notify_unbind,
+	.complete = rvin_group_notify_complete,
+};
+
+static int rvin_mc_parse_of_endpoint(struct device *dev,
+				     struct v4l2_fwnode_endpoint *vep,
+				     struct v4l2_async_subdev *asd)
+{
+	struct rvin_dev *vin = dev_get_drvdata(dev);
+
+	if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX)
+		return -EINVAL;
+
+	if (!of_device_is_available(to_of_node(asd->match.fwnode))) {
+
+		vin_dbg(vin, "OF device %pOF disabled, ignoring\n",
+			to_of_node(asd->match.fwnode));
+		return -ENOTCONN;
+
+	}
+
+	if (vin->group->csi[vep->base.id].fwnode) {
+		vin_dbg(vin, "OF device %pOF already handled\n",
+			to_of_node(asd->match.fwnode));
+		return -ENOTCONN;
+	}
+
+	vin->group->csi[vep->base.id].fwnode = asd->match.fwnode;
+
+	vin_dbg(vin, "Add group OF device %pOF to slot %u\n",
+		to_of_node(asd->match.fwnode), vep->base.id);
+
+	return 0;
+}
+
+static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
+{
+	unsigned int count = 0;
+	unsigned int i;
+	int ret;
+
+	mutex_lock(&vin->group->lock);
+
+	/* If there already is a notifier something has gone wrong, bail out. */
+	if (WARN_ON(vin->group->notifier)) {
+		mutex_unlock(&vin->group->lock);
+		return -EINVAL;
+	}
+
+	/* If not all VIN's are registered don't register the notifier. */
+	for (i = 0; i < RCAR_VIN_NUM; i++)
+		if (vin->group->vin[i])
+			count++;
+
+	if (vin->group->count != count) {
+		mutex_unlock(&vin->group->lock);
+		return 0;
+	}
+
+	/*
+	 * Have all VIN's look for subdevices. Some subdevices will overlap
+	 * but the parser function can handle it, so each subdevice will
+	 * only be registered once with the notifier.
+	 */
+
+	vin->group->notifier = &vin->notifier;
+
+	for (i = 0; i < RCAR_VIN_NUM; i++) {
+		if (!vin->group->vin[i])
+			continue;
+
+		ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+				vin->group->vin[i]->dev, vin->group->notifier,
+				sizeof(struct v4l2_async_subdev), 1,
+				rvin_mc_parse_of_endpoint);
+		if (ret) {
+			mutex_unlock(&vin->group->lock);
+			return ret;
+		}
+	}
+
+	mutex_unlock(&vin->group->lock);
+
+	vin->group->notifier->ops = &rvin_group_notify_ops;
+
+	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
+	if (ret < 0) {
+		vin_err(vin, "Notifier registration failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int rvin_mc_init(struct rvin_dev *vin)
 {
 	int ret;
@@ -422,7 +649,15 @@ static int rvin_mc_init(struct rvin_dev *vin)
 	if (ret)
 		return ret;
 
-	return rvin_group_get(vin);
+	ret = rvin_group_get(vin);
+	if (ret)
+		return ret;
+
+	ret = rvin_mc_parse_of_graph(vin);
+	if (ret)
+		rvin_group_put(vin);
+
+	return ret;
 }
 
 /* -----------------------------------------------------------------------------
@@ -542,10 +777,15 @@ static int rcar_vin_remove(struct platform_device *pdev)
 	v4l2_async_notifier_unregister(&vin->notifier);
 	v4l2_async_notifier_cleanup(&vin->notifier);
 
-	if (vin->info->use_mc)
+	if (vin->info->use_mc) {
+		mutex_lock(&vin->group->lock);
+		if (vin->group->notifier == &vin->notifier)
+			vin->group->notifier = NULL;
+		mutex_unlock(&vin->group->lock);
 		rvin_group_put(vin);
-	else
+	} else {
 		v4l2_ctrl_handler_free(&vin->ctrl_handler);
+	}
 
 	rvin_dma_unregister(vin);
 
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 93eb40856b866117..c2aef789b491ab31 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -223,9 +223,13 @@ struct rvin_dev {
  *
  * @mdev:		media device which represents the group
  *
- * @lock:		protects the count and vin members
+ * @lock:		protects the count, notifier, vin and csi members
  * @count:		number of enabled VIN instances found in DT
+ * @notifier:		pointer to the notifier of a VIN which handles the
+ *			groups async sub-devices.
  * @vin:		VIN instances which are part of the group
+ * @csi:		array of pairs of fwnode and subdev pointers
+ *			to all CSI-2 subdevices.
  */
 struct rvin_group {
 	struct kref refcount;
@@ -234,7 +238,13 @@ struct rvin_group {
 
 	struct mutex lock;
 	unsigned int count;
+	struct v4l2_async_notifier *notifier;
 	struct rvin_dev *vin[RCAR_VIN_NUM];
+
+	struct {
+		struct fwnode_handle *fwnode;
+		struct v4l2_subdev *subdev;
+	} csi[RVIN_CSI_MAX];
 };
 
 int rvin_dma_register(struct rvin_dev *vin, int irq);
-- 
2.16.2

  parent reply	other threads:[~2018-04-14 12:02 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-14 11:56 [PATCH v14 00/33] rcar-vin: Add Gen3 with media controller Niklas Söderlund
2018-04-14 11:56 ` [PATCH v14 01/33] dt-bindings: media: rcar_vin: Reverse SoC part number list Niklas Söderlund
2018-04-14 11:56 ` [PATCH v14 02/33] dt-bindings: media: rcar_vin: add device tree support for r8a774[35] Niklas Söderlund
2018-04-14 11:56 ` [PATCH v14 03/33] rcar-vin: add Gen3 devicetree bindings documentation Niklas Söderlund
2018-05-02 13:10   ` Geert Uytterhoeven
2018-04-14 11:56 ` [PATCH v14 04/33] rcar-vin: rename poorly named initialize and cleanup functions Niklas Söderlund
2018-04-14 11:56 ` [PATCH v14 05/33] rcar-vin: unregister video device on driver removal Niklas Söderlund
2018-04-14 11:56 ` [PATCH v14 06/33] rcar-vin: move subdevice handling to async callbacks Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 07/33] rcar-vin: move model information to own struct Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 08/33] rcar-vin: move max width and height information to chip information Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 09/33] rcar-vin: move functions regarding scaling Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 10/33] rcar-vin: all Gen2 boards can scale simplify logic Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 11/33] rcar-vin: set a default field to fallback on Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 12/33] rcar-vin: fix handling of single field frames (top, bottom and alternate fields) Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 13/33] rcar-vin: update bytesperline and sizeimage calculation Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 14/33] rcar-vin: align pixelformat check Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 15/33] rcar-vin: break out format alignment and checking Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 16/33] rcar-vin: simplify how formats are set and reset Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 17/33] rcar-vin: cache video standard Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 18/33] rcar-vin: move media bus configuration to struct rvin_dev Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 19/33] rcar-vin: enable Gen3 hardware configuration Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 20/33] rcar-vin: add function to manipulate Gen3 chsel value Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 21/33] rcar-vin: add flag to switch to media controller mode Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 22/33] rcar-vin: use different v4l2 operations in " Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 23/33] rcar-vin: force default colorspace for media centric mode Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 24/33] rcar-vin: prepare for media controller mode initialization Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 25/33] rcar-vin: add group allocator functions Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 26/33] rcar-vin: change name of video device Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 27/33] rcar-vin: add chsel information to rvin_info Niklas Söderlund
2018-04-14 11:57 ` Niklas Söderlund [this message]
2018-04-14 11:57 ` [PATCH v14 29/33] rcar-vin: add link notify for Gen3 Niklas Söderlund
2019-04-05 14:17   ` [PATCH v14,29/33] " Eugeniu Rosca
2019-04-05 14:34     ` Niklas Söderlund
2019-04-05 14:45       ` Eugeniu Rosca
2018-04-14 11:57 ` [PATCH v14 30/33] rcar-vin: extend {start,stop}_streaming to work with media controller Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 31/33] rcar-vin: enable support for r8a7795 Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 32/33] rcar-vin: enable support for r8a7796 Niklas Söderlund
2018-04-14 11:57 ` [PATCH v14 33/33] rcar-vin: enable support for r8a77970 Niklas Söderlund

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180414115726.5075-29-niklas.soderlund+renesas@ragnatech.se \
    --to=niklas.soderlund+renesas@ragnatech.se \
    --cc=hverkuil@xs4all.nl \
    --cc=kieran.bingham@ideasonboard.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-renesas-soc@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.