]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: ti: cal: Add streams support
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Wed, 26 Mar 2025 11:34:03 +0000 (13:34 +0200)
committerHans Verkuil <hverkuil@xs4all.nl>
Fri, 25 Apr 2025 08:15:25 +0000 (10:15 +0200)
Add multiplexed streams support. CAL has 8 DMA-engines and can capture 8
separate streams at the same time. The driver filters the streams based
on CSI-2 virtual channel number and datatype. CAL may have (depending on
the SoC) two CSI-2 RX blocks, which share the 8 DMA-engines, so the
number of capturable streams does not change even if there are two CSI-2
RX blocks.

Add 8 video device nodes, each representing a single DMA-engine, and set
the number of source pads on CSI-2 RX blocks to 8. Each video node can be
connected to any of the source pads on either of the CSI-2 RX instances
using media links. CSI-2 RX block's subdevice internal routing is used
to route the incoming CSI-2 streams to one of the 8 source pads.

Only video data streams are supported at the moment.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
drivers/media/platform/ti/cal/cal-camerarx.c
drivers/media/platform/ti/cal/cal-video.c
drivers/media/platform/ti/cal/cal.c
drivers/media/platform/ti/cal/cal.h

index 9cc875665695625963e37bcdf93bc4b918291d42..00a71dac0ff4d6b0cd5e7bd55f227486f5e342ad 100644 (file)
@@ -49,21 +49,38 @@ static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy)
 {
        struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2;
        u32 num_lanes = mipi_csi2->num_data_lanes;
-       const struct cal_format_info *fmtinfo;
        struct v4l2_subdev_state *state;
-       struct v4l2_mbus_framefmt *fmt;
        u32 bpp;
        s64 freq;
 
+       /*
+        * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back
+        * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available.
+        *
+        * With multistream input there is no single pixel rate, and thus we
+        * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which
+        * causes v4l2_get_link_freq() to return an error if it falls back to
+        * V4L2_CID_PIXEL_RATE.
+        */
+
        state = v4l2_subdev_get_locked_active_state(&phy->subdev);
 
-       fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK);
+       if (state->routing.num_routes > 1) {
+               bpp = 0;
+       } else {
+               struct v4l2_subdev_route *route = &state->routing.routes[0];
+               const struct cal_format_info *fmtinfo;
+               struct v4l2_mbus_framefmt *fmt;
 
-       fmtinfo = cal_format_by_code(fmt->code);
-       if (!fmtinfo)
-               return -EINVAL;
+               fmt = v4l2_subdev_state_get_format(state, route->sink_pad,
+                                                  route->sink_stream);
 
-       bpp = fmtinfo->bpp;
+               fmtinfo = cal_format_by_code(fmt->code);
+               if (!fmtinfo)
+                       return -EINVAL;
+
+               bpp = fmtinfo->bpp;
+       }
 
        freq = v4l2_get_link_freq(&phy->source->entity.pads[phy->source_pad],
                                  bpp, 2 * num_lanes);
@@ -285,15 +302,32 @@ static void cal_camerarx_ppi_disable(struct cal_camerarx *phy)
                        0, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
 }
 
-static int cal_camerarx_start(struct cal_camerarx *phy)
+static int cal_camerarx_start(struct cal_camerarx *phy, u32 sink_stream)
 {
+       struct media_pad *remote_pad;
        s64 link_freq;
        u32 sscounter;
        u32 val;
        int ret;
 
+       remote_pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]);
+
+       /*
+        * We need to enable the PHY hardware when enabling the first stream,
+        * but for the following streams we just propagate the enable_streams
+        * to the source.
+        */
+
        if (phy->enable_count > 0) {
+               ret = v4l2_subdev_enable_streams(phy->source, remote_pad->index,
+                                                BIT(sink_stream));
+               if (ret) {
+                       phy_err(phy, "enable streams failed in source: %d\n", ret);
+                       return ret;
+               }
+
                phy->enable_count++;
+
                return 0;
        }
 
@@ -395,7 +429,8 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
         * Start the source to enable the CSI-2 HS clock. We can now wait for
         * CSI-2 PHY reset to complete.
         */
-       ret = v4l2_subdev_call(phy->source, video, s_stream, 1);
+       ret = v4l2_subdev_enable_streams(phy->source, remote_pad->index,
+                                        BIT(sink_stream));
        if (ret) {
                v4l2_subdev_call(phy->source, core, s_power, 0);
                cal_camerarx_disable_irqs(phy);
@@ -426,12 +461,22 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
        return 0;
 }
 
