/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Compute the minimum time per frame value as the maximum of time per frame
 * limits reported by every block in the pipeline.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends or if the pipeline doesn't start with a
 * video source (either a subdev with no input pad, or a non-subdev entity).
 */
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;

    pipe->max_rate = pipe->l3_ick;

    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 (isp->isp_ccdc.vpcfg.pixelclk > 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.
         */
        pad = media_entity_remote_source(pad);
        if (pad == NULL)
            return -EPIPE;

        if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
            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;
}
Beispiel #2
0
/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Compute the minimum time per frame value as the maximum of time per frame
 * limits reported by every block in the pipeline.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends.
 */
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;

	pipe->max_rate = pipe->l3_ick;

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

	while (1) {
		/* 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 (isp->isp_ccdc.vpcfg.pixelclk > rate)
				return -ENOSPC;
		}

		/* Retrieve the source format */
		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			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.code != fmt_sink.format.code ||
		    fmt_source.format.width != fmt_sink.format.width ||
		    fmt_source.format.height != fmt_sink.format.height)
			return -EPIPE;
	}

	return 0;
}