[PATCH 2/8] media: qcom: camss: create the source to CSIPHY link per endpoint

From: Hitesh Patel

Date: Mon Sep 14 2026 - 11:31:03 EST


The link from the external CSI-2 transmitter to the CSIPHY is created
in the notifier .complete() callback by walking every registered
subdev, reading the CSIPHY it was bound to from sd->host_priv and
linking the subdev's first source pad to that CSIPHY.

This assumes one transmitter feeds exactly one CSIPHY. A GMSL
deserializer such as the MAX9296A has two independent CSI-2 output
ports which, on the RB3 Gen2 vision mezzanine, are wired to two
different SoC CSIPHYs. The same subdev is then bound once per CAMSS
port endpoint, the second .bound() overwrites host_priv, and
.complete() creates a single link from source pad 0 to the last
CSIPHY. The second output port is left with no link at all, so a
second camera can never be routed to the SoC.

Move the link creation into .bound(), where both the endpoint and
the CSIPHY are known, and resolve the transmitter's source pad from
the endpoint fwnode with media_entity_get_fwnode_pad(). Each
endpoint then gets its own link between the right source pad and
the right CSIPHY.

For a subdev that does not implement .get_fwnode_pad,
media_entity_get_fwnode_pad() falls back to the first pad matching
the requested direction, which is exactly what the .complete() loop
did, so ordinary single-output sensors keep the same link as before.

Signed-off-by: Hitesh Patel <hitesh@xxxxxxxxxxxxxx>
---
drivers/media/platform/qcom/camss/camss.c | 51 ++++++++---------------
1 file changed, 18 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 16ad1c26c..4cf736d80 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -5231,49 +5231,34 @@ static int camss_subdev_notifier_bound(struct v4l2_async_notifier *async,
container_of(asd, struct camss_async_subdev, asd);
u8 id = csd->interface.csiphy_id;
struct csiphy_device *csiphy = &camss->csiphy[id];
+ struct media_entity *input = &csiphy->subdev.entity;
+ struct media_entity *sensor = &subdev->entity;
+ int pad, ret;

csiphy->cfg.csi2 = &csd->interface.csi2;
subdev->host_priv = csiphy;

+ pad = media_entity_get_fwnode_pad(sensor, asd->match.fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (pad < 0) {
+ dev_err(camss->dev, "No source pad in external entity %s: %d\n",
+ sensor->name, pad);
+ return pad;
+ }
+
+ ret = media_create_pad_link(sensor, pad, input, MSM_CSIPHY_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+ if (ret < 0) {
+ camss_link_err(camss, sensor->name, input->name, ret);
+ return ret;
+ }
+
return 0;
}

static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
{
struct camss *camss = container_of(async, struct camss, notifier);
- struct v4l2_device *v4l2_dev = &camss->v4l2_dev;
- struct v4l2_subdev *sd;
-
- list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
- struct csiphy_device *csiphy = sd->host_priv;
- struct media_entity *input, *sensor;
- unsigned int i;
- int ret;
-
- if (!csiphy)
- continue;
-
- input = &csiphy->subdev.entity;
- sensor = &sd->entity;
-
- for (i = 0; i < sensor->num_pads; i++) {
- if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
- break;
- }
- if (i == sensor->num_pads) {
- dev_err(camss->dev,
- "No source pad in external entity\n");
- return -EINVAL;
- }
-
- ret = media_create_pad_link(sensor, i, input,
- MSM_CSIPHY_PAD_SINK,
- MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
- if (ret < 0) {
- camss_link_err(camss, sensor->name, input->name, ret);
- return ret;
- }
- }

return v4l2_device_register_subdev_nodes(&camss->v4l2_dev);
}
--
2.43.0