Am Donnerstag, den 08.12.2016, 16:24 +0100 schrieb Michael Tretter: > If the CODA driver is configured to produce NV12 output and the VDOA is > available, the VDOA can be used to transform the custom macroblock tiled > format to a raster-ordered format for scanout. > > In this case, set the output format of the CODA to the custom macroblock > tiled format, disable the rotator, and use the VDOA to write to the v4l2 > buffer. The VDOA is synchronized with the CODA to always un-tile the > frame that the CODA finished in the previous run. > > Signed-off-by: Michael Tretter <m.tretter@xxxxxxxxxxxxxx> > --- > drivers/media/platform/coda/coda-bit.c | 77 +++++++++++++++++++++---------- > drivers/media/platform/coda/coda-common.c | 55 ++++++++++++++++++++-- > drivers/media/platform/coda/coda.h | 2 + > 3 files changed, 104 insertions(+), 30 deletions(-) > > diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c > index 309eb4e..3e2f830 100644 > --- a/drivers/media/platform/coda/coda-bit.c > +++ b/drivers/media/platform/coda/coda-bit.c > @@ -30,6 +30,7 @@ > #include <media/videobuf2-vmalloc.h> > > #include "coda.h" > +#include "imx-vdoa.h" > #define CREATE_TRACE_POINTS > #include "trace.h" > > @@ -1517,6 +1518,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) > u32 val; > int ret; > > + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, > + "Video Data Order Adapter: %s\n", > + ctx->use_vdoa ? "Enabled" : "Disabled"); > + > /* Start decoding */ > q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); > q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); > @@ -1535,7 +1540,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) > if (dst_fourcc == V4L2_PIX_FMT_NV12) > ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; > if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) > - ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; > + ctx->frame_mem_ctrl |= (0x3 << 9) | > + ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); > coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); > > ctx->display_idx = -1; > @@ -1724,6 +1730,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) > struct coda_q_data *q_data_dst; > struct coda_buffer_meta *meta; > unsigned long flags; > + u32 rot_mode = 0; > u32 reg_addr, reg_stride; > > dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); > @@ -1759,27 +1766,40 @@ static int coda_prepare_decode(struct coda_ctx *ctx) > if (dev->devtype->product == CODA_960) > coda_set_gdi_regs(ctx); > > - if (dev->devtype->product == CODA_960) { > - /* > - * The CODA960 seems to have an internal list of buffers with > - * 64 entries that includes the registered frame buffers as > - * well as the rotator buffer output. > - * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. > - */ > - coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->vb2_buf.index, > - CODA9_CMD_DEC_PIC_ROT_INDEX); > - > - reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; > - reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; > + if (ctx->use_vdoa && > + ctx->display_idx >= 0 && > + ctx->display_idx < ctx->num_internal_frames) { > + vdoa_device_run(ctx->vdoa, > + vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), > + ctx->internal_frames[ctx->display_idx].paddr); > } else { > - reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; > - reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; > + if (dev->devtype->product == CODA_960) { > + /* > + * The CODA960 seems to have an internal list of > + * buffers with 64 entries that includes the > + * registered frame buffers as well as the rotator > + * buffer output. > + * > + * ROT_INDEX needs to be < 0x40, but > > + * ctx->num_internal_frames. > + */ > + coda_write(dev, > + CODA_MAX_FRAMEBUFFERS + dst_buf->vb2_buf.index, > + CODA9_CMD_DEC_PIC_ROT_INDEX); > + > + reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; > + reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; > + } else { > + reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; > + reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; > + } > + coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); > + coda_write(dev, q_data_dst->bytesperline, reg_stride); > + > + rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; > } > - coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); > - coda_write(dev, q_data_dst->bytesperline, reg_stride); > > - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, > - CODA_CMD_DEC_PIC_ROT_MODE); > + coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); > > switch (dev->devtype->product) { > case CODA_DX6: > @@ -1851,6 +1871,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) > u32 src_fourcc; > int success; > u32 err_mb; > + int err_vdoa = 0; > u32 val; > > /* Update kfifo out pointer from coda bitstream read pointer */ > @@ -1934,13 +1955,17 @@ static void coda_finish_decode(struct coda_ctx *ctx) > } > } > > + /* Wait until the VDOA finished writing the previous display frame */ > + if (ctx->use_vdoa && > + ctx->display_idx >= 0 && > + ctx->display_idx < ctx->num_internal_frames) { > + err_vdoa = vdoa_wait_for_completion(ctx->vdoa); > + } > + > ctx->frm_dis_flg = coda_read(dev, > CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); > > - /* > - * The previous display frame was copied out by the rotator, > - * now it can be overwritten again > - */ > + /* The previous display frame was copied out and can be overwritten */ > if (ctx->display_idx >= 0 && > ctx->display_idx < ctx->num_internal_frames) { > ctx->frm_dis_flg &= ~(1 << ctx->display_idx); > @@ -2057,8 +2082,10 @@ static void coda_finish_decode(struct coda_ctx *ctx) > } > vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); > > - coda_m2m_buf_done(ctx, dst_buf, ctx->frame_errors[ctx->display_idx] ? > - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); > + if (ctx->frame_errors[ctx->display_idx] || err_vdoa) > + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); > + else > + coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); > > v4l2_dbg(1, coda_debug, &dev->v4l2_dev, > "job finished: decoding frame (%d) (%s)\n", > diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c > index 3a21000..8b23ea4 100644 > --- a/drivers/media/platform/coda/coda-common.c > +++ b/drivers/media/platform/coda/coda-common.c > @@ -450,6 +450,30 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) > return 0; > } > > +static int coda_try_vdoa(struct coda_ctx *ctx, struct v4l2_format *f) This should probably be called coda_try_fmt_vdoa and add an additional bool *use_vdoa return value ... > +{ > + int err; > + > + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; > + > + if (!ctx->vdoa) { > + ctx->use_vdoa = false; > + return 0; > + } > + > + err = vdoa_context_configure(ctx->vdoa, f->fmt.pix.width, > + f->fmt.pix.height, f->fmt.pix.pixelformat); > + if (err) { > + ctx->use_vdoa = false; > + return 0; > + } > + > + ctx->use_vdoa = true; ... to avoid changing context state when called from TRY_FMT. > + > + return 0; > +} > + > static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, > u32 width, u32 height) > { > @@ -564,6 +588,10 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, > f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); > f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * > f->fmt.pix.height * 3 / 2; > + > + ret = coda_try_vdoa(ctx, f); > + if (ret < 0) > + return ret; > } > > return 0; > @@ -632,13 +660,20 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, > q_data->rect.height = f->fmt.pix.height; > } > > + /* > + * It would be nice to set use_vdoa in coda_s_fmt instead of > + * coda_try_vdoa() to have a single location where this is changed. > + * Unfortunately, if the capture format is V4L2_PIX_FMT_NV12, we > + * cannot be sure if the VDOA should be used, without storing the > + * result of coda_try_vdoa() or calling vdoa_context_configure() > + * again. Therefore, set use_vdoa in coda_try_vdoa. > + */ > + See above. ctx->use_vdoa should only be set in SET_FMT. > switch (f->fmt.pix.pixelformat) { > case V4L2_PIX_FMT_NV12: > - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { > - ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; > - if (!disable_tiling) > - break; > - } > + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; > + if (!disable_tiling) > + break; > /* else fall through */ > case V4L2_PIX_FMT_YUV420: > case V4L2_PIX_FMT_YVU420: > @@ -1764,6 +1799,13 @@ static int coda_open(struct file *file) > default: > ctx->reg_idx = idx; > } > + if (ctx->dev->vdoa) { if (ctx->dev->vdoa && !disable_vdoa) { > + ctx->vdoa = vdoa_context_create(dev->vdoa); > + if (!ctx->vdoa) > + v4l2_warn(&dev->v4l2_dev, > + "Failed to create vdoa context: not using vdoa"); > + } > + ctx->use_vdoa = false; > > /* Power up and upload firmware if necessary */ > ret = pm_runtime_get_sync(&dev->plat_dev->dev); > @@ -1839,6 +1881,9 @@ static int coda_release(struct file *file) > v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", > ctx); > > + if (ctx->vdoa) > + vdoa_context_destroy(ctx->vdoa); > + > if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) > coda_bit_stream_end_flag(ctx); > > diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h > index ae202dc..7ed79eb 100644 > --- a/drivers/media/platform/coda/coda.h > +++ b/drivers/media/platform/coda/coda.h > @@ -237,6 +237,8 @@ struct coda_ctx { > int display_idx; > struct dentry *debugfs_entry; > bool use_bit; > + bool use_vdoa; > + struct vdoa_ctx *vdoa; > }; > > extern int coda_debug; regards Philipp -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html