diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2012-09-21 14:18:41 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-05 20:28:04 -0400 |
commit | 36fa80927638babe523dce14f3408f9fdefa86d3 (patch) | |
tree | fee92facba413f8e31f4dfe2fee3cd2da2a4f97d /drivers/media/platform/s5p-fimc | |
parent | c3010097a79fc741d27b07e068598fd9468ca41f (diff) |
[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>
Diffstat (limited to 'drivers/media/platform/s5p-fimc')
-rw-r--r-- | drivers/media/platform/s5p-fimc/mipi-csis.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 8e4eed8414bd..acf4ce2c4bb9 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c | |||
@@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); | |||
98 | #define CSIS_MAX_PIX_WIDTH 0xffff | 98 | #define CSIS_MAX_PIX_WIDTH 0xffff |
99 | #define CSIS_MAX_PIX_HEIGHT 0xffff | 99 | #define CSIS_MAX_PIX_HEIGHT 0xffff |
100 | 100 | ||
101 | /* Non-image packet data buffers */ | ||
102 | #define S5PCSIS_PKTDATA_ODD 0x2000 | ||
103 | #define S5PCSIS_PKTDATA_EVEN 0x3000 | ||
104 | #define S5PCSIS_PKTDATA_SIZE SZ_4K | ||
105 | |||
101 | enum { | 106 | enum { |
102 | CSIS_CLK_MUX, | 107 | CSIS_CLK_MUX, |
103 | CSIS_CLK_GATE, | 108 | CSIS_CLK_GATE, |
@@ -144,6 +149,11 @@ static const struct s5pcsis_event s5pcsis_events[] = { | |||
144 | }; | 149 | }; |
145 | #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) | 150 | #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) |
146 | 151 | ||
152 | struct csis_pktbuf { | ||
153 | u32 *data; | ||
154 | unsigned int len; | ||
155 | }; | ||
156 | |||
147 | /** | 157 | /** |
148 | * struct csis_state - the driver's internal state data structure | 158 | * struct csis_state - the driver's internal state data structure |
149 | * @lock: mutex serializing the subdev and power management operations, | 159 | * @lock: mutex serializing the subdev and power management operations, |
@@ -159,6 +169,7 @@ static const struct s5pcsis_event s5pcsis_events[] = { | |||
159 | * @csis_fmt: current CSIS pixel format | 169 | * @csis_fmt: current CSIS pixel format |
160 | * @format: common media bus format for the source and sink pad | 170 | * @format: common media bus format for the source and sink pad |
161 | * @slock: spinlock protecting structure members below | 171 | * @slock: spinlock protecting structure members below |
172 | * @pkt_buf: the frame embedded (non-image) data buffer | ||
162 | * @events: MIPI-CSIS event (error) counters | 173 | * @events: MIPI-CSIS event (error) counters |
163 | */ | 174 | */ |
164 | struct csis_state { | 175 | struct csis_state { |
@@ -175,6 +186,7 @@ struct csis_state { | |||
175 | struct v4l2_mbus_framefmt format; | 186 | struct v4l2_mbus_framefmt format; |
176 | 187 | ||
177 | struct spinlock slock; | 188 | struct spinlock slock; |
189 | struct csis_pktbuf pkt_buf; | ||
178 | struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; | 190 | struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; |
179 | }; | 191 | }; |
180 | 192 | ||
@@ -529,6 +541,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
529 | return 0; | 541 | return 0; |
530 | } | 542 | } |
531 | 543 | ||
544 | static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, | ||
545 | unsigned int *size) | ||
546 | { | ||
547 | struct csis_state *state = sd_to_csis_state(sd); | ||
548 | unsigned long flags; | ||
549 | |||
550 | *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); | ||
551 | |||
552 | spin_lock_irqsave(&state->slock, flags); | ||
553 | state->pkt_buf.data = buf; | ||
554 | state->pkt_buf.len = *size; | ||
555 | spin_unlock_irqrestore(&state->slock, flags); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
532 | static int s5pcsis_log_status(struct v4l2_subdev *sd) | 560 | static int s5pcsis_log_status(struct v4l2_subdev *sd) |
533 | { | 561 | { |
534 | struct csis_state *state = sd_to_csis_state(sd); | 562 | struct csis_state *state = sd_to_csis_state(sd); |
@@ -566,6 +594,7 @@ static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { | |||
566 | }; | 594 | }; |
567 | 595 | ||
568 | static struct v4l2_subdev_video_ops s5pcsis_video_ops = { | 596 | static struct v4l2_subdev_video_ops s5pcsis_video_ops = { |
597 | .s_rx_buffer = s5pcsis_s_rx_buffer, | ||
569 | .s_stream = s5pcsis_s_stream, | 598 | .s_stream = s5pcsis_s_stream, |
570 | }; | 599 | }; |
571 | 600 | ||
@@ -578,13 +607,26 @@ static struct v4l2_subdev_ops s5pcsis_subdev_ops = { | |||
578 | static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) | 607 | static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) |
579 | { | 608 | { |
580 | struct csis_state *state = dev_id; | 609 | struct csis_state *state = dev_id; |
610 | struct csis_pktbuf *pktbuf = &state->pkt_buf; | ||
581 | unsigned long flags; | 611 | unsigned long flags; |
582 | u32 status; | 612 | u32 status; |
583 | 613 | ||
584 | status = s5pcsis_read(state, S5PCSIS_INTSRC); | 614 | status = s5pcsis_read(state, S5PCSIS_INTSRC); |
585 | |||
586 | spin_lock_irqsave(&state->slock, flags); | 615 | spin_lock_irqsave(&state->slock, flags); |
587 | 616 | ||
617 | if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { | ||
618 | u32 offset; | ||
619 | |||
620 | if (status & S5PCSIS_INTSRC_EVEN) | ||
621 | offset = S5PCSIS_PKTDATA_EVEN; | ||
622 | else | ||
623 | offset = S5PCSIS_PKTDATA_ODD; | ||
624 | |||
625 | memcpy(pktbuf->data, state->regs + offset, pktbuf->len); | ||
626 | pktbuf->data = NULL; | ||
627 | rmb(); | ||
628 | } | ||
629 | |||
588 | /* Update the event/error counters */ | 630 | /* Update the event/error counters */ |
589 | if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { | 631 | if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { |
590 | int i; | 632 | int i; |