diff options
Diffstat (limited to 'drivers/media/platform/coda')
-rw-r--r-- | drivers/media/platform/coda/coda-bit.c | 49 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 70 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda.h | 5 | ||||
-rw-r--r-- | drivers/media/platform/coda/imx-vdoa.c | 49 |
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); } |