MLK-22066: media: ISI: fix tearing issue for IMX8MN platform
authorGuoniu.Zhou <guoniu.zhou@nxp.com>
Wed, 10 Jul 2019 01:39:34 +0000 (09:39 +0800)
committerGuoniu.Zhou <guoniu.zhou@nxp.com>
Wed, 7 Aug 2019 06:29:03 +0000 (14:29 +0800)
ISI use ping-pong buffer to write image data to memory. Theoretically,
BUF1 will first work and then BUF2, but sometimes ISI of IMX8MN do not
follow this rule. But in our driver, we use list to manage buffers. It
means that we must follow 1-2-1... sequence. So just skip the frame for
this specail case.

Because we can not guarantee the interrupt sequence of BUF1 and BUF2,
and not sure which buffer is free, so change the buffer switching by
buffer status, not frame sequence.

Signed-off-by: Guoniu.Zhou <guoniu.zhou@nxp.com>
drivers/media/platform/imx8/mxc-isi-cap.c
drivers/media/platform/imx8/mxc-isi-core.c
drivers/media/platform/imx8/mxc-isi-core.h
drivers/media/platform/imx8/mxc-isi-hw.c

index f81b2d7..5ef4968 100644 (file)
@@ -254,6 +254,7 @@ static int mxc_isi_update_buf_paddr(struct mxc_isi_buffer *buf, int memplanes)
 
 void mxc_isi_cap_frame_write_done(struct mxc_isi_dev *mxc_isi)
 {
+       struct device *dev = &mxc_isi->pdev->dev;
        struct mxc_isi_buffer *buf;
        struct vb2_buffer *vb2;
 
@@ -266,6 +267,16 @@ void mxc_isi_cap_frame_write_done(struct mxc_isi_dev *mxc_isi)
        buf = list_first_entry(&mxc_isi->isi_cap.out_active,
                                struct mxc_isi_buffer, list);
 
+       /*
+        * Skip frame when buffer number is not match ISI trigger
+        * buffer
+        */
+       if (((mxc_isi->status & 0x100) && (buf->id == MXC_ISI_BUF2)) ||
+           ((mxc_isi->status & 0x200) && (buf->id == MXC_ISI_BUF1))) {
+               dev_dbg(dev, "status=0x%x id=%d\n", mxc_isi->status, buf->id);
+               return;
+       }
+
        if (buf->discard) {
                list_move_tail(mxc_isi->isi_cap.out_active.next,
                                        &mxc_isi->isi_cap.out_discard);
@@ -280,8 +291,7 @@ void mxc_isi_cap_frame_write_done(struct mxc_isi_dev *mxc_isi)
 
        if (list_empty(&mxc_isi->isi_cap.out_pending)) {
                if (list_empty(&mxc_isi->isi_cap.out_discard)) {
-                       dev_warn(&mxc_isi->pdev->dev,
-                                       "%s: trying to access empty discard list\n", __func__);
+                       dev_warn(dev, "%s: trying to access empty discard list\n", __func__);
                        return;
                }
 
index de5d176..28de3f9 100644 (file)
@@ -23,6 +23,7 @@ static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
 
        status = mxc_isi_get_irq_status(mxc_isi);
        mxc_isi_clean_irq_status(mxc_isi, status);
+       mxc_isi->status = status;
 
        if (status & CHNL_STS_FRM_STRD_MASK) {
                if (mxc_isi->is_m2m)
index 56f9e1a..f733060 100644 (file)
@@ -156,6 +156,11 @@ enum mxc_isi_m2m_in_fmt {
        MXC_ISI_M2M_IN_FMT_YUV422_1P10P,
 };
 
+enum mxc_isi_buf_id {
+       MXC_ISI_BUF1    = 0x0,
+       MXC_ISI_BUF2,
+};
+
 struct mxc_isi_fmt {
        char    *name;
        u32 mbus_code;
@@ -228,6 +233,7 @@ struct mxc_isi_buffer {
        struct vb2_v4l2_buffer v4l2_buf;
        struct list_head        list;
        struct frame_addr       paddr;
+       enum mxc_isi_buf_id     id;
        bool discard;
 };
 
@@ -311,6 +317,7 @@ struct mxc_isi_dev {
        u32 skip_m2m;
        u32 req_cap_buf_num;
        u32 req_out_buf_num;
+       u32 status;
        u8 chain_buf;
 
        atomic_t open_count;
index 1bf2463..b4fcb8e 100644 (file)
@@ -163,17 +163,18 @@ void mxc_isi_channel_set_outbuf(struct mxc_isi_dev *mxc_isi, struct mxc_isi_buff
        }
 
        val = readl(mxc_isi->regs + CHNL_OUT_BUF_CTRL);
-
-       if (framecount % 2 == 0) {
+       if (framecount == 0 || ((mxc_isi->status & 0x100) && (framecount != 1))) {
                writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_Y);
                writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_U);
                writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_V);
                val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR_MASK;
-       } else if (framecount % 2 == 1) {
+               buf->id = MXC_ISI_BUF1;
+       } else if (framecount == 1 || mxc_isi->status & 0x200) {
                writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_Y);
                writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_U);
                writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_V);
                val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR_MASK;
+               buf->id = MXC_ISI_BUF2;
        }
        writel(val, mxc_isi->regs + CHNL_OUT_BUF_CTRL);
 }