From ed7309a8b79b4141ebeddc22ae01109c1e8237f2 Mon Sep 17 00:00:00 2001 From: "Guoniu.Zhou" Date: Wed, 10 Jul 2019 09:39:34 +0800 Subject: [PATCH] MLK-22066: media: ISI: fix tearing issue for IMX8MN platform 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 --- drivers/media/platform/imx8/mxc-isi-cap.c | 14 ++++++++++++-- drivers/media/platform/imx8/mxc-isi-core.c | 1 + drivers/media/platform/imx8/mxc-isi-core.h | 7 +++++++ drivers/media/platform/imx8/mxc-isi-hw.c | 7 ++++--- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/imx8/mxc-isi-cap.c b/drivers/media/platform/imx8/mxc-isi-cap.c index f81b2d72a99a..5ef49686ae56 100644 --- a/drivers/media/platform/imx8/mxc-isi-cap.c +++ b/drivers/media/platform/imx8/mxc-isi-cap.c @@ -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; } diff --git a/drivers/media/platform/imx8/mxc-isi-core.c b/drivers/media/platform/imx8/mxc-isi-core.c index de5d17618ab3..28de3f944984 100644 --- a/drivers/media/platform/imx8/mxc-isi-core.c +++ b/drivers/media/platform/imx8/mxc-isi-core.c @@ -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) diff --git a/drivers/media/platform/imx8/mxc-isi-core.h b/drivers/media/platform/imx8/mxc-isi-core.h index 56f9e1a2f367..f73306092980 100644 --- a/drivers/media/platform/imx8/mxc-isi-core.h +++ b/drivers/media/platform/imx8/mxc-isi-core.h @@ -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; diff --git a/drivers/media/platform/imx8/mxc-isi-hw.c b/drivers/media/platform/imx8/mxc-isi-hw.c index 1bf24638580a..b4fcb8e4041a 100644 --- a/drivers/media/platform/imx8/mxc-isi-hw.c +++ b/drivers/media/platform/imx8/mxc-isi-hw.c @@ -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); } -- 2.17.1