[media] s5p-csis: Add support for non-image data packets capture
MIPI-CSI has internal memory mapped buffers for the frame embedded
(non-image) data. There are two buffers, for even and odd frames which
need to be saved after an interrupt is raised. The packet data buffers
size is 4 KiB and there is no status register in the hardware where the
actual non-image data size can be read from. Hence the driver copies
whole packet data buffer into a buffer provided by the FIMC driver.
This will form a separate plane in the user buffer.
When FIMC DMA engine is stopped by the driver due the to user space
not keeping up with buffer de-queuing the MIPI-CSIS will still run,
however it must discard data which is not captured by FIMC. Which
frames are actually capture by MIPI-CSIS is determined by means of
the s_tx_buffer subdev callback. When it is not called after a single
embedded data frame has been captured and copied and before next
embedded data frame interrupt occurrs, subsequent embedded data frames
will be dropped.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index 8e4eed8..acf4ce2 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -98,6 +98,11 @@
#define CSIS_MAX_PIX_WIDTH 0xffff
#define CSIS_MAX_PIX_HEIGHT 0xffff
+/* Non-image packet data buffers */
+#define S5PCSIS_PKTDATA_ODD 0x2000
+#define S5PCSIS_PKTDATA_EVEN 0x3000
+#define S5PCSIS_PKTDATA_SIZE SZ_4K
+
enum {
CSIS_CLK_MUX,
CSIS_CLK_GATE,
@@ -144,6 +149,11 @@
};
#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
+struct csis_pktbuf {
+ u32 *data;
+ unsigned int len;
+};
+
/**
* struct csis_state - the driver's internal state data structure
* @lock: mutex serializing the subdev and power management operations,
@@ -159,6 +169,7 @@
* @csis_fmt: current CSIS pixel format
* @format: common media bus format for the source and sink pad
* @slock: spinlock protecting structure members below
+ * @pkt_buf: the frame embedded (non-image) data buffer
* @events: MIPI-CSIS event (error) counters
*/
struct csis_state {
@@ -175,6 +186,7 @@
struct v4l2_mbus_framefmt format;
struct spinlock slock;
+ struct csis_pktbuf pkt_buf;
struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
};
@@ -529,6 +541,22 @@
return 0;
}
+static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf,
+ unsigned int *size)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ unsigned long flags;
+
+ *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE);
+
+ spin_lock_irqsave(&state->slock, flags);
+ state->pkt_buf.data = buf;
+ state->pkt_buf.len = *size;
+ spin_unlock_irqrestore(&state->slock, flags);
+
+ return 0;
+}
+
static int s5pcsis_log_status(struct v4l2_subdev *sd)
{
struct csis_state *state = sd_to_csis_state(sd);
@@ -566,6 +594,7 @@
};
static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+ .s_rx_buffer = s5pcsis_s_rx_buffer,
.s_stream = s5pcsis_s_stream,
};
@@ -578,13 +607,26 @@
static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
{
struct csis_state *state = dev_id;
+ struct csis_pktbuf *pktbuf = &state->pkt_buf;
unsigned long flags;
u32 status;
status = s5pcsis_read(state, S5PCSIS_INTSRC);
-
spin_lock_irqsave(&state->slock, flags);
+ if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) {
+ u32 offset;
+
+ if (status & S5PCSIS_INTSRC_EVEN)
+ offset = S5PCSIS_PKTDATA_EVEN;
+ else
+ offset = S5PCSIS_PKTDATA_ODD;
+
+ memcpy(pktbuf->data, state->regs + offset, pktbuf->len);
+ pktbuf->data = NULL;
+ rmb();
+ }
+
/* Update the event/error counters */
if ((status & S5PCSIS_INTSRC_ERRORS) || debug) {
int i;