[PATCH v2 25/31] omap3isp: Implement proper CCDC link validation, check pixel rate

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

 



Implement correct link validation for the CCDC. Use external_rate from
isp_pipeline to configurat vp divisor and check that external_rate does not
exceed our data rate limitations.

Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxx>
---
 drivers/media/video/omap3isp/ispccdc.c |   69 +++++++++++++++++++++++++++++--
 1 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index 6aff241..1555891 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -836,8 +836,8 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
 
 	if (pipe->input)
 		div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
-	else if (ccdc->vpcfg.pixelclk)
-		div = l3_ick / ccdc->vpcfg.pixelclk;
+	else if (pipe->external_rate)
+		div = l3_ick / pipe->external_rate;
 
 	div = clamp(div, 2U, max_div);
 	fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
@@ -1749,7 +1749,18 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
 	}
 
 	switch (enable) {
-	case ISP_PIPELINE_STREAM_CONTINUOUS:
+	case ISP_PIPELINE_STREAM_CONTINUOUS: {
+		struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
+		unsigned int rate = UINT_MAX;
+
+		/*
+		 * Check that maximum allowed rate isn't exceeded by
+		 * the pixel rate.
+		 */
+		omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+		if (pipe->external_rate > rate)
+			return -ENOSPC;
+
 		if (ccdc->output & CCDC_OUTPUT_MEMORY)
 			omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
 
@@ -1758,6 +1769,7 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
 
 		ccdc->underrun = 0;
 		break;
+	}
 
 	case ISP_PIPELINE_STREAM_SINGLESHOT:
 		if (ccdc->output & CCDC_OUTPUT_MEMORY &&
@@ -1999,6 +2011,37 @@ 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,
@@ -2008,13 +2051,31 @@ static int ccdc_link_validate(struct v4l2_subdev *sd,
 	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
 	int rval;
 
+	/* 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;
+		unsigned long parallel_shift = pdata->data_lane_shift * 2;
+		/* 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;
+
 		pipe->external =
 			media_entity_to_v4l2_subdev(link->source->entity);
 		rval = omap3isp_get_external_info(pipe, link);
 		if (rval < 0)
 			return 0;
+	} else {
+		if (source_fmt->format.code != sink_fmt->format.code)
+			return -EPIPE;
 	}
 
 	return 0;
@@ -2299,8 +2360,6 @@ int omap3isp_ccdc_init(struct isp_device *isp)
 	ccdc->clamp.oblen = 0;
 	ccdc->clamp.dcsubval = 0;
 
-	ccdc->vpcfg.pixelclk = 0;
-
 	ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
 	ccdc_apply_controls(ccdc);
 
-- 
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[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