-static void cal_camerarx_stop(struct cal_camerarx *phy)
+static void cal_camerarx_stop(struct cal_camerarx *phy, u32 sink_stream)
 {
+       struct media_pad *remote_pad;
        int ret;
 
-       if (--phy->enable_count > 0)
+       remote_pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]);
+
+       if (--phy->enable_count > 0) {
+               ret = v4l2_subdev_disable_streams(phy->source,
+                                                 remote_pad->index,
+                                                 BIT(sink_stream));
+               if (ret)
+                       phy_err(phy, "stream off failed in subdev\n");
+
                return;
+       }
 
        cal_camerarx_ppi_disable(phy);
 
@@ -451,7 +496,9 @@ static void cal_camerarx_stop(struct cal_camerarx *phy)
        /* Disable the phy */
        cal_camerarx_disable(phy);
 
-       if (v4l2_subdev_call(phy->source, video, s_stream, 0))
+       ret = v4l2_subdev_disable_streams(phy->source, remote_pad->index,
+                                         BIT(sink_stream));
+       if (ret)
                phy_err(phy, "stream off failed in subdev\n");
 
        ret = v4l2_subdev_call(phy->source, core, s_power, 0);
@@ -600,22 +647,50 @@ static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd)
        return container_of(sd, struct cal_camerarx, subdev);
 }
 
-static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
+struct cal_camerarx *
+cal_camerarx_get_phy_from_entity(struct media_entity *entity)
+{
+       struct v4l2_subdev *sd;
+
+       sd = media_entity_to_v4l2_subdev(entity);
+       if (!sd)
+               return NULL;
+
+       return to_cal_camerarx(sd);
+}
+
+static int cal_camerarx_sd_enable_streams(struct v4l2_subdev *sd,
+                                         struct v4l2_subdev_state *state,
+                                         u32 pad, u64 streams_mask)
 {
        struct cal_camerarx *phy = to_cal_camerarx(sd);
-       struct v4l2_subdev_state *state;
-       int ret = 0;
+       u32 sink_stream;
+       int ret;
 
-       state = v4l2_subdev_lock_and_get_active_state(sd);
+       ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, 0,
+                                                   NULL, &sink_stream);
+       if (ret)
+               return ret;
 
-       if (enable)
-               ret = cal_camerarx_start(phy);
-       else
-               cal_camerarx_stop(phy);
+       return cal_camerarx_start(phy, sink_stream);
+}
 
-       v4l2_subdev_unlock_state(state);
+static int cal_camerarx_sd_disable_streams(struct v4l2_subdev *sd,
+                                          struct v4l2_subdev_state *state,
+                                          u32 pad, u64 streams_mask)
+{
+       struct cal_camerarx *phy = to_cal_camerarx(sd);
+       u32 sink_stream;
+       int ret;
 
-       return ret;
+       ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, 0,
+                                                   NULL, &sink_stream);
+       if (ret)
+               return ret;
+
+       cal_camerarx_stop(phy, sink_stream);
+
+       return 0;
 }
 
 static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
@@ -629,8 +704,12 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index > 0)
                        return -EINVAL;
 
-               fmt = v4l2_subdev_state_get_format(state,
-                                                  CAL_CAMERARX_PAD_SINK);
+               fmt = v4l2_subdev_state_get_opposite_stream_format(state,
+                                                                  code->pad,
+                                                                  code->stream);
+               if (!fmt)
+                       return -EINVAL;
+
                code->code = fmt->code;
        } else {
                if (code->index >= cal_num_formats)
@@ -655,8 +734,12 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
        if (cal_rx_pad_is_source(fse->pad)) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_state_get_format(state,
-                                                  CAL_CAMERARX_PAD_SINK);
+               fmt = v4l2_subdev_state_get_opposite_stream_format(state,
+                                                                  fse->pad,
+                                                                  fse->stream);
+               if (!fmt)
+                       return -EINVAL;
+
                if (fse->code != fmt->code)
                        return -EINVAL;
 
@@ -712,36 +795,77 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
 
        /* Store the format and propagate it to the source pad. */
 
-       fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK);
+       fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+       if (!fmt)
+               return -EINVAL;
+
        *fmt = format->format;
 
