@@ -168,10 +168,37 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags,
}
/* Add the new link to the existing mask and check if it works. */
- csi_id = rvin_group_entity_to_csi_id(group, link->source->entity);
channel = rvin_group_csi_pad_to_channel(link->source->index);
- mask_new = mask & rvin_group_get_mask(vin, csi_id, channel);
+ csi_id = rvin_group_entity_to_csi_id(group, link->source->entity);
+ if (csi_id == -ENODEV) {
+ struct v4l2_subdev *sd;
+ unsigned int i;
+
+ /*
+ * Make sure the source entity subdevice is registered as
+ * a digital input of one of the enabled VINs if it is not
+ * one of the CSI-2 subdevices.
+ *
+ * No hardware configuration required for digital inputs,
+ * we can return here.
+ */
+ sd = media_entity_to_v4l2_subdev(link->source->entity);
+
+ for (i = 0; i < RCAR_VIN_NUM; i++) {
+ if (group->vin[i] && group->vin[i]->digital &&
+ group->vin[i]->digital->subdev == sd) {
+ ret = 0;
+ goto out;
+ }
+ }
+ vin_err(vin, "Subdevice %s not registered to any VIN\n",
+ link->source->entity->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ mask_new = mask & rvin_group_get_mask(vin, csi_id, channel);
vin_dbg(vin, "Try link change mask: 0x%x new: 0x%x\n", mask, mask_new);
if (!mask_new) {
@@ -583,50 +610,70 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)
static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
{
- struct rvin_dev *vin = notifier_to_vin(notifier);
+ struct rvin_dev *gvin = notifier_to_vin(notifier);
const struct rvin_group_route *route;
+ struct media_entity *source;
+ struct media_entity *sink;
unsigned int i;
int ret;
- ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
+ ret = v4l2_device_register_subdev_nodes(&gvin->v4l2_dev);
if (ret) {
- vin_err(vin, "Failed to register subdev nodes\n");
+ vin_err(gvin, "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;
+ struct rvin_dev *ivin;
+
+ if (!gvin->group->vin[i])
+ continue;
+
+ /* Register all video nodes for the group. */
+ ivin = gvin->group->vin[i];
+ ret = rvin_v4l2_register(ivin);
+ if (ret)
+ return ret;
+
+ /* Link the digital input, if any. */
+ if (!ivin->digital || !ivin->digital->subdev)
+ continue;
+
+ source = &ivin->digital->subdev->entity;
+ sink = &ivin->vdev.entity;
+
+ ret = media_create_pad_link(source, ivin->digital->source_pad,
+ sink, ivin->digital->sink_pad, 0);
+ if (ret) {
+ vin_err(gvin, "Error adding link from %s to %s\n",
+ source->name, sink->name);
+ 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++) {
+ mutex_lock(&gvin->group->lock);
+ for (route = gvin->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])
+ if (!gvin->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)])
+ if (!gvin->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)
+ if (!gvin->group->csi[route->csi].subdev)
continue;
- source = &vin->group->csi[route->csi].subdev->entity;
+ source = &gvin->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 = &gvin->group->vin[route->vin]->vdev.entity;
sink_pad = &sink->pads[0];
/* Skip if link already exists. */
@@ -635,12 +682,12 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
ret = media_create_pad_link(source, source_idx, sink, 0, 0);
if (ret) {
- vin_err(vin, "Error adding link from %s to %s\n",
+ vin_err(gvin, "Error adding link from %s to %s\n",
source->name, sink->name);
break;
}
}
- mutex_unlock(&vin->group->lock);
+ mutex_unlock(&gvin->group->lock);
return ret;
}
@@ -650,6 +697,7 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct rvin_dev *vin = notifier_to_vin(notifier);
+ struct rvin_group *group = vin->group;
unsigned int i;
for (i = 0; i < RCAR_VIN_NUM; i++)
@@ -658,6 +706,23 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
mutex_lock(&vin->group->lock);
+ /* Check if this is a digital subdevice first, then try with CSI-2. */
+ for (i = 0; i < RCAR_VIN_NUM; i++)
+ if (group->vin[i] && group->vin[i]->digital &&
+ group->vin[i]->digital->asd.match.fwnode ==
+ asd->match.fwnode)
+ break;
+
+ if (i < RCAR_VIN_NUM) {
+ group->vin[i]->digital->subdev = NULL;
+ vin_dbg(vin, "Unbind digital subdevice %s from VIN %u\n",
+ subdev->name, i);
+
+ mutex_unlock(&vin->group->lock);
+
+ return;
+ }
+
for (i = 0; i < RVIN_CSI_MAX; i++) {
if (vin->group->csi[i].fwnode != asd->match.fwnode)
continue;
@@ -674,14 +739,36 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct rvin_dev *vin = notifier_to_vin(notifier);
+ struct rvin_group *group = vin->group;
unsigned int i;
- mutex_lock(&vin->group->lock);
+ mutex_lock(&group->lock);
+
+ /* Check if this is a digital subdevice first, then try with CSI-2. */
+ for (i = 0; i < RCAR_VIN_NUM; i++)
+ if (group->vin[i] && group->vin[i]->digital &&
+ group->vin[i]->digital->asd.match.fwnode ==
+ asd->match.fwnode)
+ break;
+
+ if (i < RCAR_VIN_NUM) {
+ group->vin[i]->digital->subdev = subdev;
+ group->vin[i]->digital->sink_pad = RVIN_PORT_DIGITAL;
+ group->vin[i]->digital->source_pad = rvin_find_pad(subdev,
+ MEDIA_PAD_FL_SOURCE);
+
+ vin_dbg(vin, "Bound digital subdevice %s to VIN %u\n",
+ subdev->name, i);
+
+ mutex_unlock(&vin->group->lock);
+
+ return 0;
+ }
for (i = 0; i < RVIN_CSI_MAX; i++) {
- if (vin->group->csi[i].fwnode != asd->match.fwnode)
+ if (group->csi[i].fwnode != asd->match.fwnode)
continue;
- vin->group->csi[i].subdev = subdev;
+ group->csi[i].subdev = subdev;
vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i);
break;
}
Add support for binding and unbinding digital subdevices to rcar-vin. On 'complete' also create direct links between the VIN instance and the digital subdevice. Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org> --- drivers/media/platform/rcar-vin/rcar-core.c | 133 +++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 23 deletions(-)