Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6d7a62d authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab
Browse files

[media] omap3isp: Move CCDC link validation to ccdc_link_validate()



Perform CCDC link validation in ccdc_link_validate() instead of
isp_video_validate_pipeline(). Also perform maximum data rate check in
isp_video_check_external_subdevs().

Signed-off-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 20d4ab7b
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -2154,6 +2154,69 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
	return 0;
}

/*
 * Decide whether desired output pixel code can be obtained with
 * the lane shifter by shifting the input pixel code.
 * @in: input pixelcode to shifter
 * @out: output pixelcode from shifter
 * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
 *
 * return true if the combination is possible
 * return false otherwise
 */
static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
			      enum v4l2_mbus_pixelcode out,
			      unsigned int additional_shift)
{
	const struct isp_format_info *in_info, *out_info;

	if (in == out)
		return true;

	in_info = omap3isp_video_format_info(in);
	out_info = omap3isp_video_format_info(out);

	if ((in_info->flavor == 0) || (out_info->flavor == 0))
		return false;

	if (in_info->flavor != out_info->flavor)
		return false;

	return in_info->bpp - out_info->bpp + additional_shift <= 6;
}

static int ccdc_link_validate(struct v4l2_subdev *sd,
			      struct media_link *link,
			      struct v4l2_subdev_format *source_fmt,
			      struct v4l2_subdev_format *sink_fmt)
{
	struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
	unsigned long parallel_shift;

	/* Check if the two ends match */
	if (source_fmt->format.width != sink_fmt->format.width ||
	    source_fmt->format.height != sink_fmt->format.height)
		return -EPIPE;

	/* We've got a parallel sensor here. */
	if (ccdc->input == CCDC_INPUT_PARALLEL) {
		struct isp_parallel_platform_data *pdata =
			&((struct isp_v4l2_subdevs_group *)
			  media_entity_to_v4l2_subdev(link->source->entity)
			  ->host_priv)->bus.parallel;
		parallel_shift = pdata->data_lane_shift * 2;
	} else {
		parallel_shift = 0;
	}

	/* Lane shifter may be used to drop bits on CCDC sink pad */
	if (!ccdc_is_shiftable(source_fmt->format.code,
			       sink_fmt->format.code, parallel_shift))
		return -EPIPE;

	return 0;
}

/*
 * ccdc_init_formats - Initialize formats on all pads
 * @sd: ISP CCDC V4L2 subdevice
@@ -2198,6 +2261,7 @@ static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
	.set_fmt = ccdc_set_format,
	.get_selection = ccdc_get_selection,
	.set_selection = ccdc_set_selection,
	.link_validate = ccdc_link_validate,
};

/* V4L2 subdev operations */
@@ -2307,6 +2371,7 @@ static int ccdc_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations ccdc_media_ops = {
	.link_setup = ccdc_link_setup,
	.link_validate = v4l2_subdev_link_validate,
};

void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
+11 −84
Original line number Diff line number Diff line
@@ -129,37 +129,6 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
	return NULL;
}

/*
 * Decide whether desired output pixel code can be obtained with
 * the lane shifter by shifting the input pixel code.
 * @in: input pixelcode to shifter
 * @out: output pixelcode from shifter
 * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
 *
 * return true if the combination is possible
 * return false otherwise
 */
static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in,
		enum v4l2_mbus_pixelcode out,
		unsigned int additional_shift)
{
	const struct isp_format_info *in_info, *out_info;

	if (in == out)
		return true;

	in_info = omap3isp_video_format_info(in);
	out_info = omap3isp_video_format_info(out);

	if ((in_info->flavor == 0) || (out_info->flavor == 0))
		return false;

	if (in_info->flavor != out_info->flavor)
		return false;

	return in_info->bpp - out_info->bpp + additional_shift <= 6;
}

/*
 * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
 * @video: ISP video instance
@@ -315,51 +284,24 @@ static int isp_video_get_graph_data(struct isp_video *video,
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
	struct isp_device *isp = pipe->output->isp;
	struct v4l2_subdev_format fmt_source;
	struct v4l2_subdev_format fmt_sink;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	int ret;

	subdev = isp_video_remote_subdev(pipe->output, NULL);
	if (subdev == NULL)
		return -EPIPE;

	while (1) {
		unsigned int shifter_link;

		/* Retrieve the sink format */
		pad = &subdev->entity.pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		fmt_sink.pad = pad->index;
		fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Update the maximum frame rate */
		if (subdev == &isp->isp_res.subdev)
			omap3isp_resizer_max_rate(&isp->isp_res,
						  &pipe->max_rate);

		/* Check ccdc maximum data rate when data comes from sensor
		 * TODO: Include ccdc rate in pipe->max_rate and compare the
		 *       total pipe rate with the input data rate from sensor.
		 */
		if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
			unsigned int rate = UINT_MAX;

			omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
			if (pipe->external_rate > rate)
				return -ENOSPC;
		}

		/* If sink pad is on CCDC, the link has the lane shifter
		 * in the middle of it. */
		shifter_link = subdev == &isp->isp_ccdc.subdev;

		/* Retrieve the source format. Return an error if no source
		 * entity can be found, and stop checking the pipeline if the
		 * source entity isn't a subdev.
@@ -372,32 +314,6 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
			break;

		subdev = media_entity_to_v4l2_subdev(pad->entity);

		fmt_source.pad = pad->index;
		fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Check if the two ends match */
		if (fmt_source.format.width != fmt_sink.format.width ||
		    fmt_source.format.height != fmt_sink.format.height)
			return -EPIPE;

		if (shifter_link) {
			unsigned int parallel_shift = 0;
			if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
				struct isp_parallel_platform_data *pdata =
					&((struct isp_v4l2_subdevs_group *)
					      subdev->host_priv)->bus.parallel;
				parallel_shift = pdata->data_lane_shift * 2;
			}
			if (!isp_video_is_shiftable(fmt_source.format.code,
						fmt_sink.format.code,
						parallel_shift))
				return -EPIPE;
		} else if (fmt_source.format.code != fmt_sink.format.code)
			return -EPIPE;
	}

	return 0;
@@ -1024,6 +940,17 @@ static int isp_video_check_external_subdevs(struct isp_video *video,

	pipe->external_rate = ctrl.value64;

	if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
		unsigned int rate = UINT_MAX;
		/*
		 * Check that maximum allowed CCDC pixel rate isn't
		 * exceeded by the pixel rate.
		 */
		omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
		if (pipe->external_rate > rate)
			return -ENOSPC;
	}

	return 0;
}