Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[pandora-kernel.git] / drivers / media / video / omap3isp / ispvideo.c
index 208a7ec..9cd8f1a 100644 (file)
 
 static struct isp_format_info formats[] = {
        { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
-         V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, },
+         V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_GREY, 8, },
+       { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y10, 10, },
+       { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y12, 12, },
+       { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR8, 8, },
+       { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG8, 8, },
+       { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG8, 8, },
+       { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB8, 8, },
        { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
-         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+         V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+         V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
        { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
-         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, },
+         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR10, 10, },
        { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
-         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, },
+         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG10, 10, },
        { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
-         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, },
+         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG10, 10, },
        { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
-         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, },
+         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB10, 10, },
        { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
-         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, },
+         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR12, 12, },
        { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
-         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, },
+         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG12, 12, },
        { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
-         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, },
+         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG12, 12, },
        { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
-         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, },
+         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB12, 12, },
        { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
-         V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, },
+         V4L2_MBUS_FMT_UYVY8_1X16, 0,
+         V4L2_PIX_FMT_UYVY, 16, },
        { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
-         V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, },
+         V4L2_MBUS_FMT_YUYV8_1X16, 0,
+         V4L2_PIX_FMT_YUYV, 16, },
 };
 
 const struct isp_format_info *
@@ -85,6 +115,37 @@ 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
@@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                return -EPIPE;
 
        while (1) {
+               unsigned int shifter_link;
                /* Retrieve the sink format */
                pad = &subdev->entity.pads[0];
                if (!(pad->flags & MEDIA_PAD_FL_SINK))
@@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                                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 */
                pad = media_entity_remote_source(pad);
                if (pad == NULL ||
@@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                        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 ||
+               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;