diff options
Diffstat (limited to 'drivers/media/platform/qcom/iris/iris_vdec.c')
-rw-r--r-- | drivers/media/platform/qcom/iris/iris_vdec.c | 359 |
1 files changed, 89 insertions, 270 deletions
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index 4143acedfc57..ae13c3e1b426 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -7,14 +7,13 @@ #include <media/v4l2-mem2mem.h> #include "iris_buffer.h" +#include "iris_common.h" #include "iris_ctrls.h" #include "iris_instance.h" #include "iris_power.h" #include "iris_vdec.h" #include "iris_vpu_buffer.h" -#define DEFAULT_WIDTH 320 -#define DEFAULT_HEIGHT 240 #define DEFAULT_CODEC_ALIGNMENT 16 int iris_vdec_inst_init(struct iris_inst *inst) @@ -32,6 +31,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) f->fmt.pix_mp.width = DEFAULT_WIDTH; f->fmt.pix_mp.height = DEFAULT_HEIGHT; f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + inst->codec = f->fmt.pix_mp.pixelformat; f->fmt.pix_mp.num_planes = 1; f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); @@ -55,7 +55,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; - memcpy(&inst->fw_caps[0], &core->inst_fw_caps[0], + memcpy(&inst->fw_caps[0], &core->inst_fw_caps_dec[0], INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); return iris_ctrls_init(inst); @@ -67,14 +67,67 @@ void iris_vdec_inst_deinit(struct iris_inst *inst) kfree(inst->fmt_src); } +static const struct iris_fmt iris_vdec_formats[] = { + [IRIS_FMT_H264] = { + .pixfmt = V4L2_PIX_FMT_H264, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_HEVC] = { + .pixfmt = V4L2_PIX_FMT_HEVC, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_VP9] = { + .pixfmt = V4L2_PIX_FMT_VP9, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, +}; + +static const struct iris_fmt * +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) +{ + unsigned int size = ARRAY_SIZE(iris_vdec_formats); + const struct iris_fmt *fmt = iris_vdec_formats; + unsigned int i; + + for (i = 0; i < size; i++) { + if (fmt[i].pixfmt == pixfmt) + break; + } + + if (i == size || fmt[i].type != type) + return NULL; + + return &fmt[i]; +} + +static const struct iris_fmt * +find_format_by_index(struct iris_inst *inst, u32 index, u32 type) +{ + const struct iris_fmt *fmt = iris_vdec_formats; + unsigned int size = ARRAY_SIZE(iris_vdec_formats); + + if (index >= size || fmt[index].type != type) + return NULL; + + return &fmt[index]; +} + int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) { + const struct iris_fmt *fmt; + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - f->pixelformat = V4L2_PIX_FMT_H264; + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixfmt; f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (f->index) + return -EINVAL; f->pixelformat = V4L2_PIX_FMT_NV12; break; default: @@ -88,13 +141,15 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + const struct iris_fmt *fmt; struct v4l2_format *f_inst; struct vb2_queue *src_q; memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + fmt = find_format(inst, pixmp->pixelformat, f->type); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) { + if (!fmt) { f_inst = inst->fmt_src; f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; @@ -145,13 +200,14 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) switch (f->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) return -EINVAL; fmt = inst->fmt_src; fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - - codec_align = DEFAULT_CODEC_ALIGNMENT; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + inst->codec = fmt->fmt.pix_mp.pixelformat; + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); fmt->fmt.pix_mp.num_planes = 1; @@ -171,6 +227,11 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + /* Update capture format based on new ip w/h */ + output_fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); + output_fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); + inst->buffers[BUF_OUTPUT].size = iris_get_buffer_size(inst, BUF_OUTPUT); + inst->crop.left = 0; inst->crop.top = 0; inst->crop.width = f->fmt.pix_mp.width; @@ -203,6 +264,19 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) return 0; } +int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat) +{ + const struct iris_fmt *fmt = NULL; + + if (pixelformat != V4L2_PIX_FMT_NV12) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!fmt) + return -EINVAL; + } + + return 0; +} + int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub) { int ret = 0; @@ -239,161 +313,6 @@ void iris_vdec_src_change(struct iris_inst *inst) v4l2_event_queue_fh(&inst->fh, &event); } -static int iris_vdec_get_num_queued_buffers(struct iris_inst *inst, - enum iris_buffer_type type) -{ - struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; - struct v4l2_m2m_buffer *buffer, *n; - struct iris_buffer *buf; - u32 count = 0; - - switch (type) { - case BUF_INPUT: - v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (!(buf->attr & BUF_ATTR_QUEUED)) - continue; - count++; - } - return count; - case BUF_OUTPUT: - v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (!(buf->attr & BUF_ATTR_QUEUED)) - continue; - count++; - } - return count; - default: - return count; - } -} - -static void iris_vdec_flush_deferred_buffers(struct iris_inst *inst, - enum iris_buffer_type type) -{ - struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; - struct v4l2_m2m_buffer *buffer, *n; - struct iris_buffer *buf; - - if (type == BUF_INPUT) { - v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (buf->attr & BUF_ATTR_DEFERRED) { - if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { - buf->attr |= BUF_ATTR_BUFFER_DONE; - buf->data_size = 0; - iris_vb2_buffer_done(inst, buf); - } - } - } - } else { - v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (buf->attr & BUF_ATTR_DEFERRED) { - if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { - buf->attr |= BUF_ATTR_BUFFER_DONE; - buf->data_size = 0; - iris_vb2_buffer_done(inst, buf); - } - } - } - } -} - -static void iris_vdec_kill_session(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - - if (!inst->session_id) - return; - - hfi_ops->session_close(inst); - iris_inst_change_state(inst, IRIS_INST_ERROR); -} - -int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - enum iris_buffer_type buffer_type; - u32 count; - int ret; - - switch (plane) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - buffer_type = BUF_INPUT; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - buffer_type = BUF_OUTPUT; - break; - default: - return -EINVAL; - } - - ret = hfi_ops->session_stop(inst, plane); - if (ret) - goto error; - - count = iris_vdec_get_num_queued_buffers(inst, buffer_type); - if (count) { - ret = -EINVAL; - goto error; - } - - ret = iris_inst_state_change_streamoff(inst, plane); - if (ret) - goto error; - - iris_vdec_flush_deferred_buffers(inst, buffer_type); - - return 0; - -error: - iris_vdec_kill_session(inst); - iris_vdec_flush_deferred_buffers(inst, buffer_type); - - return ret; -} - -static int iris_vdec_process_streamon_input(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - enum iris_inst_sub_state set_sub_state = 0; - int ret; - - iris_scale_power(inst); - - ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0); - if (ret) - return ret; - } - - if (inst->sub_state & IRIS_INST_SUB_DRC || - inst->sub_state & IRIS_INST_SUB_DRAIN || - inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) { - if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) { - if (hfi_ops->session_pause) { - ret = hfi_ops->session_pause(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - } - set_sub_state = IRIS_INST_SUB_INPUT_PAUSE; - } - } - - ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - - return iris_inst_change_sub_state(inst, 0, set_sub_state); -} - int iris_vdec_streamon_input(struct iris_inst *inst) { int ret; @@ -402,13 +321,13 @@ int iris_vdec_streamon_input(struct iris_inst *inst) if (ret) return ret; - ret = iris_alloc_and_queue_persist_bufs(inst); + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_PERSIST); if (ret) return ret; iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - ret = iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (ret) return ret; @@ -420,69 +339,7 @@ int iris_vdec_streamon_input(struct iris_inst *inst) if (ret) return ret; - return iris_vdec_process_streamon_input(inst); -} - -static int iris_vdec_process_streamon_output(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - bool drain_active = false, drc_active = false; - enum iris_inst_sub_state clear_sub_state = 0; - int ret = 0; - - iris_scale_power(inst); - - drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && - inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; - - drc_active = inst->sub_state & IRIS_INST_SUB_DRC && - inst->sub_state & IRIS_INST_SUB_DRC_LAST; - - if (drc_active) - clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; - else if (drain_active) - clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret = iris_alloc_and_queue_input_int_bufs(inst); - if (ret) - return ret; - ret = iris_set_stage(inst, STAGE); - if (ret) - return ret; - ret = iris_set_pipe(inst, PIPE); - if (ret) - return ret; - } - - if (inst->state == IRIS_INST_INPUT_STREAMING && - inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - if (!drain_active) - ret = hfi_ops->session_resume_drc(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - else if (hfi_ops->session_resume_drain) - ret = hfi_ops->session_resume_drain(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE; - } - - if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) - clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC; - - ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) - return ret; - - if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) - clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; - - ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) - return ret; - - return iris_inst_change_sub_state(inst, clear_sub_state, 0); + return iris_process_streamon_input(inst); } int iris_vdec_streamon_output(struct iris_inst *inst) @@ -496,7 +353,7 @@ int iris_vdec_streamon_output(struct iris_inst *inst) iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - ret = iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (ret) return ret; @@ -504,7 +361,7 @@ int iris_vdec_streamon_output(struct iris_inst *inst) if (ret) return ret; - ret = iris_vdec_process_streamon_output(inst); + ret = iris_process_streamon_output(inst); if (ret) goto error; @@ -515,49 +372,11 @@ int iris_vdec_streamon_output(struct iris_inst *inst) return ret; error: - iris_vdec_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); return ret; } -static int -iris_vdec_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); - - buf->type = iris_v4l2_type_to_driver(vb2->type); - buf->index = vb2->index; - buf->fd = vb2->planes[0].m.fd; - buf->buffer_size = vb2->planes[0].length; - buf->data_offset = vb2->planes[0].data_offset; - buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset; - buf->flags = vbuf->flags; - buf->timestamp = vb2->timestamp; - buf->attr = 0; - - return 0; -} - -static void -iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) -{ - u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - struct vb2_buffer *vb = &vbuf->vb2_buf; - u64 ts_us = vb->timestamp; - - if (inst->metadata_idx >= ARRAY_SIZE(inst->tss)) - inst->metadata_idx = 0; - - do_div(ts_us, NSEC_PER_USEC); - - inst->tss[inst->metadata_idx].flags = vbuf->flags & mask; - inst->tss[inst->metadata_idx].tc = vbuf->timecode; - inst->tss[inst->metadata_idx].ts_us = ts_us; - inst->tss[inst->metadata_idx].ts_ns = vb->timestamp; - - inst->metadata_idx++; -} - int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) { struct iris_buffer *buf = to_iris_buffer(vbuf); @@ -565,7 +384,7 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) struct vb2_queue *q; int ret; - ret = iris_vdec_vb2_buffer_to_driver(vb2, buf); + ret = iris_vb2_buffer_to_driver(vb2, buf); if (ret) return ret; |