[media] omap3isp: ccdc: Add basic support for interlaced video
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Mon, 19 May 2014 19:37:38 +0000 (16:37 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 21 Aug 2014 20:25:14 +0000 (15:25 -0500)
When the CCDC input is interlaced enable the alternate field order on
the CCDC output video node. The field signal polarity is specified
through platform data.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Enrico Butera <ebutera@users.sourceforge.net>
Acked-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/omap3isp/ispvideo.h
include/media/omap3isp.h

index 76d4fd73f5e8e4d8587b8ded0dc6e4ef13ceabbb..49d7256a7de34c6619823bf93e5c84b3745a7e9d 100644 (file)
@@ -1001,6 +1001,9 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
        if (pdata && pdata->vs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
 
        if (pdata && pdata->vs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
 
+       if (pdata && pdata->fld_pol)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
+
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
@@ -1140,6 +1143,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
 
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
 
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
+       /* Configure the sync interface. */
        ccdc_config_sync_if(ccdc, pdata, depth_out);
 
        syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
        ccdc_config_sync_if(ccdc, pdata, depth_out);
 
        syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1499,6 +1503,17 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                return 1;
        }
 
                return 1;
        }
 
+       /* When capturing fields in alternate order read the current field
+        * identifier and store it in the pipeline.
+        */
+       if (ccdc->formats[CCDC_PAD_SOURCE_OF].field == V4L2_FIELD_ALTERNATE) {
+               u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
+                                            ISPCCDC_SYN_MODE);
+
+               pipe->field = syn_mode & ISPCCDC_SYN_MODE_FLDSTAT
+                           ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
+       }
+
        if (ccdc_sbl_wait_idle(ccdc, 1000)) {
                dev_info(isp->dev, "CCDC won't become idle!\n");
                isp->crashed |= 1U << ccdc->subdev.entity.id;
        if (ccdc_sbl_wait_idle(ccdc, 1000)) {
                dev_info(isp->dev, "CCDC won't become idle!\n");
                isp->crashed |= 1U << ccdc->subdev.entity.id;
@@ -1830,6 +1845,11 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                /* Clamp the input size. */
                fmt->width = clamp_t(u32, width, 32, 4096);
                fmt->height = clamp_t(u32, height, 32, 4096);
                /* Clamp the input size. */
                fmt->width = clamp_t(u32, width, 32, 4096);
                fmt->height = clamp_t(u32, height, 32, 4096);
+
+               /* Default to progressive field order. */
+               if (fmt->field == V4L2_FIELD_ANY)
+                       fmt->field = V4L2_FIELD_NONE;
+
                break;
 
        case CCDC_PAD_SOURCE_OF:
                break;
 
        case CCDC_PAD_SOURCE_OF:
@@ -1885,7 +1905,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
         * stored on 2 bytes.
         */
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
         * stored on 2 bytes.
         */
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
-       fmt->field = V4L2_FIELD_NONE;
 }
 
 /*
 }
 
 /*
index 756c1628ef86dd0b46014278b033cf949f3d6b56..c38f1d4cc5381c536108dc5c1a2077167aa526bc 100644 (file)
@@ -482,6 +482,11 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
        else
                buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
 
        else
                buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
 
+       if (pipe->field != V4L2_FIELD_NONE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       buf->vb.v4l2_buf.field = pipe->field;
+
        /* Report pipeline errors to userspace on the capture device side. */
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
                state = VB2_BUF_STATE_ERROR;
        /* Report pipeline errors to userspace on the capture device side. */
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
                state = VB2_BUF_STATE_ERROR;
@@ -1038,6 +1043,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        video->queue = &vfh->queue;
        INIT_LIST_HEAD(&video->dmaqueue);
        atomic_set(&pipe->frame_number, -1);
        video->queue = &vfh->queue;
        INIT_LIST_HEAD(&video->dmaqueue);
        atomic_set(&pipe->frame_number, -1);
+       pipe->field = vfh->format.fmt.pix.field;
 
        mutex_lock(&video->queue_lock);
        ret = vb2_streamon(&vfh->queue, type);
 
        mutex_lock(&video->queue_lock);
        ret = vb2_streamon(&vfh->queue, type);
index a76124cd6431afec551148f37ba0b361ccf6f52b..0b7efedc3da990945bddc7e32389b55693df1ab3 100644 (file)
@@ -78,6 +78,7 @@ enum isp_pipeline_state {
 
 /*
  * struct isp_pipeline - An ISP hardware pipeline
 
 /*
  * struct isp_pipeline - An ISP hardware pipeline
+ * @field: The field being processed by the pipeline
  * @error: A hardware error occurred during capture
  * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
  * @error: A hardware error occurred during capture
  * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
@@ -91,6 +92,7 @@ struct isp_pipeline {
        u32 entities;
        unsigned long l3_ick;
        unsigned int max_rate;
        u32 entities;
        unsigned long l3_ick;
        unsigned int max_rate;
+       enum v4l2_field field;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
        bool error;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
        bool error;
index c9d06d9f7e6eaa823eb4eb8b286ada0008abc176..398279dd1922b4b41959aa7966b0991d19fbb24b 100644 (file)
@@ -57,6 +57,8 @@ enum {
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *             0 - Active high, 1 - Active low
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *             0 - Active high, 1 - Active low
+ * @fld_pol: Field signal polarity
+ *             0 - Positive, 1 - Negative
  * @data_pol: Data polarity
  *             0 - Normal, 1 - One's complement
  */
  * @data_pol: Data polarity
  *             0 - Normal, 1 - One's complement
  */
@@ -65,6 +67,7 @@ struct isp_parallel_platform_data {
        unsigned int clk_pol:1;
        unsigned int hs_pol:1;
        unsigned int vs_pol:1;
        unsigned int clk_pol:1;
        unsigned int hs_pol:1;
        unsigned int vs_pol:1;
+       unsigned int fld_pol:1;
        unsigned int data_pol:1;
 };
 
        unsigned int data_pol:1;
 };