On Tue Sep 8 09:33:13 2026 +0300, Tomi Valkeinen wrote:
> Call get_frame_desc to find out VC & DT, for Gen3 platforms, instead of
> hardcoding the VC routing and deducing the DT based on the mbus format.
> 
> If the source subdevice doesn't implement .get_frame_desc, we use a
> fallback case where we assume there's a single stream with VC = 0 and DT
> based on the mbus format.
> 
> Reviewed-by: Niklas Söderlund <[email protected]>
> Tested-by: Niklas Söderlund <[email protected]>
> Signed-off-by: Tomi Valkeinen <[email protected]>
> Signed-off-by: Sakari Ailus <[email protected]>

Patch committed.

Thanks,
Sakari Ailus

 drivers/media/platform/renesas/rcar-csi2.c | 111 ++++++++++++++++++-----------
 1 file changed, 71 insertions(+), 40 deletions(-)

---

diff --git a/drivers/media/platform/renesas/rcar-csi2.c 
b/drivers/media/platform/renesas/rcar-csi2.c
index 7bff2fe8daad..65e3c9decfa4 100644
--- a/drivers/media/platform/renesas/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-csi2.c
@@ -1069,62 +1069,93 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv,
 static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv,
                                     struct v4l2_subdev_state *state)
 {
-       const struct v4l2_subdev_route *route;
-       const struct rcar_csi2_format *format;
-       u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
-       const struct v4l2_mbus_framefmt *fmt;
+       u32 phycnt, vcdt = 0, vcdt2 = 0;
+       u32 fld = FLD_DET_SEL(1);
+       struct v4l2_mbus_frame_desc source_fd;
+       struct v4l2_subdev_route *route;
        unsigned int lanes;
-       unsigned int i;
        int mbps, ret;
+       u8 ch = 0;
 
-       /* Use the format on the sink pad to compute the receiver config. */
+       ret = v4l2_subdev_call(priv->remote, pad, get_frame_desc,
+                              priv->remote_pad, &source_fd);
+       if (ret && ret != -ENOIOCTLCMD)
+               return ret;
 
-       if (state->routing.num_routes != 1)
-               return -EINVAL;
+       if (ret == -ENOIOCTLCMD) {
+               /* Create a fallback source_fd */
+               struct v4l2_mbus_frame_desc *fd = &source_fd;
+               const struct v4l2_subdev_route *route;
+               const struct rcar_csi2_format *format;
+               struct v4l2_mbus_framefmt *fmt;
 
-       route = &state->routing.routes[0];
+               if (state->routing.num_routes != 1)
+                       return -EINVAL;
 
-       fmt = v4l2_subdev_state_get_format(state, route->sink_pad,
-                                          route->sink_stream);
-       if (!fmt)
-               return -EINVAL;
+               route = &state->routing.routes[0];
 
-       dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
-               fmt->width, fmt->height,
-               fmt->field == V4L2_FIELD_NONE ? 'p' : 'i');
+               fmt = v4l2_subdev_state_get_format(state, route->sink_pad,
+                                                  route->sink_stream);
+               if (!fmt)
+                       return -EINVAL;
 
-       /* Code is validated in set_fmt. */
-       format = rcsi2_code_to_fmt(fmt->code);
-       if (!format)
-               return -EINVAL;
+               format = rcsi2_code_to_fmt(fmt->code);
+               if (!format)
+                       return -EINVAL;
 
-       /*
-        * Enable all supported CSI-2 channels with virtual channel and
-        * data type matching.
-        *
-        * NOTE: It's not possible to get individual datatype for each
-        *       source virtual channel. Once this is possible in V4L2
-        *       it should be used here.
-        */
-       for (i = 0; i < priv->info->num_channels; i++) {
+               memset(fd, 0, sizeof(*fd));
+
+               fd->num_entries = 1;
+               fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+               fd->entry[0].stream = 0;
+               fd->entry[0].pixelcode = fmt->code;
+               fd->entry[0].bus.csi2.vc = 0;
+               fd->entry[0].bus.csi2.dt = format->datatype;
+       }
+
+       for_each_active_route(&state->routing, route) {
+               const struct v4l2_mbus_frame_desc_entry *source_entry = NULL;
+               const struct v4l2_mbus_framefmt *fmt;
+               unsigned int i;
                u32 vcdt_part;
 
-               if (priv->channel_vc[i] < 0)
-                       continue;
+               for (i = 0; i < source_fd.num_entries; i++) {
+                       if (source_fd.entry[i].stream == route->sink_stream) {
+                               source_entry = &source_fd.entry[i];
+                               break;
+                       }
+               }
 
-               vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN |
-                       VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype);
+               if (!source_entry) {
+                       dev_err(priv->dev,
+                               "Failed to find stream from source frame 
desc\n");
+                       return -EPIPE;
+               }
+
+               vcdt_part = VCDT_SEL_VC(source_entry->bus.csi2.vc) |
+                           VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
+                           VCDT_SEL_DT(source_entry->bus.csi2.dt);
 
                /* Store in correct reg and offset. */
-               if (i < 2)
-                       vcdt |= vcdt_part << ((i % 2) * 16);
+               if (ch < 2)
+                       vcdt |= vcdt_part << ((ch % 2) * 16);
                else
-                       vcdt2 |= vcdt_part << ((i % 2) * 16);
-       }
+                       vcdt2 |= vcdt_part << ((ch % 2) * 16);
+
+               fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK,
+                                                  route->sink_stream);
+               if (!fmt)
+                       return -EINVAL;
+
+               dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
+                       fmt->width, fmt->height,
+                       fmt->field == V4L2_FIELD_NONE ? 'p' : 'i');
 
-       if (fmt->field == V4L2_FIELD_ALTERNATE)
-               fld = FLD_DET_SEL(1) | FLD_FLD_EN(3) | FLD_FLD_EN(2) |
-                     FLD_FLD_EN(1) | FLD_FLD_EN(0);
+               if (fmt->field == V4L2_FIELD_ALTERNATE)
+                       fld |= FLD_FLD_EN(ch);
+
+               ch++;
+       }
 
        /*
         * Get the number of active data lanes inspecting the remote mbus
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to