-       fmt = v4l2_subdev_state_get_format(state,
-                                          CAL_CAMERARX_PAD_FIRST_SOURCE);
+       fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+                                                          format->stream);
+       if (!fmt)
+               return -EINVAL;
+
        *fmt = format->format;
 
        return 0;
 }
 
+static int cal_camerarx_set_routing(struct v4l2_subdev *sd,
+                                   struct v4l2_subdev_state *state,
+                                   struct v4l2_subdev_krouting *routing)
+{
+       static const struct v4l2_mbus_framefmt format = {
+               .width = 640,
+               .height = 480,
+               .code = MEDIA_BUS_FMT_UYVY8_1X16,
+               .field = V4L2_FIELD_NONE,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .ycbcr_enc = V4L2_YCBCR_ENC_601,
+               .quantization = V4L2_QUANTIZATION_LIM_RANGE,
+               .xfer_func = V4L2_XFER_FUNC_SRGB,
+       };
+       int ret;
+
+       ret = v4l2_subdev_routing_validate(sd, routing,
+                                          V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 |
+                                          V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING);
+       if (ret)
+               return ret;
+
+       ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int cal_camerarx_sd_set_routing(struct v4l2_subdev *sd,
+                                      struct v4l2_subdev_state *state,
+                                      enum v4l2_subdev_format_whence which,
+                                      struct v4l2_subdev_krouting *routing)
+{
+       return cal_camerarx_set_routing(sd, state, routing);
+}
+
 static int cal_camerarx_sd_init_state(struct v4l2_subdev *sd,
                                      struct v4l2_subdev_state *state)
 {
-       struct v4l2_subdev_format format = {
-               .which = state ? V4L2_SUBDEV_FORMAT_TRY
-               : V4L2_SUBDEV_FORMAT_ACTIVE,
-               .pad = CAL_CAMERARX_PAD_SINK,
-               .format = {
-                       .width = 640,
-                       .height = 480,
-                       .code = MEDIA_BUS_FMT_UYVY8_1X16,
-                       .field = V4L2_FIELD_NONE,
-                       .colorspace = V4L2_COLORSPACE_SRGB,
-                       .ycbcr_enc = V4L2_YCBCR_ENC_601,
-                       .quantization = V4L2_QUANTIZATION_LIM_RANGE,
-                       .xfer_func = V4L2_XFER_FUNC_SRGB,
-               },
+       struct v4l2_subdev_route routes[] = { {
+               .sink_pad = 0,
+               .sink_stream = 0,
+               .source_pad = 1,
+               .source_stream = 0,
+               .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+       } };
+
+       struct v4l2_subdev_krouting routing = {
+               .num_routes = 1,
+               .routes = routes,
        };
 
-       return cal_camerarx_sd_set_fmt(sd, state, &format);
+       /* Initialize routing to single route to the fist source pad */
+       return cal_camerarx_set_routing(sd, state, &routing);
 }
 
 static int cal_camerarx_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
@@ -750,48 +874,71 @@ static int cal_camerarx_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
        struct cal_camerarx *phy = to_cal_camerarx(sd);
        struct v4l2_mbus_frame_desc remote_desc;
        const struct media_pad *remote_pad;
+       struct v4l2_subdev_state *state;
+       u32 sink_stream;
+       unsigned int i;
        int ret;
 
+       state = v4l2_subdev_lock_and_get_active_state(sd);
+
+       ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
+                                                   pad, 0,
+                                                   NULL, &sink_stream);
+       if (ret)
+               goto out_unlock;
+
        remote_pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]);
-       if (!remote_pad)
-               return -EPIPE;
+       if (!remote_pad) {
+               ret = -EPIPE;
+               goto out_unlock;
+       }
 
        ret = v4l2_subdev_call(phy->source, pad, get_frame_desc,
                               remote_pad->index, &remote_desc);
        if (ret)
-               return ret;
+               goto out_unlock;
 
        if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
                cal_err(phy->cal,
                        "Frame descriptor does not describe CSI-2 link");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_unlock;
        }
 
-       if (remote_desc.num_entries > 1)
-               cal_err(phy->cal,
-                       "Multiple streams not supported in remote frame descriptor, using the first one\n");
+       for (i = 0; i < remote_desc.num_entries; i++) {
+               if (remote_desc.entry[i].stream == sink_stream)
+                       break;
+       }
+
+       if (i == remote_desc.num_entries) {
+               cal_err(phy->cal, "Stream %u not found in remote frame desc\n",
+                       sink_stream);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
        fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
        fd->num_entries = 1;
-       fd->entry[0] = remote_desc.entry[0];
+       fd->entry[0] = remote_desc.entry[i];
 
-       return 0;
-}
+out_unlock:
+       v4l2_subdev_unlock_state(state);
 
-static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
-       .s_stream = cal_camerarx_sd_s_stream,
-};
+       return ret;
+}
 
 static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = {
+       .enable_streams = cal_camerarx_sd_enable_streams,
+       .disable_streams = cal_camerarx_sd_disable_streams,
        .enum_mbus_code = cal_camerarx_sd_enum_mbus_code,
        .enum_frame_size = cal_camerarx_sd_enum_frame_size,
        .get_fmt = v4l2_subdev_get_fmt,
        .set_fmt = cal_camerarx_sd_set_fmt,
+       .set_routing = cal_camerarx_sd_set_routing,
        .get_frame_desc = cal_camerarx_get_frame_desc,
 };
 
 static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = {
-       .video = &cal_camerarx_video_ops,
        .pad = &cal_camerarx_pad_ops,
 };
 
@@ -801,6 +948,7 @@ static const struct v4l2_subdev_internal_ops cal_camerarx_internal_ops = {
 
 static const struct media_entity_operations cal_camerarx_media_ops = {
        .link_validate = v4l2_subdev_link_validate,
+       .has_pad_interdep = v4l2_subdev_has_pad_interdep,
 };
 
 /* ------------------------------------------------------------------
@@ -852,7 +1000,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
        v4l2_subdev_init(sd, &cal_camerarx_subdev_ops);
        sd->internal_ops = &cal_camerarx_internal_ops;
        sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
-       sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
        snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance);
        sd->dev = cal->dev;
 
index 29c38bf8d7a1a83ed9989f3d7e3df3009ba0ca7f..d40e24ab112783f861cf07bdc1cfcca8dcf84fdd 100644 (file)
@@ -108,9 +108,10 @@ static int __subdev_get_format(struct cal_ctx *ctx,
                .pad = 0,
        };
        struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+       struct v4l2_subdev *sd = ctx->phy->source;
        int ret;
 
-       ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt);
+       ret = v4l2_subdev_call_state_active(sd, pad, get_fmt, &sd_fmt);
        if (ret)
                return ret;
 
@@ -130,11 +131,12 @@ static int __subdev_set_format(struct cal_ctx *ctx,
                .pad = 0,
        };
        struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+       struct v4l2_subdev *sd = ctx->phy->source;
        int ret;
 
        *mbus_fmt = *fmt;
 
-       ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt);
+       ret = v4l2_subdev_call_state_active(sd, pad, set_fmt, &sd_fmt);
        if (ret)
                return ret;
 
@@ -176,6 +178,7 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
                                      struct v4l2_format *f)
 {
        struct cal_ctx *ctx = video_drvdata(file);
+       struct v4l2_subdev *sd = ctx->phy->source;
        const struct cal_format_info *fmtinfo;
        struct v4l2_subdev_frame_size_enum fse = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -201,8 +204,8 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
        for (fse.index = 0; ; fse.index++) {
                int ret;
 
-               ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size,
-                                      NULL, &fse);
+               ret = v4l2_subdev_call_state_active(sd, pad, enum_frame_size,
+                                                   &fse);
                if (ret)
                        break;
 
@@ -238,6 +241,7 @@ static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
                                    struct v4l2_format *f)
 {
        struct cal_ctx *ctx = video_drvdata(file);
+       struct v4l2_subdev *sd = &ctx->phy->subdev;
        struct vb2_queue *q = &ctx->vb_vidq;
        struct v4l2_subdev_format sd_fmt = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -277,7 +281,7 @@ static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
        ctx->v_fmt.fmt.pix.field = sd_fmt.format.field;
        cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
 
-       v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt);
+       v4l2_subdev_call_state_active(sd, pad, set_fmt, &sd_fmt);
 
        ctx->fmtinfo = fmtinfo;
        *f = ctx->v_fmt;
@@ -289,6 +293,7 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
                                      struct v4l2_frmsizeenum *fsize)
 {
        struct cal_ctx *ctx = video_drvdata(file);
+       struct v4l2_subdev *sd = ctx->phy->source;
        const struct cal_format_info *fmtinfo;
        struct v4l2_subdev_frame_size_enum fse = {
                .index = fsize->index,
@@ -307,8 +312,7 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
 
        fse.code = fmtinfo->code;
 
-       ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL,
-                              &fse);
+       ret = v4l2_subdev_call_state_active(sd, pad, enum_frame_size, &fse);
        if (ret)
                return ret;
 
@@ -350,6 +354,7 @@ static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
                                          struct v4l2_frmivalenum *fival)
 {
        struct cal_ctx *ctx = video_drvdata(file);
+       struct v4l2_subdev *sd = ctx->phy->source;
        const struct cal_format_info *fmtinfo;
        struct v4l2_subdev_frame_interval_enum fie = {
                .index = fival->index,
@@ -364,8 +369,8 @@ static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
                return -EINVAL;
 
        fie.code = fmtinfo->code;
-       ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval,
-                              NULL, &fie);
+
+       ret = v4l2_subdev_call_state_active(sd, pad, enum_frame_interval, &fie);
        if (ret)
                return ret;
        fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
@@ -432,6 +437,9 @@ static int cal_mc_enum_fmt_vid_cap(struct file *file, void  *priv,
        idx = 0;
 
        for (i = 0; i < cal_num_formats; ++i) {
+               if (cal_formats[i].meta)
+                       continue;
+
                if (f->mbus_code && cal_formats[i].code != f->mbus_code)
                        continue;
 
@@ -459,7 +467,7 @@ static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f,
         * supported.
         */
        fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat);
