Commit b86f6ea0 authored by Paul Kocialkowski's avatar Paul Kocialkowski Committed by Mauro Carvalho Chehab

media: sun6i-csi: Add capture state using vsync for page flip

The current implementation requires up to 3 buffers to properly
implement page flipping without losing frames: one is configured
before the video stream is started, one just after that and page
flipping is synchronized to the frame done interrupt. The comment in
the code mentions that "CSI will lookup the next dma buffer for next
frame before the current frame done IRQ triggered".

Based on observations of the CSI unit behavior, it seems that the
buffer DMA address is sampled when the frame scan begins (in addition
to starting the stream), which corresponds to the vblank interrupt
that hits just before the frame-done interrupt of the previous frame.

As a result, the address configured at the frame done interrupt is not
actually used for the next frame but for the one after that.

This proposal changes the page flipping sync point to the vsync
interrupt, which allows the DMA address to be sampled for the next
frame instead and allows operating with only two buffers.

In addition to the change in the sync point, the code is refactored
to introduce a notion of state that clarifies tracking of the buffers
with tidy functions.
Signed-off-by: default avatarPaul Kocialkowski <paul.kocialkowski@bootlin.com>
Acked-by: default avatarJernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent e9201cb2
......@@ -566,6 +566,7 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable)
regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
regmap_write(regmap, CSI_CH_INT_EN_REG,
CSI_CH_INT_EN_VS_INT_EN |
CSI_CH_INT_EN_HB_OF_INT_EN |
CSI_CH_INT_EN_FIFO2_OF_INT_EN |
CSI_CH_INT_EN_FIFO1_OF_INT_EN |
......@@ -664,6 +665,9 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private)
if (status & CSI_CH_INT_STA_FD_PD)
sun6i_csi_capture_frame_done(csi_dev);
if (status & CSI_CH_INT_STA_VS_PD)
sun6i_csi_capture_sync(csi_dev);
regmap_write(regmap, CSI_CH_INT_STA_REG, status);
return IRQ_HANDLED;
......
......@@ -25,9 +25,6 @@ enum sun6i_csi_port {
struct sun6i_csi_buffer {
struct vb2_v4l2_buffer v4l2_buffer;
struct list_head list;
dma_addr_t dma_addr;
bool queued_to_csi;
};
/**
......
......@@ -13,23 +13,34 @@
struct sun6i_csi_device;
#undef current
struct sun6i_csi_capture_state {
struct list_head queue;
spinlock_t lock; /* Queue and buffers lock. */
struct sun6i_csi_buffer *pending;
struct sun6i_csi_buffer *current;
struct sun6i_csi_buffer *complete;
unsigned int sequence;
};
struct sun6i_csi_capture {
struct sun6i_csi_capture_state state;
struct video_device video_dev;
struct vb2_queue queue;
struct mutex lock; /* Queue lock. */
struct media_pad pad;
struct list_head dma_queue;
spinlock_t dma_queue_lock; /* DMA queue lock. */
struct v4l2_format format;
u32 mbus_code;
unsigned int sequence;
};
void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev);
void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev);
int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev);
void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev);
void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev);
#endif /* __SUN6I_CAPTURE_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment