},
 };
 
-static void csid_configure_stream(struct csid_device *csid, u8 enable)
+static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc)
 {
        struct csid_testgen_config *tg = &csid->testgen;
        u32 val;
        u32 phy_sel = 0;
        u8 lane_cnt = csid->phy.lane_cnt;
-       struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+       /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
+       struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
        const struct csid_format *format = csid_get_fmt_entry(csid->formats, csid->nformats,
                                                              input_format->code);
 
                phy_sel = csid->phy.csiphy_id;
 
        if (enable) {
-               u8 vc = 0; /* Virtual Channel 0 */
-               u8 dt_id = vc * 4;
+               u8 dt_id = vc;
 
                if (tg->enabled) {
                        /* Config Test Generator */
                val |= format->data_type << RDI_CFG0_DATA_TYPE;
                val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
                val |= dt_id << RDI_CFG0_DT_ID;
-               writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+               writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
 
                /* CSID_TIMESTAMP_STB_POST_IRQ */
                val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
-               writel_relaxed(val, csid->base + CSID_RDI_CFG1(0));
+               writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc));
 
                val = 1;
-               writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(0));
+               writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc));
 
                val = 0;
-               writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(0));
+               writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc));
 
                val = 1;
-               writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(0));
+               writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc));
 
                val = 0;
-               writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(0));
+               writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc));
 
                val = 1;
-               writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(0));
+               writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc));
 
                val = 0;
-               writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(0));
+               writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc));
 
                val = 1;
-               writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(0));
+               writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc));
 
                val = 0;
-               writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(0));
+               writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc));
 
                val = 0;
-               writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+               writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
 
-               val = readl_relaxed(csid->base + CSID_RDI_CFG0(0));
+               val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc));
                val |=  1 << RDI_CFG0_ENABLE;
-               writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+               writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
        }
 
        if (tg->enabled) {
                val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
        else
                val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
-       writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+       writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
+}
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+       u8 i;
+       /* Loop through all enabled VCs and configure stream for each */
+       for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
+               if (csid->phy.en_vc & BIT(i))
+                       __csid_configure_stream(csid, enable, i);
 }
 
 static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
        struct csid_device *csid = dev;
        u32 val;
        u8 reset_done;
+       int i;
 
        val = readl_relaxed(csid->base + CSID_TOP_IRQ_STATUS);
        writel_relaxed(val, csid->base + CSID_TOP_IRQ_CLEAR);
        val = readl_relaxed(csid->base + CSID_CSI2_RX_IRQ_STATUS);
        writel_relaxed(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR);
 
-       val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(0));
-       writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(0));
+       /* Read and clear IRQ status for each enabled RDI channel */
+       for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
+               if (csid->phy.en_vc & BIT(i)) {
+                       val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i));
+                       writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i));
+               }
 
        val = 1 << IRQ_CMD_CLEAR;
        writel_relaxed(val, csid->base + CSID_IRQ_CMD);
 
                        return ret;
                }
 
+               csid->phy.need_vc_update = true;
+
                enable_irq(csid->irq);
 
                ret = csid->ops->reset(csid);
                        return -ENOLINK;
        }
 
-       csid->ops->configure_stream(csid, enable);
+       if (csid->phy.need_vc_update) {
+               csid->ops->configure_stream(csid, enable);
+               csid->phy.need_vc_update = false;
+       }
 
        return 0;
 }
 {
        struct csid_device *csid = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
+       int i;
 
        format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
        csid_try_format(csid, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
-       /* Propagate the format from sink to source */
+       /* Propagate the format from sink to source pads */
        if (fmt->pad == MSM_CSID_PAD_SINK) {
-               format = __csid_get_format(csid, sd_state, MSM_CSID_PAD_SRC,
-                                          fmt->which);
+               for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i) {
+                       format = __csid_get_format(csid, sd_state, i, fmt->which);
 
-               *format = fmt->format;
-               csid_try_format(csid, sd_state, MSM_CSID_PAD_SRC, format,
-                               fmt->which);
+                       *format = fmt->format;
+                       csid_try_format(csid, sd_state, i, format, fmt->which);
+               }
        }
 
        return 0;
                struct csid_device *csid;
                struct csiphy_device *csiphy;
                struct csiphy_lanes_cfg *lane_cfg;
-               struct v4l2_subdev_format format = { 0 };
 
                sd = media_entity_to_v4l2_subdev(entity);
                csid = v4l2_get_subdevdata(sd);
                lane_cfg = &csiphy->cfg.csi2->lane_cfg;
                csid->phy.lane_cnt = lane_cfg->num_data;
                csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
+       }
+       /* Decide which virtual channels to enable based on which source pads are enabled */
+       if (local->flags & MEDIA_PAD_FL_SOURCE) {
+               struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+               struct csid_device *csid = v4l2_get_subdevdata(sd);
+               struct device *dev = csid->camss->dev;
+
+               if (flags & MEDIA_LNK_FL_ENABLED)
+                       csid->phy.en_vc |= BIT(local->index - 1);
+               else
+                       csid->phy.en_vc &= ~BIT(local->index - 1);
 
-               /* Reset format on source pad to sink pad format */
-               format.pad = MSM_CSID_PAD_SRC;
-               format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-               csid_set_format(&csid->subdev, NULL, &format);
+               csid->phy.need_vc_update = true;
+
+               dev_dbg(dev, "%s: Enabled CSID virtual channels mask 0x%x\n",
+                       __func__, csid->phy.en_vc);
        }
 
        return 0;
        struct v4l2_subdev *sd = &csid->subdev;
        struct media_pad *pads = csid->pads;
        struct device *dev = csid->camss->dev;
+       int i;
        int ret;
 
        v4l2_subdev_init(sd, &csid_v4l2_ops);
        }
 
        pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-       pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+       for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i)
+               pads[i].flags = MEDIA_PAD_FL_SOURCE;
 
        sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
        sd->entity.ops = &csid_media_ops;