-       if (!fmtinfo)
+       if (!fmtinfo || fmtinfo->meta)
                fmtinfo = &cal_formats[0];
 
        /*
@@ -675,16 +683,16 @@ static int cal_video_check_format(struct cal_ctx *ctx)
 {
        const struct v4l2_mbus_framefmt *format;
        struct v4l2_subdev_state *state;
-       struct media_pad *remote_pad;
+       struct media_pad *phy_source_pad;
        int ret = 0;
 
-       remote_pad = media_pad_remote_pad_first(&ctx->pad);
-       if (!remote_pad)
+       phy_source_pad = media_pad_remote_pad_first(&ctx->pad);
+       if (!phy_source_pad)
                return -ENODEV;
 
        state = v4l2_subdev_lock_and_get_active_state(&ctx->phy->subdev);
 
-       format = v4l2_subdev_state_get_format(state, remote_pad->index);
+       format = v4l2_subdev_state_get_format(state, phy_source_pad->index, 0);
        if (!format) {
                ret = -EINVAL;
                goto out;
@@ -707,16 +715,28 @@ out:
 static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
+       struct media_pad *phy_source_pad;
        struct cal_buffer *buf;
        dma_addr_t addr;
        int ret;
 
+       phy_source_pad = media_pad_remote_pad_first(&ctx->pad);
+       if (!phy_source_pad) {
+               ctx_err(ctx, "Context not connected\n");
+               ret = -ENODEV;
+               goto error_release_buffers;
+       }
+
        ret = video_device_pipeline_alloc_start(&ctx->vdev);
        if (ret < 0) {
                ctx_err(ctx, "Failed to start media pipeline: %d\n", ret);
                goto error_release_buffers;
        }
 
+       /* Find the PHY connected to this video device */
+       if (cal_mc_api)
+               ctx->phy = cal_camerarx_get_phy_from_entity(phy_source_pad->entity);
+
        /*
         * Verify that the currently configured format matches the output of
         * the connected CAMERARX.
@@ -749,7 +769,8 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
        cal_ctx_set_dma_addr(ctx, addr);
        cal_ctx_start(ctx);
 
-       ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1);
+       ret = v4l2_subdev_enable_streams(&ctx->phy->subdev,
+                                        phy_source_pad->index, BIT(0));
        if (ret)
                goto error_stop;
 
@@ -774,10 +795,14 @@ error_release_buffers:
 static void cal_stop_streaming(struct vb2_queue *vq)
 {
        struct cal_ctx *ctx = vb2_get_drv_priv(vq);
+       struct media_pad *phy_source_pad;
 
        cal_ctx_stop(ctx);
 
-       v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 0);
+       phy_source_pad = media_pad_remote_pad_first(&ctx->pad);
+
+       v4l2_subdev_disable_streams(&ctx->phy->subdev, phy_source_pad->index,
+                                   BIT(0));
 
        pm_runtime_put_sync(ctx->cal->dev);
 
@@ -786,6 +811,9 @@ static void cal_stop_streaming(struct vb2_queue *vq)
        cal_release_buffers(ctx, VB2_BUF_STATE_ERROR);
 
        video_device_pipeline_stop(&ctx->vdev);
+
+       if (cal_mc_api)
+               ctx->phy = NULL;
 }
 
 static const struct vb2_ops cal_video_qops = {
@@ -812,6 +840,7 @@ static const struct v4l2_file_operations cal_fops = {
 
 static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
 {
+       struct v4l2_subdev *sd = ctx->phy->source;
        struct v4l2_mbus_framefmt mbus_fmt;
        const struct cal_format_info *fmtinfo;
        unsigned int i, j, k;
@@ -831,20 +860,20 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
                        .which = V4L2_SUBDEV_FORMAT_ACTIVE,
                };
 
-               ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
-                                      NULL, &mbus_code);
+               ret = v4l2_subdev_call_state_active(sd, pad, enum_mbus_code,
+                                                   &mbus_code);
                if (ret == -EINVAL)
                        break;
 
                if (ret) {
                        ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
-                               ctx->phy->source->name, ret);
+                               sd->name, ret);
                        return ret;
                }
 
                ctx_dbg(2, ctx,
                        "subdev %s: code: %04x idx: %u\n",
-                       ctx->phy->source->name, mbus_code.code, j);
+                       sd->name, mbus_code.code, j);
 
                for (k = 0; k < cal_num_formats; k++) {
                        fmtinfo = &cal_formats[k];
@@ -862,7 +891,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
 
        if (i == 0) {
                ctx_err(ctx, "No suitable format reported by subdev %s\n",
-                       ctx->phy->source->name);
+                       sd->name);
                return -EINVAL;
        }
 
@@ -948,16 +977,52 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx)
                return ret;
        }
 
-       ret = media_create_pad_link(&ctx->phy->subdev.entity,
-                                   CAL_CAMERARX_PAD_FIRST_SOURCE,
-                                   &vfd->entity, 0,
-                                   MEDIA_LNK_FL_IMMUTABLE |
-                                   MEDIA_LNK_FL_ENABLED);
-       if (ret) {
-               ctx_err(ctx, "Failed to create media link for context %u\n",
-                       ctx->dma_ctx);
-               video_unregister_device(vfd);
-               return ret;
+       if (cal_mc_api) {
+               u16 phy_idx;
+               u16 pad_idx;
+
+               /* Create links from all video nodes to all PHYs */
+
+               for (phy_idx = 0; phy_idx < ctx->cal->data->num_csi2_phy;
+                    ++phy_idx) {
+                       struct media_entity *phy_entity =
+                               &ctx->cal->phy[phy_idx]->subdev.entity;
+
+                       for (pad_idx = 1; pad_idx < CAL_CAMERARX_NUM_PADS;
+                            ++pad_idx) {
+                               /*
+                                * Enable only links from video0 to PHY0 pad 1,
+                                * and video1 to PHY1 pad 1.
+                                */
+                               bool enable = (ctx->dma_ctx == 0 &&
+                                              phy_idx == 0 && pad_idx == 1) ||
+                                             (ctx->dma_ctx == 1 &&
+                                              phy_idx == 1 && pad_idx == 1);
+
+                               ret = media_create_pad_link(phy_entity, pad_idx,
+                                                           &vfd->entity, 0,
+                                                           enable ? MEDIA_LNK_FL_ENABLED : 0);
+                               if (ret) {
+                                       ctx_err(ctx,
+                                               "Failed to create media link for context %u\n",
+                                               ctx->dma_ctx);
+                                       video_unregister_device(vfd);
+                                       return ret;
+                               }
+                       }
+               }
+       } else {
+               ret = media_create_pad_link(&ctx->phy->subdev.entity,
+                                           CAL_CAMERARX_PAD_FIRST_SOURCE,
+                                           &vfd->entity, 0,
+                                           MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+               if (ret) {
+                       ctx_err(ctx,
+                               "Failed to create media link for context %u\n",
+                               ctx->dma_ctx);
+                       video_unregister_device(vfd);
+                       return ret;
+               }
        }
 
        ctx_info(ctx, "V4L2 device registered as %s\n",
index 6cb3e5f4968623aef06927d8ec7b130f1000d286..b644ed890412104887ce3ec32b5024a02a9676c8 100644 (file)
@@ -481,8 +481,9 @@ int cal_ctx_prepare(struct cal_ctx *ctx)
                ctx->vc = 0;
                ctx->datatype = CAL_CSI2_CTX_DT_ANY;
        } else if (!ret) {
-               ctx_dbg(2, ctx, "Framedesc: len %u, vc %u, dt %#x\n",
-                       entry.length, entry.bus.csi2.vc, entry.bus.csi2.dt);
+               ctx_dbg(2, ctx, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
+                       entry.stream, entry.length, entry.bus.csi2.vc,
+                       entry.bus.csi2.dt);
 
                ctx->vc = entry.bus.csi2.vc;
                ctx->datatype = entry.bus.csi2.dt;
@@ -490,7 +491,7 @@ int cal_ctx_prepare(struct cal_ctx *ctx)
                return ret;
        }
 
-       ctx->use_pix_proc = !ctx->fmtinfo->meta;
+       ctx->use_pix_proc = ctx->vb_vidq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        if (ctx->use_pix_proc) {
                ret = cal_reserve_pix_proc(ctx->cal);
@@ -1016,7 +1017,6 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst)
                return NULL;
 
        ctx->cal = cal;
-       ctx->phy = cal->phy[inst];
        ctx->dma_ctx = inst;
        ctx->csi2_ctx = inst;
        ctx->cport = inst;
@@ -1228,18 +1228,37 @@ static int cal_probe(struct platform_device *pdev)
        }
 
        /* Create contexts. */
