Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36fa8092 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c3010097
Loading
Loading
Loading
Loading
+43 −1
Original line number Diff line number Diff line
@@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#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 @@ static const struct s5pcsis_event s5pcsis_events[] = {
};
#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 @@ static const struct s5pcsis_event s5pcsis_events[] = {
 * @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 csis_state {
	struct v4l2_mbus_framefmt format;

	struct spinlock slock;
	struct csis_pktbuf pkt_buf;
	struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
};

@@ -529,6 +541,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
	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_pad_ops s5pcsis_pad_ops = {
};

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 struct v4l2_subdev_ops s5pcsis_subdev_ops = {
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;