summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/coda
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/coda')
-rw-r--r--drivers/media/platform/coda/coda-bit.c49
-rw-r--r--drivers/media/platform/coda/coda-common.c70
-rw-r--r--drivers/media/platform/coda/coda.h5
-rw-r--r--drivers/media/platform/coda/imx-vdoa.c49
4 files changed, 120 insertions, 53 deletions
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 403214e00e95..25cbf9e5ac5a 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -427,14 +427,16 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx,
/* Register frame buffers in the parameter buffer */
for (i = 0; i < ctx->num_internal_frames; i++) {
- u32 y, cb, cr;
+ u32 y, cb, cr, mvcol;
/* Start addresses of Y, Cb, Cr planes */
y = ctx->internal_frames[i].paddr;
cb = y + ysize;
cr = y + ysize + ysize/4;
+ mvcol = y + ysize + ysize/4 + ysize/4;
if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) {
cb = round_up(cb, 4096);
+ mvcol = cb + ysize/2;
cr = 0;
/* Packed 20-bit MSB of base addresses */
/* YYYYYCCC, CCyyyyyc, cccc.... */
@@ -448,9 +450,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx,
/* mvcol buffer for h.264 */
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
dev->devtype->product != CODA_DX6)
- coda_parabuf_write(ctx, 96 + i,
- ctx->internal_frames[i].paddr +
- ysize + ysize/4 + ysize/4);
+ coda_parabuf_write(ctx, 96 + i, mvcol);
}
/* mvcol buffer for mpeg4 */
@@ -1247,12 +1247,18 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
dst_buf->sequence = ctx->osequence;
ctx->osequence++;
+ force_ipicture = ctx->params.force_ipicture;
+ if (force_ipicture)
+ ctx->params.force_ipicture = false;
+ else if ((src_buf->sequence % ctx->params.gop_size) == 0)
+ force_ipicture = 1;
+
/*
* Workaround coda firmware BUG that only marks the first
* frame as IDR. This is a problem for some decoders that can't
* recover when a frame is lost.
*/
- if (src_buf->sequence % ctx->params.gop_size) {
+ if (!force_ipicture) {
src_buf->flags |= V4L2_BUF_FLAG_PFRAME;
src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
} else {
@@ -1264,10 +1270,10 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
coda_set_gdi_regs(ctx);
/*
- * Copy headers at the beginning of the first frame for H.264 only.
- * In MPEG4 they are already copied by the coda.
+ * Copy headers in front of the first frame and forced I frames for
+ * H.264 only. In MPEG4 they are already copied by the CODA.
*/
- if (src_buf->sequence == 0) {
+ if (src_buf->sequence == 0 || force_ipicture) {
pic_stream_buffer_addr =
vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) +
ctx->vpu_header_size[0] +
@@ -1291,8 +1297,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
pic_stream_buffer_size = q_data_dst->sizeimage;
}
- if (src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) {
- force_ipicture = 1;
+ if (force_ipicture) {
switch (dst_fourcc) {
case V4L2_PIX_FMT_H264:
quant_param = ctx->params.h264_intra_qp;
@@ -1309,7 +1314,6 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
break;
}
} else {
- force_ipicture = 0;
switch (dst_fourcc) {
case V4L2_PIX_FMT_H264:
quant_param = ctx->params.h264_inter_qp;
@@ -1382,7 +1386,8 @@ static void coda_finish_encode(struct coda_ctx *ctx)
wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
/* Calculate bytesused field */
- if (dst_buf->sequence == 0) {
+ if (dst_buf->sequence == 0 ||
+ src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) {
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
ctx->vpu_header_size[0] +
ctx->vpu_header_size[1] +
@@ -2193,12 +2198,32 @@ static void coda_finish_decode(struct coda_ctx *ctx)
ctx->display_idx = display_idx;
}
+static void coda_error_decode(struct coda_ctx *ctx)
+{
+ struct vb2_v4l2_buffer *dst_buf;
+
+ /*
+ * For now this only handles the case where we would deadlock with
+ * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS,
+ * but after a failed decode run we would hold the context and wait for
+ * userspace to queue more buffers.
+ */
+ if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))
+ return;
+
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf->sequence = ctx->qsequence - 1;
+
+ coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
+}
+
const struct coda_context_ops coda_bit_decode_ops = {
.queue_init = coda_decoder_queue_init,
.reqbufs = coda_decoder_reqbufs,
.start_streaming = coda_start_decoding,
.prepare_run = coda_prepare_decode,
.finish_run = coda_finish_decode,
+ .error_run = coda_error_decode,
.seq_end_work = coda_seq_end_work,
.release = coda_bit_release,
};
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index d523e990d509..f92cc7df58fb 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -430,10 +430,10 @@ static int coda_g_fmt(struct file *file, void *priv,
f->fmt.pix.bytesperline = q_data->bytesperline;
f->fmt.pix.sizeimage = q_data->sizeimage;
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- else
- f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+ f->fmt.pix.quantization = ctx->quantization;
return 0;
}
@@ -599,6 +599,9 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
}
f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+ f->fmt.pix.quantization = ctx->quantization;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
@@ -612,7 +615,6 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
/* The h.264 decoder only returns complete 16x16 macroblocks */
if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
- f->fmt.pix.width = f->fmt.pix.width;
f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
@@ -635,6 +637,23 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static void coda_set_default_colorspace(struct v4l2_pix_format *fmt)
+{
+ enum v4l2_colorspace colorspace;
+
+ if (fmt->pixelformat == V4L2_PIX_FMT_JPEG)
+ colorspace = V4L2_COLORSPACE_JPEG;
+ else if (fmt->width <= 720 && fmt->height <= 576)
+ colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ colorspace = V4L2_COLORSPACE_REC709;
+
+ fmt->colorspace = colorspace;
+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+}
+
static int coda_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -648,16 +667,8 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
if (ret < 0)
return ret;
- switch (f->fmt.pix.colorspace) {
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_JPEG:
- break;
- default:
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- else
- f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
- }
+ if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT)
+ coda_set_default_colorspace(&f->fmt.pix);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc);
@@ -772,6 +783,9 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
return ret;
ctx->colorspace = f->fmt.pix.colorspace;
+ ctx->xfer_func = f->fmt.pix.xfer_func;
+ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->quantization = f->fmt.pix.quantization;
memset(&f_cap, 0, sizeof(f_cap));
f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1149,6 +1163,9 @@ static void coda_pic_run_work(struct work_struct *work)
ctx->hold = true;
coda_hw_reset(ctx);
+
+ if (ctx->ops->error_run)
+ ctx->ops->error_run(ctx);
} else if (!ctx->aborting) {
ctx->ops->finish_run(ctx);
}
@@ -1282,7 +1299,13 @@ static void set_default_params(struct coda_ctx *ctx)
csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h);
ctx->params.codec_mode = ctx->codec->mode;
- ctx->colorspace = V4L2_COLORSPACE_REC709;
+ if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG)
+ ctx->colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
ctx->params.framerate = 30;
/* Default formats for output and input queues */
@@ -1680,6 +1703,9 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
ctx->params.intra_refresh = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+ ctx->params.force_ipicture = true;
+ break;
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
coda_set_jpeg_compression_quality(ctx, ctrl->val);
break;
@@ -2063,8 +2089,7 @@ static int coda_hw_init(struct coda_dev *dev)
if (ret)
goto err_clk_ahb;
- if (dev->rstc)
- reset_control_reset(dev->rstc);
+ reset_control_reset(dev->rstc);
/*
* Copy the first CODA_ISRAM_SIZE in the internal SRAM.
@@ -2448,13 +2473,8 @@ static int coda_probe(struct platform_device *pdev)
dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
if (IS_ERR(dev->rstc)) {
ret = PTR_ERR(dev->rstc);
- if (ret == -ENOENT || ret == -ENOTSUPP) {
- dev->rstc = NULL;
- } else {
- dev_err(&pdev->dev, "failed get reset control: %d\n",
- ret);
- return ret;
- }
+ dev_err(&pdev->dev, "failed get reset control: %d\n", ret);
+ return ret;
}
/* Get IRAM pool from device tree or platform data */
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 20222befb9b2..40fe22f0d757 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -135,6 +135,7 @@ struct coda_params {
u32 vbv_size;
u32 slice_max_bits;
u32 slice_max_mb;
+ bool force_ipicture;
};
struct coda_buffer_meta {
@@ -182,6 +183,7 @@ struct coda_context_ops {
int (*start_streaming)(struct coda_ctx *ctx);
int (*prepare_run)(struct coda_ctx *ctx);
void (*finish_run)(struct coda_ctx *ctx);
+ void (*error_run)(struct coda_ctx *ctx);
void (*seq_end_work)(struct work_struct *work);
void (*release)(struct coda_ctx *ctx);
};
@@ -206,6 +208,9 @@ struct coda_ctx {
enum coda_inst_type inst_type;
const struct coda_codec *codec;
enum v4l2_colorspace colorspace;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
struct coda_params params;
struct v4l2_ctrl_handler ctrls;
struct v4l2_fh fh;
diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c
index 669a4c82f1ff..df9b71621420 100644
--- a/drivers/media/platform/coda/imx-vdoa.c
+++ b/drivers/media/platform/coda/imx-vdoa.c
@@ -101,6 +101,8 @@ struct vdoa_ctx {
struct vdoa_data *vdoa;
struct completion completion;
struct vdoa_q_data q_data[2];
+ unsigned int submitted_job;
+ unsigned int completed_job;
};
static irqreturn_t vdoa_irq_handler(int irq, void *data)
@@ -114,7 +116,7 @@ static irqreturn_t vdoa_irq_handler(int irq, void *data)
curr_ctx = vdoa->curr_ctx;
if (!curr_ctx) {
- dev_dbg(vdoa->dev,
+ dev_warn(vdoa->dev,
"Instance released before the end of transaction\n");
return IRQ_HANDLED;
}
@@ -127,19 +129,44 @@ static irqreturn_t vdoa_irq_handler(int irq, void *data)
} else if (!(val & VDOAIST_EOT)) {
dev_warn(vdoa->dev, "Spurious interrupt\n");
}
+ curr_ctx->completed_job++;
complete(&curr_ctx->completion);
return IRQ_HANDLED;
}
+int vdoa_wait_for_completion(struct vdoa_ctx *ctx)
+{
+ struct vdoa_data *vdoa = ctx->vdoa;
+
+ if (ctx->submitted_job == ctx->completed_job)
+ return 0;
+
+ if (!wait_for_completion_timeout(&ctx->completion,
+ msecs_to_jiffies(300))) {
+ dev_err(vdoa->dev,
+ "Timeout waiting for transfer result\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vdoa_wait_for_completion);
+
void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src)
{
struct vdoa_q_data *src_q_data, *dst_q_data;
struct vdoa_data *vdoa = ctx->vdoa;
u32 val;
+ if (vdoa->curr_ctx)
+ vdoa_wait_for_completion(vdoa->curr_ctx);
+
vdoa->curr_ctx = ctx;
+ reinit_completion(&ctx->completion);
+ ctx->submitted_job++;
+
src_q_data = &ctx->q_data[V4L2_M2M_SRC];
dst_q_data = &ctx->q_data[V4L2_M2M_DST];
@@ -177,21 +204,6 @@ void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src)
}
EXPORT_SYMBOL(vdoa_device_run);
-int vdoa_wait_for_completion(struct vdoa_ctx *ctx)
-{
- struct vdoa_data *vdoa = ctx->vdoa;
-
- if (!wait_for_completion_timeout(&ctx->completion,
- msecs_to_jiffies(300))) {
- dev_err(vdoa->dev,
- "Timeout waiting for transfer result\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(vdoa_wait_for_completion);
-
struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa)
{
struct vdoa_ctx *ctx;
@@ -218,6 +230,11 @@ void vdoa_context_destroy(struct vdoa_ctx *ctx)
{
struct vdoa_data *vdoa = ctx->vdoa;
+ if (vdoa->curr_ctx == ctx) {
+ vdoa_wait_for_completion(vdoa->curr_ctx);
+ vdoa->curr_ctx = NULL;
+ }
+
clk_disable_unprepare(vdoa->vdoa_clk);
kfree(ctx);
}