.../platform/synopsys/hdmirx/snps_hdmirx.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+)
hdmirx_start_streaming() enables FIFO_OVERFLOW_INT_EN,
FIFO_UNDERFLOW_INT_EN, HDMIRX_AXI_ERROR_INT_EN and
LAST_FRAME_AXI_UNFINISH_INT_EN in DMA_CONFIG4, but
hdmirx_dma_irq_handler() only decodes HDMIRX_DMA_IDLE_INT and
LINE_FLAG_INT_EN. Any of the four error interrupts therefore falls
through the handler with handled still false and is discarded: no
counter, no message at default verbosity, and nothing reported to
userspace. The only trace is a v4l2_dbg level 3 line saying the irq was
not handled, printing the raw status word.
The practical effect is that a capture FIFO overflow -- the DMA failing
to drain incoming pixels to memory, which loses whole runs of lines from
the frame -- is completely silent. Frame cadence, DMA idle interrupts and
buffer delivery all continue to look healthy while the delivered buffers
contain unwritten lines. On affected boards this reads as unexplained
video corruption with every normal indicator nominal.
Measured on RK3588 with a 900 frame capture: a board writing a
semi-planar format reported 907 DMA idle and 907 line flag interrupts as
expected, plus 702 FIFO overflow interrupts, all of them dropped. An
otherwise identical capture on a board writing a packed format at the
same data rate reported none.
Decode the four error bits, count them per stream, warn once per stream
on the first occurrence of each, and log the totals when streaming stops.
No functional change to the capture path.
Signed-off-by: Thomas Weustenfeld <tw@tvlabs.ai>
---
.../platform/synopsys/hdmirx/snps_hdmirx.c | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
index 25f8ca0d6d94..d7ff7aa4ebde 100644
--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
@@ -117,6 +117,10 @@ struct hdmirx_stream {
u32 sequence;
u32 line_flag_int_cnt;
u32 irq_stat;
+ u32 fifo_overflow_cnt;
+ u32 fifo_underflow_cnt;
+ u32 axi_error_cnt;
+ u32 last_frame_unfinish_cnt;
};
struct snps_hdmirx_dev {
@@ -1567,6 +1571,15 @@ static void hdmirx_stop_streaming(struct vb2_queue *queue)
hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0);
return_all_buffers(stream, VB2_BUF_STATE_ERROR);
mutex_unlock(&hdmirx_dev->stream_lock);
+
+ if (stream->fifo_overflow_cnt || stream->fifo_underflow_cnt ||
+ stream->axi_error_cnt || stream->last_frame_unfinish_cnt)
+ v4l2_warn(v4l2_dev,
+ "dma errors over %u frames: fifo_overflow:%u fifo_underflow:%u axi_error:%u last_frame_unfinish:%u\n",
+ stream->sequence, stream->fifo_overflow_cnt,
+ stream->fifo_underflow_cnt, stream->axi_error_cnt,
+ stream->last_frame_unfinish_cnt);
+
v4l2_dbg(1, debug, v4l2_dev, "stream stopping finished\n");
}
@@ -1583,6 +1596,10 @@ static int hdmirx_start_streaming(struct vb2_queue *queue, unsigned int count)
mutex_lock(&hdmirx_dev->stream_lock);
stream->sequence = 0;
stream->line_flag_int_cnt = 0;
+ stream->fifo_overflow_cnt = 0;
+ stream->fifo_underflow_cnt = 0;
+ stream->axi_error_cnt = 0;
+ stream->last_frame_unfinish_cnt = 0;
stream->curr_buf = NULL;
stream->next_buf = NULL;
stream->irq_stat = 0;
@@ -2080,6 +2097,31 @@ static void line_flag_int_handler(struct snps_hdmirx_dev *hdmirx_dev,
*handled = true;
}
+static void dma_error_int_handler(struct snps_hdmirx_dev *hdmirx_dev,
+ u32 dma_stat1, bool *handled)
+{
+ struct hdmirx_stream *stream = &hdmirx_dev->stream;
+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev;
+
+ if ((dma_stat1 & FIFO_OVERFLOW_INT_EN) && !stream->fifo_overflow_cnt++)
+ v4l2_warn(v4l2_dev,
+ "dma fifo overflow, captured lines are being dropped\n");
+
+ if ((dma_stat1 & FIFO_UNDERFLOW_INT_EN) &&
+ !stream->fifo_underflow_cnt++)
+ v4l2_warn(v4l2_dev, "dma fifo underflow\n");
+
+ if ((dma_stat1 & HDMIRX_AXI_ERROR_INT_EN) && !stream->axi_error_cnt++)
+ v4l2_err(v4l2_dev, "dma axi error\n");
+
+ if ((dma_stat1 & LAST_FRAME_AXI_UNFINISH_INT_EN) &&
+ !stream->last_frame_unfinish_cnt++)
+ v4l2_warn(v4l2_dev,
+ "dma did not finish writing the last frame\n");
+
+ *handled = true;
+}
+
static irqreturn_t hdmirx_dma_irq_handler(int irq, void *dev_id)
{
struct snps_hdmirx_dev *hdmirx_dev = dev_id;
@@ -2115,6 +2157,11 @@ static irqreturn_t hdmirx_dma_irq_handler(int irq, void *dev_id)
if (dma_stat1 & LINE_FLAG_INT_EN)
line_flag_int_handler(hdmirx_dev, &handled);
+ if (dma_stat1 & (FIFO_OVERFLOW_INT_EN | FIFO_UNDERFLOW_INT_EN |
+ HDMIRX_AXI_ERROR_INT_EN |
+ LAST_FRAME_AXI_UNFINISH_INT_EN))
+ dma_error_int_handler(hdmirx_dev, dma_stat1, &handled);
+
if (!handled)
v4l2_dbg(3, debug, v4l2_dev,
"%s: dma irq not handled, dma_stat1:%#x\n",
--
2.55.0
© 2016 - 2026 Red Hat, Inc.