-       for (i = 0; i < cal->data->num_csi2_phy; ++i) {
-               if (!cal->phy[i]->source_node)
-                       continue;
+       if (!cal_mc_api) {
+               for (i = 0; i < cal->data->num_csi2_phy; ++i) {
+                       struct cal_ctx *ctx;
+
+                       if (!cal->phy[i]->source_node)
+                               continue;
+
+                       ctx = cal_ctx_create(cal, i);
+                       if (!ctx) {
+                               cal_err(cal, "Failed to create context %u\n", cal->num_contexts);
+                               ret = -ENODEV;
+                               goto error_context;
+                       }
+
+                       ctx->phy = cal->phy[i];
 
-               cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i);
-               if (!cal->ctx[cal->num_contexts]) {
-                       cal_err(cal, "Failed to create context %u\n", cal->num_contexts);
-                       ret = -ENODEV;
-                       goto error_context;
+                       cal->ctx[cal->num_contexts++] = ctx;
                }
+       } else {
+               for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
+                       struct cal_ctx *ctx;
+
+                       ctx = cal_ctx_create(cal, i);
+                       if (!ctx) {
+                               cal_err(cal, "Failed to create context %u\n", i);
+                               ret = -ENODEV;
+                               goto error_context;
+                       }
 
-               cal->num_contexts++;
+                       cal->ctx[cal->num_contexts++] = ctx;
+               }
        }
 
        /* Register the media device. */
index 72a246a64d9e136d22054078b39202e338e35ab8..33b1885aafe1bc5dda737ddb940ee6ffb31cc7aa 100644 (file)
@@ -45,7 +45,7 @@
 
 #define CAL_CAMERARX_PAD_SINK          0
 #define CAL_CAMERARX_PAD_FIRST_SOURCE  1
-#define CAL_CAMERARX_NUM_SOURCE_PADS   1
+#define CAL_CAMERARX_NUM_SOURCE_PADS   8
 #define CAL_CAMERARX_NUM_PADS          (1 + CAL_CAMERARX_NUM_SOURCE_PADS)
 
 static inline bool cal_rx_pad_is_sink(u32 pad)
@@ -320,6 +320,7 @@ const struct cal_format_info *cal_format_by_code(u32 code);
 
 void cal_quickdump_regs(struct cal_dev *cal);
 
+struct cal_camerarx *cal_camerarx_get_phy_from_entity(struct media_entity *entity);
 void cal_camerarx_disable(struct cal_camerarx *phy);
 void cal_camerarx_i913_errata(struct cal_camerarx *phy);
 struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,