diff options
Diffstat (limited to 'drivers/media/video/samsung/fimc/fimc_output.c')
-rw-r--r-- | drivers/media/video/samsung/fimc/fimc_output.c | 145 |
1 files changed, 144 insertions, 1 deletions
diff --git a/drivers/media/video/samsung/fimc/fimc_output.c b/drivers/media/video/samsung/fimc/fimc_output.c index 57611e5..da651c5 100644 --- a/drivers/media/video/samsung/fimc/fimc_output.c +++ b/drivers/media/video/samsung/fimc/fimc_output.c @@ -2726,13 +2726,21 @@ 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 *buf = (struct fimc_buf *)b->m.userptr; struct fimc_ctx *ctx; struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; int idx, ctx_num; int ret = -1; + u32 width; + u32 height; + u32 format; + u32 y_size = 0; + u32 cb_size = 0; + u32 cr_size = 0; + u32 size; + ctx = &ctrl->out->ctx[ctx_id]; fimc_info2("ctx(%d) queued idx = %d\n", ctx->ctx_num, b->index); if (ctx->status == FIMC_STREAMOFF) { @@ -2758,6 +2766,69 @@ int fimc_qbuf_output(void *fh, struct v4l2_buffer *b) return -EINVAL; } + /* Check input buffer for CMA region */ + width = ctx->pix.width; + height = ctx->pix.height; + format = ctx->pix.pixelformat; + y_size = width * height; + + switch (format) { + case V4L2_PIX_FMT_RGB32: + y_size = y_size << 2; + size = PAGE_ALIGN(y_size); + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + y_size = y_size << 1; + size = PAGE_ALIGN(y_size); + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV12M: + cb_size = y_size >> 2; + cr_size = y_size >> 2; + size = PAGE_ALIGN(y_size + cb_size + cr_size); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + cb_size = y_size >> 1; + size = PAGE_ALIGN(y_size + cb_size); + break; + case V4L2_PIX_FMT_NV12T: + fimc_get_nv12t_size(width, height, &y_size, &cb_size); + size = PAGE_ALIGN(y_size + cb_size); + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", __func__, format); + return -EINVAL; + } + + if (buf->base[FIMC_ADDR_Y] != 0 && y_size != 0 && + !cma_is_registered_region(buf->base[FIMC_ADDR_Y], y_size)) { + fimc_err("%s: Y address is not CMA region 0x%x, %d \n", + __func__, buf->base[FIMC_ADDR_Y], y_size); + return -EINVAL; + } + if (buf->base[FIMC_ADDR_CB] != 0 && cb_size != 0 && + !cma_is_registered_region(buf->base[FIMC_ADDR_CB], cb_size)) { + fimc_err("%s: CB address is not CMA region 0x%x, %d \n", + __func__, buf->base[FIMC_ADDR_CB], cb_size); + return -EINVAL; + } + if (buf->base[FIMC_ADDR_CR] != 0 && cr_size != 0 && + !cma_is_registered_region(buf->base[FIMC_ADDR_CR], cr_size)) { + fimc_err("%s: CR address is not CMA region 0x%x, %d \n", + __func__, buf->base[FIMC_ADDR_CR], cr_size); + return -EINVAL; + } + /* End check CMA region */ + if ((ctrl->status == FIMC_READY_ON) || (ctrl->status == FIMC_STREAMON) || (ctrl->status == FIMC_STREAMON_IDLE)) { @@ -2850,6 +2921,78 @@ int fimc_qbuf_output(void *fh, struct v4l2_buffer *b) } } + /* Check output buffer for CMA region */ + width = ctx->fbuf.fmt.width; + height = ctx->fbuf.fmt.height; + format = ctx->fbuf.fmt.pixelformat; + y_size = width * height; + cb_size = 0; + cr_size = 0; + + switch (format) { + case V4L2_PIX_FMT_RGB32: + y_size = y_size << 2; + size = PAGE_ALIGN(y_size); + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + y_size = y_size << 1; + size = PAGE_ALIGN(y_size); + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV12M: + cb_size = y_size >> 2; + cr_size = y_size >> 2; + size = PAGE_ALIGN(y_size + cb_size + cr_size); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + cb_size = y_size >> 1; + size = PAGE_ALIGN(y_size + cb_size); + break; + case V4L2_PIX_FMT_NV12T: + fimc_get_nv12t_size(width, height, &y_size, &cb_size); + size = PAGE_ALIGN(y_size + cb_size); + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", __func__, format); + ret = -EINVAL; + goto err_routine; + } + + if (ctx->dst[idx].base[FIMC_ADDR_Y] != 0 && y_size != 0 && + !cma_is_registered_region((dma_addr_t)ctx->dst[idx].base[FIMC_ADDR_Y], + y_size)) { + fimc_err("%s: Y address is not CMA region 0x%x, %d \n", + __func__, ctx->dst[idx].base[FIMC_ADDR_Y], y_size); + ret = -EINVAL; + goto err_routine; + } + if (ctx->dst[idx].base[FIMC_ADDR_CB] != 0 && cb_size != 0 && + !cma_is_registered_region((dma_addr_t)ctx->dst[idx].base[FIMC_ADDR_CB], + cb_size)) { + fimc_err("%s: CB address is not CMA region 0x%x, %d \n", + __func__, ctx->dst[idx].base[FIMC_ADDR_CB], cb_size); + ret = -EINVAL; + goto err_routine; + } + if (ctx->dst[idx].base[FIMC_ADDR_CR] != 0 && cr_size != 0 && + !cma_is_registered_region((dma_addr_t)ctx->dst[idx].base[FIMC_ADDR_CR], + cr_size)) { + fimc_err("%s: CR address is not CMA region 0x%x, %d \n", + __func__, ctx->dst[idx].base[FIMC_ADDR_CR], cr_size); + ret = -EINVAL; + goto err_routine; + } + /* End check CMA region */ + switch (ctx->overlay.mode) { case FIMC_OVLY_FIFO: ret = fimc_qbuf_output_fifo(ctrl, ctx, idx); |