aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/fimc/fimc_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/fimc/fimc_output.c')
-rw-r--r--drivers/media/video/samsung/fimc/fimc_output.c92
1 files changed, 90 insertions, 2 deletions
diff --git a/drivers/media/video/samsung/fimc/fimc_output.c b/drivers/media/video/samsung/fimc/fimc_output.c
index 895cb7f..57611e5 100644
--- a/drivers/media/video/samsung/fimc/fimc_output.c
+++ b/drivers/media/video/samsung/fimc/fimc_output.c
@@ -25,6 +25,9 @@
#include <plat/media.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#ifdef CONFIG_SLP_DMABUF
+#include <linux/dma-buf.h>
+#endif
#include "fimc.h"
#include "fimc-ipc.h"
@@ -287,6 +290,33 @@ static void fimc_init_out_buf(struct fimc_ctx *ctx)
}
}
+#ifdef CONFIG_SLP_DMABUF
+static int fimc_set_out_num_plane(struct fimc_control *ctrl,
+ struct fimc_ctx *ctx)
+{
+ u32 format = ctx->pix.pixelformat;
+
+ switch (format) {
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_RGB565: /* fall through */
+ case V4L2_PIX_FMT_UYVY: /* fall through */
+ case V4L2_PIX_FMT_YUYV:
+ return PLANE_1;
+ case V4L2_PIX_FMT_NV12: /* fall through */
+ case V4L2_PIX_FMT_NV21: /* fall through */
+ case V4L2_PIX_FMT_NV12T:
+ return PLANE_2;
+ case V4L2_PIX_FMT_YUV420: /* fall through */
+ return PLANE_3;
+ default:
+ fimc_err("%s: Invalid pixelformt : %d\n", __func__, format);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
static int fimc_outdev_set_src_buf(struct fimc_control *ctrl,
struct fimc_ctx *ctx)
{
@@ -1690,6 +1720,10 @@ int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b)
default:
break;
}
+#ifdef CONFIG_SLP_DMABUF
+ if (b->memory == V4L2_MEMORY_DMABUF)
+ _fimc_queue_free(ctrl, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+#endif
} else {
/* initialize source buffers */
if (b->memory == V4L2_MEMORY_MMAP) {
@@ -1701,6 +1735,14 @@ int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b)
if (mode == FIMC_OVLY_DMA_AUTO ||
mode == FIMC_OVLY_NOT_FIXED)
ctx->overlay.req_idx = FIMC_USERPTR_IDX;
+#ifdef CONFIG_SLP_DMABUF
+ } else if (b->memory == V4L2_MEMORY_DMABUF) {
+ int num_planes;
+
+ num_planes = fimc_set_out_num_plane(ctrl, ctx);
+ fimc_queue_alloc(ctrl, b->type, b->memory, b->count,
+ num_planes);
+#endif
}
ctx->is_requested = 1;
@@ -2365,6 +2407,7 @@ static int fimc_outdev_start_operation(struct fimc_control *ctrl,
ret = fimc_outdev_start_camif(ctrl);
if (ret < 0) {
fimc_err("Fail: fimc_start_camif\n");
+ spin_unlock_irqrestore(&ctrl->out->slock, spin_flags);
return -EINVAL;
}
@@ -2399,6 +2442,7 @@ static int fimc_qbuf_output_single_buf(struct fimc_control *ctrl,
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
buf_set.base[FIMC_ADDR_Y] = (dma_addr_t)ctx->fbuf.base;
break;
case V4L2_PIX_FMT_YUV420:
@@ -2465,9 +2509,11 @@ static int fimc_qbuf_output_multi_buf(struct fimc_control *ctrl,
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y];
break;
case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420: /* fall through */
buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y];
buf_set.base[FIMC_ADDR_CB] = ctx->dst[idx].base[FIMC_ADDR_CB];
buf_set.base[FIMC_ADDR_CR] = ctx->dst[idx].base[FIMC_ADDR_CR];
@@ -2680,7 +2726,7 @@ static int fimc_update_in_queue_addr(struct fimc_control *ctrl,
int fimc_qbuf_output(void *fh, struct v4l2_buffer *b)
{
- struct fimc_buf *buf = (struct fimc_buf *)b->m.userptr;
+ struct fimc_buf *buf;
struct fimc_ctx *ctx;
struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
@@ -2716,9 +2762,40 @@ int fimc_qbuf_output(void *fh, struct v4l2_buffer *b)
(ctrl->status == FIMC_STREAMON) ||
(ctrl->status == FIMC_STREAMON_IDLE)) {
if (b->memory == V4L2_MEMORY_USERPTR) {
+ buf = (struct fimc_buf *)b->m.userptr;
ret = fimc_update_in_queue_addr(ctrl, ctx, b->index, buf->base);
if (ret < 0)
return ret;
+#ifdef CONFIG_SLP_DMABUF
+ } else if (b->memory == V4L2_MEMORY_DMABUF) {
+ struct vb2_buffer *vb;
+ dma_addr_t addr[3];
+ struct sg_table *sg;
+ struct dma_buf_attachment *dba;
+ int i;
+
+ vb = ctrl->out_bufs[b->index];
+ ret = _qbuf_dmabuf(ctrl, vb, b);
+ if (ret < 0) {
+ fimc_err("_qbuf_dmabuf failed ret = %d\n", ret);
+ return ret;
+ }
+ for (i = 0; i < vb->num_planes; i++) {
+ dba = vb->planes[i].mem_priv;
+ sg = dba->priv;
+ if (sg)
+ addr[i] = sg_dma_address(sg->sgl);
+ else {
+ fimc_err("%s: Wrong sg value.\n",
+ __func__);
+ return -ENODEV;
+ }
+ }
+ ret = fimc_update_in_queue_addr(ctrl, ctx, b->index,
+ addr);
+ if (ret < 0)
+ return ret;
+#endif
}
#if defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME)
@@ -2831,6 +2908,7 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b)
int idx = -1, ret = -1;
ctx = &ctrl->out->ctx[ctx_id];
+
ret = fimc_pop_outq(ctrl, ctx, &idx);
if (ret < 0) {
ret = wait_event_timeout(ctrl->wq, (ctx->outq[0] != -1),
@@ -2838,7 +2916,6 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b)
if (ret == 0) {
fimc_dump_context(ctrl, ctx);
fimc_recover_output(ctrl, ctx);
- pm_runtime_put_sync(ctrl->dev);
fimc_err("[0] out_queue is empty\n");
return -EAGAIN;
} else if (ret == -ERESTARTSYS) {
@@ -2854,7 +2931,18 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b)
}
}
}
+#ifdef CONFIG_SLP_DMABUF
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ struct vb2_buffer *vb;
+ vb = ctrl->out_bufs[idx];
+ ret = _dqbuf_dmabuf(ctrl, vb, b);
+ if (ret < 0) {
+ fimc_err("%s: _qbuf_dmabuf error.\n", __func__);
+ return -ENODEV;
+ }
+ }
+#endif
b->index = idx;
fimc_info2("ctx(%d) dqueued idx = %d\n", ctx->ctx_num, b->index);