[media] v4l: s5p-tv: mixer: fix handling of interlaced modes
authorTomasz Stanislawski <t.stanislaws@samsung.com>
Fri, 9 Mar 2012 13:49:58 +0000 (10:49 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sun, 20 May 2012 12:02:28 +0000 (09:02 -0300)
The next frame was fetched by Mixer at every VSYNC event.  This caused tearing
when Mixer's output in interlaced mode.  This patch fixes this bug by fetching
new frame every second VSYNC when working in interlaced mode.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/s5p-tv/mixer.h
drivers/media/video/s5p-tv/mixer_reg.c

index 1597078c4a5070043270d1b54b9d980ba6cadc90..fa3e30f27447439c9e207315cf99577444a23157 100644 (file)
@@ -226,6 +226,7 @@ struct mxr_resources {
 /* event flags used  */
 enum mxr_devide_flags {
        MXR_EVENT_VSYNC = 0,
+       MXR_EVENT_TOP = 1,
 };
 
 /** drivers instance */
index 4800a3cbb297726a235e4d7cdc1e7fc055b1efce..3b1670a045f4ac4d67df4e24434db2b01232cde0 100644 (file)
@@ -296,21 +296,25 @@ irqreturn_t mxr_irq_handler(int irq, void *dev_data)
        /* wake up process waiting for VSYNC */
        if (val & MXR_INT_STATUS_VSYNC) {
                set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+               /* toggle TOP field event if working in interlaced mode */
+               if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE)
+                       change_bit(MXR_EVENT_TOP, &mdev->event_flags);
                wake_up(&mdev->event_queue);
-       }
-
-       /* clear interrupts */
-       if (~val & MXR_INT_EN_VSYNC) {
                /* vsync interrupt use different bit for read and clear */
-               val &= ~MXR_INT_EN_VSYNC;
+               val &= ~MXR_INT_STATUS_VSYNC;
                val |= MXR_INT_CLEAR_VSYNC;
        }
+
+       /* clear interrupts */
        mxr_write(mdev, MXR_INT_STATUS, val);
 
        spin_unlock(&mdev->reg_slock);
        /* leave on non-vsync event */
        if (~val & MXR_INT_CLEAR_VSYNC)
                return IRQ_HANDLED;
+       /* skip layer update on bottom field */
+       if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags))
+               return IRQ_HANDLED;
        for (i = 0; i < MXR_MAX_LAYERS; ++i)
                mxr_irq_layer_handle(mdev->layer[i]);
        return IRQ_HANDLED;
@@ -333,6 +337,7 @@ void mxr_reg_streamon(struct mxr_device *mdev)
 
        /* start MIXER */
        mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+       set_bit(MXR_EVENT_TOP, &mdev->event_flags);
 
        spin_unlock_irqrestore(&mdev->reg_slock, flags);
 }