Re: [PATCH v2 4/4] media: ti: cal: Add multiplexed streams support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Tomi

On Tue, Feb 28, 2023 at 07:16:20PM +0200, Tomi Valkeinen wrote:
> Add routing and stream_config support to CAL driver.
>
> Add multiplexed streams support. CAL has 8 dma-engines and can capture 8
> separate streams at the same time.
>
> Add 8 video device nodes, each representing a single dma-engine, and set
> the number of source pads on camerarx to 8. Each video node can be
> connected to any of the source pads on either of the camerarx instances
> using media links. Camerarx internal routing is used to route the
> incoming CSI-2 streams to one of the 8 source pads.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx>
> ---
>  drivers/media/platform/ti/cal/cal-camerarx.c | 267 ++++++++++++++-----
>  drivers/media/platform/ti/cal/cal-video.c    | 121 ++++++---
>  drivers/media/platform/ti/cal/cal.c          |  43 ++-
>  drivers/media/platform/ti/cal/cal.h          |   3 +-
>  4 files changed, 330 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c
> index 95e0ad59a39b..8e373c817cdf 100644
> --- a/drivers/media/platform/ti/cal/cal-camerarx.c
> +++ b/drivers/media/platform/ti/cal/cal-camerarx.c
> @@ -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_get_pad_format(&phy->subdev, 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_stream_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->ctrl_handler, bpp, 2 * num_lanes);
>  	if (freq < 0) {
> @@ -284,15 +301,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;
>  	}
>
> @@ -394,7 +428,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);
> @@ -425,12 +460,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);
>
> @@ -450,7 +495,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);
> @@ -599,30 +646,56 @@ 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,
>  					  struct v4l2_subdev_state *state,
>  					  struct v4l2_subdev_mbus_code_enum *code)
>  {
> -	struct cal_camerarx *phy = to_cal_camerarx(sd);
> -
>  	/* No transcoding, source and sink codes must match. */
>  	if (cal_rx_pad_is_source(code->pad)) {
>  		struct v4l2_mbus_framefmt *fmt;
> @@ -630,8 +703,12 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
>  		if (code->index > 0)
>  			return -EINVAL;
>
> -		fmt = v4l2_subdev_get_pad_format(&phy->subdev, 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)
> @@ -656,8 +733,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_get_pad_format(sd, 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;
>
> @@ -713,36 +794,78 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
>
>  	/* Store the format and propagate it to the source pad. */
>
> -	fmt = v4l2_subdev_get_pad_format(sd, state, CAL_CAMERARX_PAD_SINK);
> +	fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
> +						  format->stream);
> +	if (!fmt)
> +		return -EINVAL;
> +
>  	*fmt = format->format;
>
> -	fmt = v4l2_subdev_get_pad_format(sd, 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_cfg(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,
> @@ -751,54 +874,76 @@ 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) {
>  		dev_err(phy->cal->dev,
>  			"Frame descriptor does not describe CSI-2 link");

I'm all for using standard debug functions, but the rest of the driver
uses cal_err etc. As long as this is intentional, I'm fine with it

> -		return -EINVAL;
> +		ret = -EINVAL;
> +		goto out_unlock;
> +	}
> +
> +	for (i = 0; i < remote_desc.num_entries; i++) {
> +		if (remote_desc.entry[i].stream == sink_stream)
> +			break;
>  	}
>
> -	if (remote_desc.num_entries > 1)
> -		dev_dbg(phy->cal->dev,
> -			"Multiple streams not supported in remote frame descriptor, using the first one\n");
> +	if (i == remote_desc.num_entries) {

I would have kept an error message here, or do you think this cannot
happen, or is it possible that a wrong implementation on the
transmitter's get_frame_desc could trigger it ?

All nits, to my understanding the rest looks good
Reviewed-by: Jacopo Mondi <jacopo.mondi@xxxxxxxxxxxxxxxx>

Thanks
  j


> +		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,
>  	.init_cfg = cal_camerarx_sd_init_cfg,
>  	.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,
>  };
>
>  static struct media_entity_operations cal_camerarx_media_ops = {
>  	.link_validate = v4l2_subdev_link_validate,
> +	.has_pad_interdep = v4l2_subdev_has_pad_interdep,
>  };
>
>  /* ------------------------------------------------------------------
> @@ -850,7 +995,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
>  	sd = &phy->subdev;
>  	v4l2_subdev_init(sd, &cal_camerarx_subdev_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;
>
> diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
> index a8abcd0fee17..00a79178a8b0 100644
> --- a/drivers/media/platform/ti/cal/cal-video.c
> +++ b/drivers/media/platform/ti/cal/cal-video.c
> @@ -122,9 +122,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;
>
> @@ -144,11 +145,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;
>
> @@ -190,6 +192,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,
> @@ -215,8 +218,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;
>
> @@ -252,6 +255,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,
> @@ -291,7 +295,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;
> @@ -303,6 +307,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,
> @@ -321,8 +326,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;
>
> @@ -364,6 +368,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,
> @@ -378,8 +383,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;
> @@ -688,16 +693,17 @@ 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_get_pad_format(&ctx->phy->subdev, state, remote_pad->index);
> +	format = v4l2_subdev_state_get_stream_format(state,
> +						     phy_source_pad->index, 0);
>  	if (!format) {
>  		ret = -EINVAL;
>  		goto out;
> @@ -720,16 +726,28 @@ static int cal_video_check_format(struct cal_ctx *ctx)
>  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.
> @@ -762,7 +780,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;
>
> @@ -787,10 +806,14 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
>  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);
>
> @@ -799,6 +822,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 = {
> @@ -827,6 +853,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;
> @@ -846,20 +873,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];
> @@ -877,7 +904,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;
>  	}
>
> @@ -963,16 +990,50 @@ 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) {
> +			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(
> +					&ctx->cal->phy[phy_idx]->subdev.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",
> diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
> index bb782193cf65..983323a109ac 100644
> --- a/drivers/media/platform/ti/cal/cal.c
> +++ b/drivers/media/platform/ti/cal/cal.c
> @@ -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;
> @@ -1014,7 +1015,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;
> @@ -1226,18 +1226,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. */
> diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h
> index 0856297adc0b..44ee0bece56e 100644
> --- a/drivers/media/platform/ti/cal/cal.h
> +++ b/drivers/media/platform/ti/cal/cal.h
> @@ -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)
> @@ -319,6 +319,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,
> --
> 2.34.1
>



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux