summaryrefslogtreecommitdiff
path: root/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c')
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c826
1 files changed, 437 insertions, 389 deletions
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
index 285111c2d9cd..f29cfa3af94a 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -2,7 +2,7 @@
/*
* Wave5 series multi-standard codec IP - encoder interface
*
- * Copyright (C) 2021 CHIPS&MEDIA INC
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
#include "wave5-helper.h"
@@ -73,58 +73,36 @@ static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = {
}
};
-static enum wave_std wave5_to_vpu_wavestd(unsigned int v4l2_pix_fmt)
+static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state)
{
- switch (v4l2_pix_fmt) {
- case V4L2_PIX_FMT_H264:
- return W_AVC_ENC;
- case V4L2_PIX_FMT_HEVC:
- return W_HEVC_ENC;
- default:
- return STD_UNKNOWN;
- }
-}
-
-static struct vb2_v4l2_buffer *wave5_get_valid_src_buf(struct vpu_instance *inst)
-{
- struct v4l2_m2m_buffer *v4l2_m2m_buf;
-
- v4l2_m2m_for_each_src_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
- struct vb2_v4l2_buffer *vb2_v4l2_buf;
- struct vpu_buffer *vpu_buf = NULL;
-
- vb2_v4l2_buf = &v4l2_m2m_buf->vb;
- vpu_buf = wave5_to_vpu_buf(vb2_v4l2_buf);
-
- if (!vpu_buf->consumed) {
- dev_dbg(inst->dev->dev, "%s: src buf (index: %u) has not been consumed\n",
- __func__, vb2_v4l2_buf->vb2_buf.index);
- return vb2_v4l2_buf;
- }
- }
-
- return NULL;
-}
-
-static struct vb2_v4l2_buffer *wave5_get_valid_dst_buf(struct vpu_instance *inst)
-{
- struct v4l2_m2m_buffer *v4l2_m2m_buf;
-
- v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
- struct vb2_v4l2_buffer *vb2_v4l2_buf;
- struct vpu_buffer *vpu_buf = NULL;
-
- vb2_v4l2_buf = &v4l2_m2m_buf->vb;
- vpu_buf = wave5_to_vpu_buf(vb2_v4l2_buf);
+ switch (state) {
+ case VPU_INST_STATE_NONE:
+ goto invalid_state_switch;
+ case VPU_INST_STATE_OPEN:
+ if (inst->state != VPU_INST_STATE_NONE)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_INIT_SEQ:
+ if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_PIC_RUN:
+ if (inst->state != VPU_INST_STATE_INIT_SEQ)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_STOP:
+ break;
+ };
- if (!vpu_buf->consumed) {
- dev_dbg(inst->dev->dev, "%s: dst buf (index: %u) has not been consumed\n",
- __func__, vb2_v4l2_buf->vb2_buf.index);
- return vb2_v4l2_buf;
- }
- }
+ dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ inst->state = state;
+ return 0;
- return NULL;
+invalid_state_switch:
+ WARN(1, "Invalid state switch from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ return -EINVAL;
}
static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
@@ -162,138 +140,118 @@ static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned
pix_mp->width = width;
pix_mp->height = height;
pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage = width * height;
+ pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3;
break;
}
}
-static void wave5_vpu_enc_start_encode(struct vpu_instance *inst)
+static int start_encode(struct vpu_instance *inst, u32 *fail_res)
{
- u32 max_cmd_q = 0;
-
- max_cmd_q = (inst->src_buf_count < COMMAND_QUEUE_DEPTH) ?
- inst->src_buf_count : COMMAND_QUEUE_DEPTH;
-
- if (inst->state == VPU_INST_STATE_STOP)
- max_cmd_q = 1;
-
- while (max_cmd_q) {
- struct vb2_v4l2_buffer *src_buf;
- struct vb2_v4l2_buffer *dst_buf;
- struct vpu_buffer *src_vbuf;
- struct vpu_buffer *dst_vbuf;
- struct frame_buffer frame_buf;
- struct enc_param pic_param;
- u32 stride = ALIGN(inst->dst_fmt.width, 32);
- u32 luma_size = (stride * inst->dst_fmt.height);
- u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2));
- u32 fail_res;
- int ret;
-
- memset(&pic_param, 0, sizeof(struct enc_param));
- memset(&frame_buf, 0, sizeof(struct frame_buffer));
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ struct frame_buffer frame_buf;
+ struct enc_param pic_param;
+ u32 stride = ALIGN(inst->dst_fmt.width, 32);
+ u32 luma_size = (stride * inst->dst_fmt.height);
+ u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2));
+
+ memset(&pic_param, 0, sizeof(struct enc_param));
+ memset(&frame_buf, 0, sizeof(struct frame_buffer));
+
+ dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
+ if (!dst_buf) {
+ dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__);
+ return -EAGAIN;
+ }
- src_buf = wave5_get_valid_src_buf(inst);
- dst_buf = wave5_get_valid_dst_buf(inst);
+ pic_param.pic_stream_buffer_addr =
+ vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ pic_param.pic_stream_buffer_size =
+ vb2_plane_size(&dst_buf->vb2_buf, 0);
- if (!dst_buf) {
- dev_dbg(inst->dev->dev, "%s: No valid dst buf\n", __func__);
- break;
+ src_buf = v4l2_m2m_next_src_buf(m2m_ctx);
+ if (!src_buf) {
+ dev_dbg(inst->dev->dev, "%s: No source buffer found\n", __func__);
+ if (m2m_ctx->is_draining)
+ pic_param.src_end_flag = 1;
+ else
+ return -EAGAIN;
+ } else {
+ if (inst->src_fmt.num_planes == 1) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb = frame_buf.buf_y + luma_size;
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 2) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 3) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
+ frame_buf.buf_cr =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 2);
}
+ frame_buf.stride = stride;
+ pic_param.src_idx = src_buf->vb2_buf.index;
+ }
- dst_vbuf = wave5_to_vpu_buf(dst_buf);
- pic_param.pic_stream_buffer_addr =
- vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
- pic_param.pic_stream_buffer_size =
- vb2_plane_size(&dst_buf->vb2_buf, 0);
+ pic_param.source_frame = &frame_buf;
+ pic_param.code_option.implicit_header_encode = 1;
+ pic_param.code_option.encode_aud = inst->encode_aud;
+ ret = wave5_vpu_enc_start_one_frame(inst, &pic_param, fail_res);
+ if (ret) {
+ if (*fail_res == WAVE5_SYSERR_QUEUEING_FAIL)
+ return -EINVAL;
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n",
+ __func__, ret);
+ src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
if (!src_buf) {
- dev_dbg(inst->dev->dev, "%s: No valid src buf\n", __func__);
- if (inst->state == VPU_INST_STATE_STOP)
- pic_param.src_end_flag = true;
- else
- break;
- } else {
- src_vbuf = wave5_to_vpu_buf(src_buf);
- if (inst->src_fmt.num_planes == 1) {
- frame_buf.buf_y =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- frame_buf.buf_cb = frame_buf.buf_y + luma_size;
- frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
- } else if (inst->src_fmt.num_planes == 2) {
- frame_buf.buf_y =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- frame_buf.buf_cb =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
- frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
- } else if (inst->src_fmt.num_planes == 3) {
- frame_buf.buf_y =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- frame_buf.buf_cb =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
- frame_buf.buf_cr =
- vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 2);
- }
- frame_buf.stride = stride;
- pic_param.src_idx = src_buf->vb2_buf.index;
+ dev_dbg(inst->dev->dev,
+ "%s: Removing src buf failed, the queue is empty\n",
+ __func__);
+ return -EINVAL;
}
-
- pic_param.source_frame = &frame_buf;
- pic_param.code_option.implicit_header_encode = 1;
- ret = wave5_vpu_enc_start_one_frame(inst, &pic_param, &fail_res);
- if (ret) {
- if (fail_res == WAVE5_SYSERR_QUEUEING_FAIL)
- break;
-
- dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n",
- __func__, ret);
- src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
- if (!src_buf) {
- dev_dbg(inst->dev->dev,
- "%s: Removing src buf failed, the queue is empty\n",
- __func__);
- continue;
- }
- dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
- if (!dst_buf) {
- dev_dbg(inst->dev->dev,
- "%s: Removing dst buf failed, the queue is empty\n",
- __func__);
- continue;
- }
- inst->state = VPU_INST_STATE_STOP;
- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
- v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
- } else {
- dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n",
+ dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+ if (!dst_buf) {
+ dev_dbg(inst->dev->dev,
+ "%s: Removing dst buf failed, the queue is empty\n",
__func__);
- if (src_buf)
- src_vbuf->consumed = true;
- if (dst_buf)
- dst_vbuf->consumed = true;
+ return -EINVAL;
}
-
- max_cmd_q--;
+ switch_state(inst, VPU_INST_STATE_STOP);
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ } else {
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n",
+ __func__);
+ /*
+ * Remove the source buffer from the ready-queue now and finish
+ * it in the videobuf2 framework once the index is returned by the
+ * firmware in finish_encode
+ */
+ if (src_buf)
+ v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, src_buf->vb2_buf.index);
}
-}
-
-static void wave5_vpu_enc_stop_encode(struct vpu_instance *inst)
-{
- inst->state = VPU_INST_STATE_STOP;
- v4l2_m2m_job_finish(inst->v4l2_m2m_dev, inst->v4l2_fh.m2m_ctx);
+ return 0;
}
static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst)
{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
int ret;
struct enc_output_info enc_output_info;
- u32 irq_status;
+ struct vb2_v4l2_buffer *src_buf = NULL;
struct vb2_v4l2_buffer *dst_buf = NULL;
- struct v4l2_m2m_buffer *v4l2_m2m_buf = NULL;
-
- if (kfifo_out(&inst->irq_status, &irq_status, sizeof(int)))
- wave5_vpu_clear_interrupt_ex(inst, irq_status);
ret = wave5_vpu_enc_get_output_info(inst, &enc_output_info);
if (ret) {
@@ -303,39 +261,57 @@ static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst)
return;
}
- v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
- dst_buf = &v4l2_m2m_buf->vb;
- if (enc_output_info.bitstream_buffer ==
- vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0))
- break;
- }
+ dev_dbg(inst->dev->dev,
+ "%s: pic_type %i recon_idx %i src_idx %i pic_byte %u pts %llu\n",
+ __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index,
+ enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts);
+ /*
+ * The source buffer will not be found in the ready-queue as it has been
+ * dropped after sending of the encode firmware command, locate it in
+ * the videobuf2 queue directly
+ */
if (enc_output_info.enc_src_idx >= 0) {
- struct vb2_v4l2_buffer *src_buf =
- v4l2_m2m_src_buf_remove_by_idx(inst->v4l2_fh.m2m_ctx,
+ struct vb2_buffer *vb = vb2_get_buffer(v4l2_m2m_get_src_vq(m2m_ctx),
enc_output_info.enc_src_idx);
+ if (vb->state != VB2_BUF_STATE_ACTIVE)
+ dev_warn(inst->dev->dev,
+ "%s: encoded buffer (%d) was not in ready queue %i.",
+ __func__, enc_output_info.enc_src_idx, vb->state);
+ else
+ src_buf = to_vb2_v4l2_buffer(vb);
- inst->timestamp = src_buf->vb2_buf.timestamp;
- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ if (src_buf) {
+ inst->timestamp = src_buf->vb2_buf.timestamp;
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ } else {
+ dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n",
+ __func__, enc_output_info.enc_src_idx);
+ }
}
+ dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_ENC_END) {
static const struct v4l2_event vpu_event_eos = {
.type = V4L2_EVENT_EOS
};
- vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
- dst_buf->vb2_buf.timestamp = inst->timestamp;
- dst_buf->field = V4L2_FIELD_NONE;
- dst_buf->flags |= V4L2_BUF_FLAG_LAST;
- v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf);
- v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+ if (!WARN_ON(!dst_buf)) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ dst_buf->field = V4L2_FIELD_NONE;
+ v4l2_m2m_last_buffer_done(m2m_ctx, dst_buf);
+ }
- inst->state = VPU_INST_STATE_PIC_RUN;
v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos);
- v4l2_m2m_job_finish(inst->v4l2_m2m_dev, inst->v4l2_fh.m2m_ctx);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
} else {
+ if (!dst_buf) {
+ dev_warn(inst->dev->dev, "No bitstream buffer.");
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ return;
+ }
+
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_output_info.bitstream_size);
dst_buf->vb2_buf.timestamp = inst->timestamp;
@@ -352,11 +328,12 @@ static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst)
dst_buf->flags |= V4L2_BUF_FLAG_BFRAME;
}
- v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
dev_dbg(inst->dev->dev, "%s: frame_cycle %8u\n",
__func__, enc_output_info.frame_cycle);
+
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
}
@@ -364,7 +341,6 @@ static int wave5_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capab
{
strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver));
strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card));
- strscpy(cap->bus_info, "platform:" VPU_ENC_DRV_NAME, sizeof(cap->bus_info));
return 0;
}
@@ -420,9 +396,6 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return -EINVAL;
-
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
if (!vpu_fmt) {
f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
@@ -441,10 +414,8 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
f->fmt.pix_mp.field = V4L2_FIELD_NONE;
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
- f->fmt.pix_mp.hsv_enc = inst->hsv_enc;
f->fmt.pix_mp.quantization = inst->quantization;
f->fmt.pix_mp.xfer_func = inst->xfer_func;
- memset(&f->fmt.pix_mp.reserved, 0, sizeof(f->fmt.pix_mp.reserved));
return 0;
}
@@ -462,6 +433,13 @@ static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_form
if (ret)
return ret;
+ inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type);
+ if (inst->std == STD_UNKNOWN) {
+ dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n",
+ (char *)&f->fmt.pix_mp.pixelformat);
+ return -EINVAL;
+ }
+
inst->dst_fmt.width = f->fmt.pix_mp.width;
inst->dst_fmt.height = f->fmt.pix_mp.height;
inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat;
@@ -494,7 +472,6 @@ static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_form
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
- f->fmt.pix_mp.hsv_enc = inst->hsv_enc;
f->fmt.pix_mp.quantization = inst->quantization;
f->fmt.pix_mp.xfer_func = inst->xfer_func;
@@ -527,9 +504,6 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
- if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]);
if (!vpu_fmt) {
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
@@ -547,7 +521,6 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
f->fmt.pix_mp.flags = 0;
f->fmt.pix_mp.field = V4L2_FIELD_NONE;
- memset(&f->fmt.pix_mp.reserved, 0, sizeof(f->fmt.pix_mp.reserved));
return 0;
}
@@ -591,7 +564,6 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->colorspace = f->fmt.pix_mp.colorspace;
inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
- inst->hsv_enc = f->fmt.pix_mp.hsv_enc;
inst->quantization = f->fmt.pix_mp.quantization;
inst->xfer_func = f->fmt.pix_mp.xfer_func;
@@ -606,27 +578,18 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se
dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target);
- if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- switch (s->target) {
- case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_CROP_BOUNDS:
- s->r.left = 0;
- s->r.top = 0;
- s->r.width = inst->dst_fmt.width;
- s->r.height = inst->dst_fmt.height;
- break;
- case V4L2_SEL_TGT_CROP:
- s->r.left = 0;
- s->r.top = 0;
- s->r.width = inst->dst_fmt.width;
- s->r.height = inst->dst_fmt.height;
- dev_dbg(inst->dev->dev, "%s: V4L2_SEL_TGT_CROP width: %u | height: %u\n",
- __func__, s->r.width, s->r.height);
- break;
- default:
- return -EINVAL;
- }
- } else {
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->dst_fmt.width;
+ s->r.height = inst->dst_fmt.height;
+ break;
+ default:
return -EINVAL;
}
@@ -657,6 +620,7 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se
static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
int ret;
ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
@@ -668,8 +632,14 @@ static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_en
switch (ec->cmd) {
case V4L2_ENC_CMD_STOP:
- inst->state = VPU_INST_STATE_STOP;
- inst->ops->start_process(inst);
+ if (m2m_ctx->is_draining)
+ return -EBUSY;
+
+ if (m2m_ctx->has_stopped)
+ return 0;
+
+ m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx);
+ m2m_ctx->is_draining = true;
break;
case V4L2_ENC_CMD_START:
break;
@@ -769,6 +739,9 @@ static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
dev_dbg(inst->dev->dev, "%s: name: %s | value: %d\n", __func__, ctrl->name, ctrl->val);
switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
+ inst->encode_aud = ctrl->val;
+ break;
case V4L2_CID_HFLIP:
inst->mirror_direction |= (ctrl->val << 1);
break;
@@ -1101,6 +1074,57 @@ static const struct v4l2_ctrl_ops wave5_vpu_enc_ctrl_ops = {
.s_ctrl = wave5_vpu_enc_s_ctrl,
};
+static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane inst_format =
+ (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
+
+ dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
+ *num_buffers, *num_planes, q->type);
+
+ if (*num_planes) {
+ if (inst_format.num_planes != *num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < inst_format.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = inst_format.num_planes;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]);
+ }
+ }
+
+ dev_dbg(inst->dev->dev, "%s: size: %u\n", __func__, sizes[0]);
+
+ return 0;
+}
+
+static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n",
+ __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ vbuf->sequence = inst->queued_src_buf_num++;
+ else
+ vbuf->sequence = inst->queued_dst_buf_num++;
+
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+}
+
static void wave5_set_enc_openparam(struct enc_open_param *open_param,
struct vpu_instance *inst)
{
@@ -1122,8 +1146,6 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
open_param->wave_param.rdo_skip = 1;
open_param->wave_param.lambda_scaling_enable = 1;
- open_param->stream_endian = VPU_STREAM_ENDIAN;
- open_param->source_endian = VPU_SOURCE_ENDIAN;
open_param->line_buf_int_en = true;
open_param->pic_width = inst->dst_fmt.width;
open_param->pic_height = inst->dst_fmt.height;
@@ -1199,65 +1221,107 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
}
}
-static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
- unsigned int *num_planes, unsigned int sizes[],
- struct device *alloc_devs[])
+static int initialize_sequence(struct vpu_instance *inst)
{
- struct vpu_instance *inst = vb2_get_drv_priv(q);
- struct v4l2_pix_format_mplane inst_format =
- (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
- unsigned int i;
+ struct enc_initial_info initial_info;
+ struct v4l2_ctrl *ctrl;
int ret;
- dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
- *num_buffers, *num_planes, q->type);
+ ret = wave5_vpu_enc_issue_seq_init(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n",
+ __func__, ret);
+ return ret;
+ }
- if (*num_planes) {
- if (inst_format.num_planes != *num_planes)
- return -EINVAL;
+ if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) {
+ dev_err(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__);
+ return -EINVAL;
+ }
- for (i = 0; i < *num_planes; i++) {
- if (sizes[i] < inst_format.plane_fmt[i].sizeimage)
- return -EINVAL;
- }
- } else {
- *num_planes = inst_format.num_planes;
- for (i = 0; i < *num_planes; i++) {
- sizes[i] = inst_format.plane_fmt[i].sizeimage;
- dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]);
+ ret = wave5_vpu_enc_complete_seq_init(inst, &initial_info);
+ if (ret)
+ return ret;
+
+ dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n",
+ __func__, initial_info.min_frame_buffer_count,
+ initial_info.min_src_frame_count);
+ inst->min_src_buf_count = initial_info.min_src_frame_count +
+ COMMAND_QUEUE_DEPTH;
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, inst->min_src_buf_count);
+
+ inst->fbc_buf_count = initial_info.min_frame_buffer_count;
+
+ return 0;
+}
+
+static int prepare_fb(struct vpu_instance *inst)
+{
+ u32 fb_stride = ALIGN(inst->dst_fmt.width, 32);
+ u32 fb_height = ALIGN(inst->dst_fmt.height, 32);
+ int i, ret = 0;
+
+ for (i = 0; i < inst->fbc_buf_count; i++) {
+ u32 luma_size = fb_stride * fb_height;
+ u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height;
+
+ inst->frame_vbuf[i].size = luma_size + chroma_size;
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, &inst->frame_vbuf[i]);
+ if (ret < 0) {
+ dev_err(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n",
+ __func__, inst->frame_vbuf[i].size);
+ goto free_buffers;
}
+
+ inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr;
+ inst->frame_buf[i].buf_cb = (dma_addr_t)-1;
+ inst->frame_buf[i].buf_cr = (dma_addr_t)-1;
+ inst->frame_buf[i].update_fb_info = true;
+ inst->frame_buf[i].size = inst->frame_vbuf[i].size;
}
- dev_dbg(inst->dev->dev, "%s: size: %u\n", __func__, sizes[0]);
+ ret = wave5_vpu_enc_register_frame_buffer(inst, inst->fbc_buf_count, fb_stride,
+ fb_height, COMPRESSED_FRAME_MAP);
+ if (ret) {
+ dev_err(inst->dev->dev,
+ "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n",
+ __func__, ret);
+ goto free_buffers;
+ }
+
+ return 0;
+free_buffers:
+ for (i = 0; i < inst->fbc_buf_count; i++)
+ wave5_vpu_dec_reset_framebuffer(inst, i);
+ return ret;
+}
+
+static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret = 0;
+
+ v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- unsigned int non_linear_num = 0;
- u32 fb_stride = 0;
- u32 fb_height = 0;
struct enc_open_param open_param;
- struct enc_initial_info initial_info;
- struct v4l2_ctrl *ctrl;
memset(&open_param, 0, sizeof(struct enc_open_param));
- inst->std = wave5_to_vpu_wavestd(inst->dst_fmt.pixelformat);
- if (inst->std == STD_UNKNOWN) {
- dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n",
- (char *)&inst->dst_fmt.pixelformat);
- return -EINVAL;
- }
-
wave5_set_enc_openparam(&open_param, inst);
ret = wave5_vpu_enc_open(inst, &open_param);
if (ret) {
dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_open, fail: %d\n",
__func__, ret);
- return ret;
+ goto return_buffers;
}
- inst->state = VPU_INST_STATE_OPEN;
-
if (inst->mirror_direction) {
wave5_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL);
wave5_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION,
@@ -1268,123 +1332,81 @@ static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buff
wave5_vpu_enc_give_command(inst, SET_ROTATION_ANGLE, &inst->rot_angle);
}
- ret = wave5_vpu_enc_issue_seq_init(inst);
+ ret = switch_state(inst, VPU_INST_STATE_OPEN);
+ if (ret)
+ goto return_buffers;
+ }
+ if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) {
+ ret = initialize_sequence(inst);
if (ret) {
- dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n",
- __func__, ret);
- return ret;
- }
-
- if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) {
- dev_dbg(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__);
- return -EINVAL;
+ dev_warn(inst->dev->dev, "Sequence not found: %d\n", ret);
+ goto return_buffers;
}
-
- ret = wave5_vpu_enc_complete_seq_init(inst, &initial_info);
+ ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ);
if (ret)
- return ret;
-
- dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n",
- __func__, initial_info.min_frame_buffer_count,
- initial_info.min_src_frame_count);
- inst->state = VPU_INST_STATE_INIT_SEQ;
- inst->min_src_buf_count = initial_info.min_src_frame_count +
- COMMAND_QUEUE_DEPTH;
-
- ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
- V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
- if (ctrl)
- v4l2_ctrl_s_ctrl(ctrl, inst->min_src_buf_count);
-
- inst->min_dst_buf_count = initial_info.min_frame_buffer_count;
- inst->src_buf_count = inst->min_src_buf_count;
-
- if (*num_buffers > inst->src_buf_count)
- inst->src_buf_count = *num_buffers;
-
- *num_buffers = inst->src_buf_count;
- non_linear_num = inst->min_dst_buf_count;
-
- fb_stride = ALIGN(inst->dst_fmt.width, 32);
- fb_height = ALIGN(inst->dst_fmt.height, 32);
-
- for (i = 0; i < non_linear_num; i++) {
- u32 luma_size = fb_stride * fb_height;
- u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height;
-
- inst->frame_vbuf[i].size = luma_size + chroma_size;
- ret = wave5_vdi_allocate_dma_memory(inst->dev, &inst->frame_vbuf[i]);
- if (ret < 0) {
- dev_dbg(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n",
- __func__, inst->frame_vbuf[i].size);
- goto free_buffers;
- }
-
- inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr;
- inst->frame_buf[i].buf_cb = (dma_addr_t)-1;
- inst->frame_buf[i].buf_cr = (dma_addr_t)-1;
- inst->frame_buf[i].update_fb_info = true;
- inst->frame_buf[i].size = inst->frame_vbuf[i].size;
- }
-
- ret = wave5_vpu_enc_register_frame_buffer(inst, non_linear_num, fb_stride,
- fb_height, COMPRESSED_FRAME_MAP);
+ goto return_buffers;
+ /*
+ * The sequence must be analyzed first to calculate the proper
+ * size of the auxiliary buffers.
+ */
+ ret = prepare_fb(inst);
if (ret) {
- dev_dbg(inst->dev->dev,
- "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n",
- __func__, ret);
- goto free_buffers;
+ dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret);
+ goto return_buffers;
}
- inst->state = VPU_INST_STATE_PIC_RUN;
- }
-
- if (inst->state == VPU_INST_STATE_INIT_SEQ &&
- q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- *num_buffers = inst->src_buf_count;
- dev_dbg(inst->dev->dev, "%s: src buf num: %u", __func__, *num_buffers);
+ ret = switch_state(inst, VPU_INST_STATE_PIC_RUN);
}
+ if (ret)
+ goto return_buffers;
return 0;
-
-free_buffers:
- for (i = 0; i < inst->min_dst_buf_count; i++)
- wave5_vdi_free_dma_memory(inst->dev, &inst->frame_vbuf[i]);
+return_buffers:
+ wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
return ret;
}
-static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb)
+static void streamoff_output(struct vpu_instance *inst, struct vb2_queue *q)
{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
- struct vpu_buffer *vpu_buf = wave5_to_vpu_buf(vbuf);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
- dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n",
- __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
- vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+ while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) {
+ dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+}
- if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- vbuf->sequence = inst->queued_src_buf_num++;
- else
- vbuf->sequence = inst->queued_dst_buf_num++;
+static void streamoff_capture(struct vpu_instance *inst, struct vb2_queue *q)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
- vpu_buf->consumed = FALSE;
- v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
+ while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) {
+ dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+ vb2_set_plane_payload(&buf->vb2_buf, 0, 0);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
- if (vb2_start_streaming_called(vb->vb2_queue))
- inst->ops->start_process(inst);
+ v4l2_m2m_clear_state(m2m_ctx);
}
static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
{
struct vpu_instance *inst = vb2_get_drv_priv(q);
- struct vb2_v4l2_buffer *buf;
bool check_cmd = true;
+ /*
+ * Note that we don't need m2m_ctx->next_buf_last for this driver, so we
+ * don't call v4l2_m2m_update_stop_streaming_state().
+ */
+
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
if (wave5_vpu_both_queues_are_streaming(inst))
- inst->state = VPU_INST_STATE_STOP;
+ switch_state(inst, VPU_INST_STATE_STOP);
while (check_cmd) {
struct queue_status_info q_status;
@@ -1392,7 +1414,7 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
wave5_vpu_enc_give_command(inst, ENC_GET_QUEUE_STATUS, &q_status);
- if (q_status.instance_queue_count + q_status.report_queue_count == 0)
+ if (q_status.report_queue_count == 0)
break;
if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0)
@@ -1402,20 +1424,10 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
dev_dbg(inst->dev->dev, "Getting encoding results from fw, fail\n");
}
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- while ((buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx))) {
- dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
- __func__, buf->vb2_buf.type, buf->vb2_buf.index);
- v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
- }
- } else {
- while ((buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx))) {
- dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
- __func__, buf->vb2_buf.type, buf->vb2_buf.index);
- vb2_set_plane_payload(&buf->vb2_buf, 0, 0);
- v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
- }
- }
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ streamoff_output(inst, q);
+ else
+ streamoff_capture(inst, q);
}
static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
@@ -1423,6 +1435,7 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.buf_queue = wave5_vpu_enc_buf_queue,
+ .start_streaming = wave5_vpu_enc_start_streaming,
.stop_streaming = wave5_vpu_enc_stop_streaming,
};
@@ -1451,39 +1464,68 @@ static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct
}
static const struct vpu_instance_ops wave5_vpu_enc_inst_ops = {
- .start_process = wave5_vpu_enc_start_encode,
- .stop_process = wave5_vpu_enc_stop_encode,
.finish_process = wave5_vpu_enc_finish_encode,
};
static void wave5_vpu_enc_device_run(void *priv)
{
struct vpu_instance *inst = priv;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ u32 fail_res = 0;
+ int ret = 0;
- inst->ops->start_process(inst);
+ switch (inst->state) {
+ case VPU_INST_STATE_PIC_RUN:
+ ret = start_encode(inst, &fail_res);
+ if (ret) {
+ if (ret == -EINVAL)
+ dev_err(inst->dev->dev,
+ "Frame encoding on m2m context (%p), fail: %d (res: %d)\n",
+ m2m_ctx, ret, fail_res);
+ else if (ret == -EAGAIN)
+ dev_dbg(inst->dev->dev, "Missing buffers for encode, try again\n");
+ break;
+ }
+ dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ return;
+ default:
+ WARN(1, "Execution of a job in state %s is invalid.\n",
+ state_to_str(inst->state));
+ break;
+ }
+ dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
static int wave5_vpu_enc_job_ready(void *priv)
{
struct vpu_instance *inst = priv;
-
- if (inst->state == VPU_INST_STATE_STOP)
- return 0;
-
- return 1;
-}
-
-static void wave5_vpu_enc_job_abort(void *priv)
-{
- struct vpu_instance *inst = priv;
-
- inst->ops->stop_process(inst);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ switch (inst->state) {
+ case VPU_INST_STATE_NONE:
+ dev_dbg(inst->dev->dev, "Encoder must be open to start queueing M2M jobs!\n");
+ return false;
+ case VPU_INST_STATE_PIC_RUN:
+ if (m2m_ctx->is_draining || v4l2_m2m_num_src_bufs_ready(m2m_ctx)) {
+ dev_dbg(inst->dev->dev, "Encoder ready for a job, state: %s\n",
+ state_to_str(inst->state));
+ return true;
+ }
+ fallthrough;
+ default:
+ dev_dbg(inst->dev->dev,
+ "Encoder not ready for a job, state: %s, %s draining, %d src bufs ready\n",
+ state_to_str(inst->state), m2m_ctx->is_draining ? "is" : "is not",
+ v4l2_m2m_num_src_bufs_ready(m2m_ctx));
+ break;
+ }
+ return false;
}
static const struct v4l2_m2m_ops wave5_vpu_enc_m2m_ops = {
.device_run = wave5_vpu_enc_device_run,
.job_ready = wave5_vpu_enc_job_ready,
- .job_abort = wave5_vpu_enc_job_abort,
};
static int wave5_vpu_open_enc(struct file *filp)
@@ -1503,6 +1545,10 @@ static int wave5_vpu_open_enc(struct file *filp)
inst->type = VPU_INST_TYPE_ENC;
inst->ops = &wave5_vpu_enc_inst_ops;
+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
+ if (!inst->codec_info)
+ return -ENOMEM;
+
v4l2_fh_init(&inst->v4l2_fh, vdev);
filp->private_data = &inst->v4l2_fh;
v4l2_fh_add(&inst->v4l2_fh);
@@ -1510,19 +1556,14 @@ static int wave5_vpu_open_enc(struct file *filp)
INIT_LIST_HEAD(&inst->list);
list_add_tail(&inst->list, &dev->instances);
- inst->v4l2_m2m_dev = v4l2_m2m_init(&wave5_vpu_enc_m2m_ops);
- if (IS_ERR(inst->v4l2_m2m_dev)) {
- ret = PTR_ERR(inst->v4l2_m2m_dev);
- dev_err(inst->dev->dev, "v4l2_m2m_init, fail: %d\n", ret);
- goto cleanup_inst;
- }
-
+ inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev;
inst->v4l2_fh.m2m_ctx =
v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_enc_queue_init);
if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
goto cleanup_inst;
}
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true);
v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50);
v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
@@ -1555,7 +1596,7 @@ static int wave5_vpu_open_enc(struct file *filp)
v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, 0,
- V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA);
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR);
v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
0, 2047, 1, 0);
@@ -1621,7 +1662,9 @@ static int wave5_vpu_open_enc(struct file *filp)
V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0,
V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC);
-
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
+ 0, 1, 1, 1);
v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_HFLIP,
0, 1, 1, 0);
@@ -1633,7 +1676,7 @@ static int wave5_vpu_open_enc(struct file *filp)
0, 270, 90, 0);
v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VBV_SIZE,
- 10, 3000, 1, 3000);
+ 10, 3000, 1, 1000);
v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
@@ -1671,17 +1714,11 @@ static int wave5_vpu_open_enc(struct file *filp)
wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt);
inst->colorspace = V4L2_COLORSPACE_REC709;
inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- inst->hsv_enc = 0;
inst->quantization = V4L2_QUANTIZATION_DEFAULT;
inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
inst->frame_rate = 30;
init_completion(&inst->irq_done);
- ret = kfifo_alloc(&inst->irq_status, 16 * sizeof(int), GFP_KERNEL);
- if (ret) {
- dev_err(inst->dev->dev, "Allocating fifo, fail: %d\n", ret);
- goto cleanup_inst;
- }
inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
if (inst->id < 0) {
@@ -1690,6 +1727,8 @@ static int wave5_vpu_open_enc(struct file *filp)
goto cleanup_inst;
}
+ wave5_vdi_allocate_sram(inst->dev);
+
return 0;
cleanup_inst:
@@ -1720,6 +1759,13 @@ int wave5_vpu_enc_register_device(struct vpu_device *dev)
if (!vdev_enc)
return -ENOMEM;
+ dev->v4l2_m2m_enc_dev = v4l2_m2m_init(&wave5_vpu_enc_m2m_ops);
+ if (IS_ERR(dev->v4l2_m2m_enc_dev)) {
+ ret = PTR_ERR(dev->v4l2_m2m_enc_dev);
+ dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret);
+ return -EINVAL;
+ }
+
dev->video_dev_enc = vdev_enc;
strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name));
@@ -1743,4 +1789,6 @@ int wave5_vpu_enc_register_device(struct vpu_device *dev)
void wave5_vpu_enc_unregister_device(struct vpu_device *dev)
{
video_unregister_device(dev->video_dev_enc);
+ if (dev->v4l2_m2m_enc_dev)
+ v4l2_m2m_release(dev->v4l2_m2m_enc_dev);
}