diff --git a/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c b/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c index 5c5275cb8aa4..4e6930a3aac9 100644 --- a/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c +++ b/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c @@ -185,7 +185,36 @@ static struct v4l2_subdev_ops csi2_be_soc_sd_ops = { .pad = &csi2_be_soc_sd_pad_ops, }; +static int csi2_be_soc_link_validate(struct media_link *link) +{ + struct media_pipeline *media_pipe; + struct ipu_isys_pipeline *ip; + struct v4l2_subdev *source_sd; + struct v4l2_subdev *sink_sd; + struct v4l2_subdev_format fmt = { 0 }; + + if (!link->sink->entity || !link->source->entity) + return -EINVAL; + media_pipe = media_entity_pipeline(link->sink->entity); + if (!media_pipe) + return -EINVAL; + + ip = to_ipu_isys_pipeline(media_pipe); + source_sd = media_entity_to_v4l2_subdev(link->source->entity); + sink_sd = media_entity_to_v4l2_subdev(link->sink->entity); + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + fmt.pad = CSI2_PAD_SOURCE; + v4l2_subdev_call(source_sd, pad, get_fmt, NULL, &fmt); + + fmt.pad = CSI2_BE_SOC_PAD_SINK; + v4l2_subdev_call(sink_sd, pad, set_fmt, NULL, &fmt); + return v4l2_subdev_link_validate(link); +} + static struct media_entity_operations csi2_be_soc_entity_ops = { + .link_validate = csi2_be_soc_link_validate, }; static void csi2_be_soc_set_ffmt(struct v4l2_subdev *sd, diff --git a/drivers/media/pci/intel/ipu-isys-csi2.c b/drivers/media/pci/intel/ipu-isys-csi2.c index 67914fd60f7d..75b9e0065dcb 100644 --- a/drivers/media/pci/intel/ipu-isys-csi2.c +++ b/drivers/media/pci/intel/ipu-isys-csi2.c @@ -333,6 +333,7 @@ static int csi2_link_validate(struct media_link *link) struct ipu_isys_pipeline *ip; struct v4l2_subdev *source_sd; struct v4l2_subdev *sink_sd; + struct v4l2_subdev_format fmt = { 0 }; int rval; @@ -352,6 +353,17 @@ static int csi2_link_validate(struct media_link *link) sink_sd = media_entity_to_v4l2_subdev(link->sink->entity); if (!source_sd) return -ENODEV; + /* source is external entity, get it's format */ + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = CSI2_PAD_SINK; + rval = v4l2_subdev_call(source_sd, pad, get_fmt, NULL, &fmt); + + /* set csi2 format for the same as external entity */ + rval = v4l2_subdev_call(sink_sd, pad, set_fmt, NULL, &fmt); + + rval = v4l2_subdev_link_validate(link); + if (rval) + return rval; if (strncmp(source_sd->name, IPU_ISYS_ENTITY_PREFIX, strlen(IPU_ISYS_ENTITY_PREFIX)) != 0) { diff --git a/drivers/media/pci/intel/ipu-isys-queue.c b/drivers/media/pci/intel/ipu-isys-queue.c index 6b0b74cc934f..df02813958e6 100644 --- a/drivers/media/pci/intel/ipu-isys-queue.c +++ b/drivers/media/pci/intel/ipu-isys-queue.c @@ -817,6 +817,14 @@ static int __start_streaming(struct vb2_queue *q, unsigned int count) mutex_unlock(&av->isys->stream_mutex); + rval = aq->link_fmt_validate(aq); + if (rval) { + dev_err(&av->isys->adev->dev, + "%s: link format validation failed (%d)\n", + av->vdev.name, rval); + goto out_unprepare_streaming; + } + ip = to_ipu_isys_pipeline(media_entity_pipeline(&av->vdev.entity)); pipe_av = container_of(ip, struct ipu_isys_video, ip); if (pipe_av != av) { @@ -872,6 +880,7 @@ static int __start_streaming(struct vb2_queue *q, unsigned int count) mutex_lock(&av->mutex); } +out_unprepare_streaming: mutex_lock(&av->isys->stream_mutex); if (first) ipu_isys_video_prepare_streaming(av, 0); diff --git a/drivers/media/pci/intel/ipu-isys-video.c b/drivers/media/pci/intel/ipu-isys-video.c index 2f76533f69f9..9824a65486cb 100644 --- a/drivers/media/pci/intel/ipu-isys-video.c +++ b/drivers/media/pci/intel/ipu-isys-video.c @@ -633,6 +633,9 @@ static int link_validate(struct media_link *link) struct ipu_isys_pipeline *ip = to_ipu_isys_pipeline(media_entity_pipeline(&av->vdev.entity)); struct v4l2_subdev *sd; + struct media_pad *source_pad = media_entity_remote_pad(&av->pad); + struct v4l2_subdev_format fmt = { 0 }; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; WARN_ON(!ip); if (!link->source->entity) @@ -650,6 +653,20 @@ static int link_validate(struct media_link *link) ip->nr_queues++; + /* set format for "CSI2 BE SOC" specific pad + * to be "BE SOC capture" av node format. + */ + fmt.format.width = av->mpix.width; + fmt.format.height = av->mpix.height; + fmt.format.code = av->pfmt->code; + fmt.format.field = av->mpix.field; + fmt.format.colorspace = av->mpix.colorspace; + fmt.format.ycbcr_enc = av->mpix.ycbcr_enc; + fmt.format.quantization = av->mpix.quantization; + fmt.format.xfer_func = av->mpix.xfer_func; + fmt.pad = source_pad->index; + v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); + return 0; }