diff options
Diffstat (limited to 'drivers/media/platform/qcom/iris')
41 files changed, 6473 insertions, 871 deletions
diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index e86d00ee6f15..13270cd6d899 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -1,5 +1,5 @@ -qcom-iris-objs += \ - iris_buffer.o \ +qcom-iris-objs += iris_buffer.o \ + iris_common.o \ iris_core.o \ iris_ctrls.o \ iris_firmware.o \ @@ -19,6 +19,7 @@ qcom-iris-objs += \ iris_vidc.o \ iris_vb2.o \ iris_vdec.o \ + iris_venc.o \ iris_vpu2.o \ iris_vpu3x.o \ iris_vpu_buffer.o \ diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index e5c5a564fcb8..c0900038e7de 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -63,7 +63,12 @@ static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst) { u32 y_plane, uv_plane, y_stride, uv_stride, y_scanlines, uv_scanlines; - struct v4l2_format *f = inst->fmt_dst; + struct v4l2_format *f; + + if (inst->domain == DECODER) + f = inst->fmt_dst; + else + f = inst->fmt_src; y_stride = ALIGN(f->fmt.pix_mp.width, Y_STRIDE_ALIGN); uv_stride = ALIGN(f->fmt.pix_mp.width, UV_STRIDE_ALIGN); @@ -194,7 +199,7 @@ static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane, PIXELS_4K); } -static u32 iris_bitstream_buffer_size(struct iris_inst *inst) +static u32 iris_dec_bitstream_buffer_size(struct iris_inst *inst) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; u32 base_res_mbs = NUM_MBS_4K; @@ -205,6 +210,9 @@ static u32 iris_bitstream_buffer_size(struct iris_inst *inst) if (num_mbs > NUM_MBS_4K) { div_factor = 4; base_res_mbs = caps->max_mbpf; + } else { + if (inst->codec == V4L2_PIX_FMT_VP9) + div_factor = 1; } /* @@ -216,18 +224,58 @@ static u32 iris_bitstream_buffer_size(struct iris_inst *inst) return ALIGN(frame_size, PIXELS_4K); } +static u32 iris_enc_bitstream_buffer_size(struct iris_inst *inst) +{ + u32 aligned_width, aligned_height, bitstream_size, yuv_size; + int bitrate_mode, frame_rc; + struct v4l2_format *f; + + f = inst->fmt_dst; + + bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + + aligned_width = ALIGN(f->fmt.pix_mp.width, 32); + aligned_height = ALIGN(f->fmt.pix_mp.height, 32); + bitstream_size = aligned_width * aligned_height * 3; + yuv_size = (aligned_width * aligned_height * 3) >> 1; + if (aligned_width * aligned_height > (4096 * 2176)) + /* bitstream_size = 0.25 * yuv_size; */ + bitstream_size = (bitstream_size >> 3); + else if (aligned_width * aligned_height > (1280 * 720)) + /* bitstream_size = 0.5 * yuv_size; */ + bitstream_size = (bitstream_size >> 2); + + if ((!frame_rc || bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) && + bitstream_size < yuv_size) + bitstream_size = (bitstream_size << 1); + + return ALIGN(bitstream_size, 4096); +} + int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - switch (buffer_type) { - case BUF_INPUT: - return iris_bitstream_buffer_size(inst); - case BUF_OUTPUT: - return iris_yuv_buffer_size_nv12(inst); - case BUF_DPB: - return iris_yuv_buffer_size_qc08c(inst); - default: - return 0; + if (inst->domain == DECODER) { + switch (buffer_type) { + case BUF_INPUT: + return iris_dec_bitstream_buffer_size(inst); + case BUF_OUTPUT: + return iris_yuv_buffer_size_nv12(inst); + case BUF_DPB: + return iris_yuv_buffer_size_qc08c(inst); + default: + return 0; + } + } else { + switch (buffer_type) { + case BUF_INPUT: + return iris_yuv_buffer_size_nv12(inst); + case BUF_OUTPUT: + return iris_enc_bitstream_buffer_size(inst); + default: + return 0; + } } } @@ -236,7 +284,7 @@ static void iris_fill_internal_buf_info(struct iris_inst *inst, { struct iris_buffers *buffers = &inst->buffers[buffer_type]; - buffers->size = iris_vpu_buf_size(inst, buffer_type); + buffers->size = inst->core->iris_platform_data->get_vpu_buffer_size(inst, buffer_type); buffers->min_count = iris_vpu_buf_count(inst, buffer_type); } @@ -246,16 +294,30 @@ void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) const u32 *internal_buf_type; u32 internal_buffer_count, i; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } } } @@ -296,12 +358,22 @@ int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) const u32 *internal_buf_type; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < internal_buffer_count; i++) { @@ -331,6 +403,29 @@ int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf) return 0; } +int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type) +{ + struct iris_buffer *buffer, *next; + struct iris_buffers *buffers; + int ret = 0; + + buffers = &inst->buffers[buffer_type]; + list_for_each_entry_safe(buffer, next, &buffers->list, list) { + if (buffer->attr & BUF_ATTR_PENDING_RELEASE) + continue; + if (buffer->attr & BUF_ATTR_QUEUED) + continue; + + if (buffer->attr & BUF_ATTR_DEFERRED) { + ret = iris_queue_buffer(inst, buffer); + if (ret) + return ret; + } + } + + return ret; +} + int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) { const struct iris_platform_data *platform_data = inst->core->iris_platform_data; @@ -340,12 +435,22 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) u32 internal_buffer_count, i; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < internal_buffer_count; i++) { @@ -355,6 +460,10 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) continue; if (buffer->attr & BUF_ATTR_QUEUED) continue; + if (buffer->type == BUF_DPB && inst->state != IRIS_INST_STREAMING) { + buffer->attr |= BUF_ATTR_DEFERRED; + continue; + } ret = iris_queue_buffer(inst, buffer); if (ret) return ret; @@ -376,7 +485,7 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf return 0; } -int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) +static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force) { const struct iris_platform_data *platform_data = inst->core->iris_platform_data; struct iris_buffer *buf, *next; @@ -385,17 +494,48 @@ int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) u32 i, len; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - len = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + len = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + len = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - len = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + len = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + len = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < len; i++) { buffers = &inst->buffers[internal_buf_type[i]]; list_for_each_entry_safe(buf, next, &buffers->list, list) { + /* + * during stream on, skip destroying internal(DPB) buffer + * if firmware did not return it. + * during close, destroy all buffers irrespectively. + */ + if (!force && buf->attr & BUF_ATTR_QUEUED) + continue; + + ret = iris_destroy_internal_buffer(inst, buf); + if (ret) + return ret; + } + } + + if (force) { + if (inst->domain == DECODER) + buffers = &inst->buffers[BUF_PERSIST]; + else + buffers = &inst->buffers[BUF_ARP]; + + list_for_each_entry_safe(buf, next, &buffers->list, list) { ret = iris_destroy_internal_buffer(inst, buf); if (ret) return ret; @@ -405,6 +545,16 @@ int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) return 0; } +int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane) +{ + return iris_destroy_internal_buffers(inst, plane, true); +} + +int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane) +{ + return iris_destroy_internal_buffers(inst, plane, false); +} + static int iris_release_internal_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type) { @@ -434,8 +584,13 @@ static int iris_release_input_internal_buffers(struct iris_inst *inst) u32 internal_buffer_count, i; int ret; - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } for (i = 0; i < internal_buffer_count; i++) { ret = iris_release_internal_buffers(inst, internal_buf_type[i]); @@ -446,9 +601,9 @@ static int iris_release_input_internal_buffers(struct iris_inst *inst) return 0; } -int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) +int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - struct iris_buffers *buffers = &inst->buffers[BUF_PERSIST]; + struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_buffer *buffer, *next; int ret; u32 i; @@ -456,10 +611,10 @@ int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) if (!list_empty(&buffers->list)) return 0; - iris_fill_internal_buf_info(inst, BUF_PERSIST); + iris_fill_internal_buf_info(inst, buffer_type); for (i = 0; i < buffers->min_count; i++) { - ret = iris_create_internal_buffer(inst, BUF_PERSIST, i); + ret = iris_create_internal_buffer(inst, buffer_type, i); if (ret) return ret; } @@ -593,13 +748,16 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) vb2 = &vbuf->vb2_buf; - if (buf->flags & V4L2_BUF_FLAG_ERROR) - state = VB2_BUF_STATE_ERROR; - else - state = VB2_BUF_STATE_DONE; - vbuf->flags |= buf->flags; + if (buf->flags & V4L2_BUF_FLAG_ERROR) { + state = VB2_BUF_STATE_ERROR; + vb2_set_plane_payload(vb2, 0, 0); + vb2->timestamp = 0; + v4l2_m2m_buf_done(vbuf, state); + return 0; + } + if (V4L2_TYPE_IS_CAPTURE(type)) { vb2_set_plane_payload(vb2, 0, buf->data_size); vbuf->sequence = inst->sequence_cap++; @@ -615,7 +773,10 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) v4l2_event_queue_fh(&inst->fh, &ev); v4l2_m2m_mark_stopped(m2m_ctx); } + inst->last_buffer_dequeued = true; } + + state = VB2_BUF_STATE_DONE; vb2->timestamp = buf->timestamp; v4l2_m2m_buf_done(vbuf, state); diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h index c36b6347b077..325d30fce5c9 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_buffer.h @@ -25,6 +25,8 @@ struct iris_inst; * @BUF_DPB: buffer to store display picture buffers for reference * @BUF_PERSIST: buffer to store session context data * @BUF_SCRATCH_1: buffer to store decoding/encoding context data for HW + * @BUF_SCRATCH_2: buffer to store encoding context data for HW + * @BUF_VPSS: buffer to store VPSS context data for HW * @BUF_TYPE_MAX: max buffer types */ enum iris_buffer_type { @@ -38,6 +40,8 @@ enum iris_buffer_type { BUF_DPB, BUF_PERSIST, BUF_SCRATCH_1, + BUF_SCRATCH_2, + BUF_VPSS, BUF_TYPE_MAX, }; @@ -105,9 +109,11 @@ int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_ty void iris_get_internal_buffers(struct iris_inst *inst, u32 plane); int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); +int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); -int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane); -int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst); +int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane); +int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane); +int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buf_type); int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst); int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf); int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type); diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c new file mode 100644 index 000000000000..9fc663bdaf3f --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_common.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <media/v4l2-mem2mem.h> + +#include "iris_common.h" +#include "iris_ctrls.h" +#include "iris_instance.h" +#include "iris_power.h" + +int iris_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; +} + +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_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->domain == DECODER && + (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; + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, 0, set_sub_state); +} + +int iris_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->domain == DECODER && 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; + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, clear_sub_state, 0); +} + +static void iris_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_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_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; + 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; + + ret = iris_inst_state_change_streamoff(inst, plane); + if (ret) + goto error; + + iris_flush_deferred_buffers(inst, buffer_type); + + return 0; + +error: + iris_kill_session(inst); + iris_flush_deferred_buffers(inst, buffer_type); + + return ret; +} diff --git a/drivers/media/platform/qcom/iris/iris_common.h b/drivers/media/platform/qcom/iris/iris_common.h new file mode 100644 index 000000000000..b2a27b781c9a --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_COMMON_H__ +#define __IRIS_COMMON_H__ + +struct iris_inst; +struct iris_buffer; + +int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf); +void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); +int iris_process_streamon_input(struct iris_inst *inst); +int iris_process_streamon_output(struct iris_inst *inst); +int iris_session_streamoff(struct iris_inst *inst, u32 plane); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 0fa0a3b549a2..8406c48d635b 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -15,10 +15,12 @@ void iris_core_deinit(struct iris_core *core) pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); - iris_fw_unload(core); - iris_vpu_power_off(core); - iris_hfi_queues_deinit(core); - core->state = IRIS_CORE_DEINIT; + if (core->state != IRIS_CORE_DEINIT) { + iris_fw_unload(core); + iris_vpu_power_off(core); + iris_hfi_queues_deinit(core); + core->state = IRIS_CORE_DEINIT; + } mutex_unlock(&core->lock); pm_runtime_put_sync(core->dev); diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index aeeac32a1f6d..fb194c967ad4 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -25,6 +25,11 @@ struct icc_info { #define IRIS_FW_VERSION_LENGTH 128 #define IFACEQ_CORE_PKT_SIZE (1024 * 4) +enum domain_type { + ENCODER = BIT(0), + DECODER = BIT(1), +}; + /** * struct iris_core - holds core parameters valid for all instances * @@ -33,8 +38,10 @@ struct icc_info { * @irq: iris irq * @v4l2_dev: a holder for v4l2 device structure * @vdev_dec: iris video device structure for decoder + * @vdev_enc: iris video device structure for encoder * @iris_v4l2_file_ops: iris v4l2 file ops - * @iris_v4l2_ioctl_ops: iris v4l2 ioctl ops + * @iris_v4l2_ioctl_ops_dec: iris v4l2 ioctl ops for decoder + * @iris_v4l2_ioctl_ops_enc: iris v4l2 ioctl ops for encoder * @iris_vb2_ops: iris vb2 ops * @icc_tbl: table of iris interconnects * @icc_count: count of iris interconnects @@ -64,7 +71,8 @@ struct icc_info { * @intr_status: interrupt status * @sys_error_handler: a delayed work for handling system fatal error * @instances: a list_head of all instances - * @inst_fw_caps: an array of supported instance capabilities + * @inst_fw_caps_dec: an array of supported instance capabilities by decoder + * @inst_fw_caps_enc: an array of supported instance capabilities by encoder */ struct iris_core { @@ -73,8 +81,10 @@ struct iris_core { int irq; struct v4l2_device v4l2_dev; struct video_device *vdev_dec; + struct video_device *vdev_enc; const struct v4l2_file_operations *iris_v4l2_file_ops; - const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops; + const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_dec; + const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_enc; const struct vb2_ops *iris_vb2_ops; struct icc_bulk_data *icc_tbl; u32 icc_count; @@ -104,7 +114,9 @@ struct iris_core { u32 intr_status; struct delayed_work sys_error_handler; struct list_head instances; - struct platform_inst_fw_cap inst_fw_caps[INST_FW_CAP_MAX]; + /* encoder and decoder have overlapping caps, so two different arrays are required */ + struct platform_inst_fw_cap inst_fw_caps_dec[INST_FW_CAP_MAX]; + struct platform_inst_fw_cap inst_fw_caps_enc[INST_FW_CAP_MAX]; }; int iris_core_init(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index b690578256d5..754a5ad718bc 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -7,8 +7,13 @@ #include <media/v4l2-mem2mem.h> #include "iris_ctrls.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_hfi_gen2_defines.h" #include "iris_instance.h" +#define CABAC_MAX_BITRATE 160000000 +#define CAVLC_MAX_BITRATE 220000000 + static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) { return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; @@ -17,12 +22,82 @@ static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) { switch (id) { - case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: - return DEBLOCK; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - return PROFILE; + return PROFILE_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + return PROFILE_HEVC; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + return PROFILE_VP9; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - return LEVEL; + return LEVEL_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + return LEVEL_HEVC; + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: + return LEVEL_VP9; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + return TIER; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + return HEADER_MODE; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + return PREPEND_SPSPPS_TO_IDR; + case V4L2_CID_MPEG_VIDEO_BITRATE: + return BITRATE; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + return BITRATE_PEAK; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return BITRATE_MODE; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + return FRAME_SKIP_MODE; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + return FRAME_RC_ENABLE; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return GOP_SIZE; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + return ENTROPY_MODE; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + return MIN_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + return MIN_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + return MAX_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + return MAX_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: + return I_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: + return I_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: + return P_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: + return P_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: + return B_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: + return B_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: + return I_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: + return I_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: + return P_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: + return P_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: + return B_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: + return B_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + return I_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + return I_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + return P_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + return P_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: + return B_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + return B_FRAME_QP_HEVC; default: return INST_FW_CAP_MAX; } @@ -34,18 +109,88 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return 0; switch (cap_id) { - case DEBLOCK: - return V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER; - case PROFILE: + case PROFILE_H264: return V4L2_CID_MPEG_VIDEO_H264_PROFILE; - case LEVEL: + case PROFILE_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_PROFILE; + case PROFILE_VP9: + return V4L2_CID_MPEG_VIDEO_VP9_PROFILE; + case LEVEL_H264: return V4L2_CID_MPEG_VIDEO_H264_LEVEL; + case LEVEL_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_LEVEL; + case LEVEL_VP9: + return V4L2_CID_MPEG_VIDEO_VP9_LEVEL; + case TIER: + return V4L2_CID_MPEG_VIDEO_HEVC_TIER; + case HEADER_MODE: + return V4L2_CID_MPEG_VIDEO_HEADER_MODE; + case PREPEND_SPSPPS_TO_IDR: + return V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR; + case BITRATE: + return V4L2_CID_MPEG_VIDEO_BITRATE; + case BITRATE_PEAK: + return V4L2_CID_MPEG_VIDEO_BITRATE_PEAK; + case BITRATE_MODE: + return V4L2_CID_MPEG_VIDEO_BITRATE_MODE; + case FRAME_SKIP_MODE: + return V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE; + case FRAME_RC_ENABLE: + return V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE; + case GOP_SIZE: + return V4L2_CID_MPEG_VIDEO_GOP_SIZE; + case ENTROPY_MODE: + return V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + case MIN_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_MIN_QP; + case MIN_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP; + case MAX_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_MAX_QP; + case MAX_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP; + case I_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP; + case I_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP; + case P_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP; + case P_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP; + case B_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP; + case B_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP; + case I_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP; + case I_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP; + case P_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP; + case P_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP; + case B_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP; + case B_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP; + case I_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP; + case I_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP; + case P_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP; + case P_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP; + case B_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP; + case B_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP; default: return 0; } } -static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) +static int iris_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); enum platform_inst_fw_cap_type cap_id; @@ -66,11 +211,16 @@ static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) inst->fw_caps[cap_id].value = ctrl->val; + if (vb2_is_streaming(q)) { + if (cap[cap_id].set) + cap[cap_id].set(inst, cap_id); + } + return 0; } static const struct v4l2_ctrl_ops iris_ctrl_ops = { - .s_ctrl = iris_vdec_op_s_ctrl, + .s_ctrl = iris_op_s_ctrl, }; int iris_ctrls_init(struct iris_inst *inst) @@ -84,10 +234,11 @@ int iris_ctrls_init(struct iris_inst *inst) if (iris_get_v4l2_id(cap[idx].cap_id)) num_ctrls++; } - if (!num_ctrls) - return -EINVAL; - /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ + /* Adding 1 to num_ctrls to include + * V4L2_CID_MIN_BUFFERS_FOR_CAPTURE for decoder and + * V4L2_CID_MIN_BUFFERS_FOR_OUTPUT for encoder + */ ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); if (ret) @@ -129,8 +280,13 @@ int iris_ctrls_init(struct iris_inst *inst) ctrl_idx++; } - v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + if (inst->domain == DECODER) { + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + } else { + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 4); + } ret = inst->ctrl_handler.error; if (ret) @@ -148,31 +304,57 @@ void iris_session_init_caps(struct iris_core *core) struct platform_inst_fw_cap *caps; u32 i, num_cap, cap_id; - caps = core->iris_platform_data->inst_fw_caps; - num_cap = core->iris_platform_data->inst_fw_caps_size; + caps = core->iris_platform_data->inst_fw_caps_dec; + num_cap = core->iris_platform_data->inst_fw_caps_dec_size; for (i = 0; i < num_cap; i++) { cap_id = caps[i].cap_id; if (!iris_valid_cap_id(cap_id)) continue; - core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; - core->inst_fw_caps[cap_id].min = caps[i].min; - core->inst_fw_caps[cap_id].max = caps[i].max; - core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; - core->inst_fw_caps[cap_id].value = caps[i].value; - core->inst_fw_caps[cap_id].flags = caps[i].flags; - core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; + core->inst_fw_caps_dec[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps_dec[cap_id].min = caps[i].min; + core->inst_fw_caps_dec[cap_id].max = caps[i].max; + core->inst_fw_caps_dec[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps_dec[cap_id].value = caps[i].value; + core->inst_fw_caps_dec[cap_id].flags = caps[i].flags; + core->inst_fw_caps_dec[cap_id].hfi_id = caps[i].hfi_id; + core->inst_fw_caps_dec[cap_id].set = caps[i].set; + } + + caps = core->iris_platform_data->inst_fw_caps_enc; + num_cap = core->iris_platform_data->inst_fw_caps_enc_size; + + for (i = 0; i < num_cap; i++) { + cap_id = caps[i].cap_id; + if (!iris_valid_cap_id(cap_id)) + continue; + + core->inst_fw_caps_enc[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps_enc[cap_id].min = caps[i].min; + core->inst_fw_caps_enc[cap_id].max = caps[i].max; + core->inst_fw_caps_enc[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps_enc[cap_id].value = caps[i].value; + core->inst_fw_caps_enc[cap_id].flags = caps[i].flags; + core->inst_fw_caps_enc[cap_id].hfi_id = caps[i].hfi_id; + core->inst_fw_caps_enc[cap_id].set = caps[i].set; } } static u32 iris_get_port_info(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) - return HFI_PORT_BITSTREAM; - else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) - return HFI_PORT_RAW; + if (inst->domain == DECODER) { + if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) + return HFI_PORT_BITSTREAM; + else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) + return HFI_PORT_RAW; + } else { + if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) + return HFI_PORT_RAW; + else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) + return HFI_PORT_BITSTREAM; + } return HFI_PORT_NONE; } @@ -212,8 +394,10 @@ int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id u32 width = inp_f->fmt.pix_mp.width; u32 work_mode = STAGE_2; - if (iris_res_is_less_than(width, height, 1280, 720)) - work_mode = STAGE_1; + if (inst->domain == DECODER) { + if (iris_res_is_less_than(width, height, 1280, 720)) + work_mode = STAGE_1; + } return hfi_ops->session_set_property(inst, hfi_id, HFI_HOST_FLAGS_NONE, @@ -235,6 +419,470 @@ int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) &work_route, sizeof(u32)); } +int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id, hfi_value; + + if (inst->codec == V4L2_PIX_FMT_H264) { + hfi_id = inst->fw_caps[PROFILE_H264].hfi_id; + hfi_value = inst->fw_caps[PROFILE_H264].value; + } else { + hfi_id = inst->fw_caps[PROFILE_HEVC].hfi_id; + hfi_value = inst->fw_caps[PROFILE_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32)); +} + +int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id, hfi_value; + + if (inst->codec == V4L2_PIX_FMT_H264) { + hfi_id = inst->fw_caps[LEVEL_H264].hfi_id; + hfi_value = inst->fw_caps[LEVEL_H264].value; + } else { + hfi_id = inst->fw_caps[LEVEL_HEVC].hfi_id; + hfi_value = inst->fw_caps[LEVEL_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32)); +} + +int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + struct hfi_profile_level pl; + + if (inst->codec == V4L2_PIX_FMT_H264) { + pl.profile = inst->fw_caps[PROFILE_H264].value; + pl.level = inst->fw_caps[LEVEL_H264].value; + } else { + pl.profile = inst->fw_caps[PROFILE_HEVC].value; + pl.level = inst->fw_caps[LEVEL_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &pl, sizeof(u32)); +} + +int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 header_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) + hfi_val = 0; + else + hfi_val = 1; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &hfi_val, sizeof(u32)); +} + +int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 prepend_sps_pps = inst->fw_caps[PREPEND_SPSPPS_TO_IDR].value; + u32 header_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (prepend_sps_pps) + hfi_val = HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME; + else if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) + hfi_val = HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME; + else + hfi_val = HFI_SEQ_HEADER_SEPERATE_FRAME; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_val, sizeof(u32)); +} + +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[ENTROPY_MODE].value; + u32 bitrate = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 max_bitrate; + + if (inst->codec == V4L2_PIX_FMT_HEVC) + max_bitrate = CABAC_MAX_BITRATE; + + if (entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + max_bitrate = CABAC_MAX_BITRATE; + else + max_bitrate = CAVLC_MAX_BITRATE; + + bitrate = min(bitrate, max_bitrate); + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &bitrate, sizeof(u32)); +} + +int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 rc_mode = inst->fw_caps[BITRATE_MODE].value; + u32 peak_bitrate = inst->fw_caps[cap_id].value; + u32 bitrate = inst->fw_caps[BITRATE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + + if (rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + return 0; + + if (inst->fw_caps[cap_id].flags & CAP_FLAG_CLIENT_SET) { + if (peak_bitrate < bitrate) + peak_bitrate = bitrate; + } else { + peak_bitrate = bitrate; + } + + inst->fw_caps[cap_id].value = peak_bitrate; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &peak_bitrate, sizeof(u32)); +} + +int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 rc_mode = 0; + + if (!frame_rc) + rc_mode = HFI_RATE_CONTROL_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + rc_mode = frame_skip ? HFI_RATE_CONTROL_VBR_VFR : HFI_RATE_CONTROL_VBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + rc_mode = frame_skip ? HFI_RATE_CONTROL_CBR_VFR : HFI_RATE_CONTROL_CBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + rc_mode = HFI_RATE_CONTROL_CQ; + + inst->hfi_rc_type = rc_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &rc_mode, sizeof(u32)); +} + +int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 rc_mode = 0; + + if (!frame_rc) + rc_mode = HFI_RC_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + rc_mode = HFI_RC_VBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + rc_mode = frame_skip ? HFI_RC_CBR_VFR : HFI_RC_CBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + rc_mode = HFI_RC_CQ; + + inst->hfi_rc_type = rc_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &rc_mode, sizeof(u32)); +} + +int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec != V4L2_PIX_FMT_H264) + return 0; + + hfi_val = (entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) ? + HFI_H264_ENTROPY_CAVLC : HFI_H264_ENTROPY_CABAC; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &hfi_val, sizeof(u32)); +} + +int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 profile; + + if (inst->codec != V4L2_PIX_FMT_H264) + return 0; + + profile = inst->fw_caps[PROFILE_H264].value; + + if (profile == V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE || + profile == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) + entropy_mode = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + + inst->fw_caps[cap_id].value = entropy_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &entropy_mode, sizeof(u32)); +} + +int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0; + u32 min_qp_enable = 0, client_qp_enable = 0; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[MIN_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + min_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[I_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[P_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[B_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } else { + if (inst->fw_caps[MIN_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + min_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[I_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[P_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[B_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = max(inst->fw_caps[I_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + p_frame_qp = max(inst->fw_caps[P_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + b_frame_qp = max(inst->fw_caps[B_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + } else { + i_frame_qp = max(inst->fw_caps[I_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + p_frame_qp = max(inst->fw_caps[P_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + b_frame_qp = max(inst->fw_caps[B_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 max_qp_enable = 0, client_qp_enable; + u32 i_frame_qp, p_frame_qp, b_frame_qp; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[MAX_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + max_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[I_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[P_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[B_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } else { + if (inst->fw_caps[MAX_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + max_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[I_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[P_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[B_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = min(inst->fw_caps[I_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + p_frame_qp = min(inst->fw_caps[P_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + b_frame_qp = min(inst->fw_caps[B_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + } else { + i_frame_qp = min(inst->fw_caps[I_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + p_frame_qp = min(inst->fw_caps[P_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + b_frame_qp = min(inst->fw_caps[B_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0, client_qp_enable; + u32 i_frame_qp, p_frame_qp, b_frame_qp; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + struct vb2_queue *q; + u32 hfi_val; + + q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + if (vb2_is_streaming(q)) { + if (inst->hfi_rc_type != HFI_RC_OFF) + return 0; + } + + if (inst->hfi_rc_type == HFI_RC_OFF) { + i_qp_enable = 1; + p_qp_enable = 1; + b_qp_enable = 1; + } else { + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[I_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + i_qp_enable = 1; + if (inst->fw_caps[P_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + p_qp_enable = 1; + if (inst->fw_caps[B_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + b_qp_enable = 1; + } else { + if (inst->fw_caps[I_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + i_qp_enable = 1; + if (inst->fw_caps[P_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + p_qp_enable = 1; + if (inst->fw_caps[B_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + b_qp_enable = 1; + } + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = inst->fw_caps[I_FRAME_QP_H264].value; + p_frame_qp = inst->fw_caps[P_FRAME_QP_H264].value; + b_frame_qp = inst->fw_caps[B_FRAME_QP_H264].value; + } else { + i_frame_qp = inst->fw_caps[I_FRAME_QP_HEVC].value; + p_frame_qp = inst->fw_caps[P_FRAME_QP_HEVC].value; + b_frame_qp = inst->fw_caps[B_FRAME_QP_HEVC].value; + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + struct hfi_quantization_range_v2 range; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + range.min_qp.qp_packed = inst->fw_caps[MIN_FRAME_QP_HEVC].value; + range.max_qp.qp_packed = inst->fw_caps[MAX_FRAME_QP_HEVC].value; + } else { + range.min_qp.qp_packed = inst->fw_caps[MIN_FRAME_QP_H264].value; + range.max_qp.qp_packed = inst->fw_caps[MAX_FRAME_QP_H264].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &range, sizeof(range)); +} + int iris_set_properties(struct iris_inst *inst, u32 plane) { const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 9b5741868933..30af333cc494 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -17,6 +17,21 @@ int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index f1b5cd56db32..9ab499fad946 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -60,16 +60,7 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) ret = qcom_mdt_load(dev, firmware, fw_name, pas_id, mem_virt, mem_phys, res_size, NULL); - if (ret) - goto err_mem_unmap; - - ret = qcom_scm_pas_auth_and_reset(pas_id); - if (ret) - goto err_mem_unmap; - - return ret; -err_mem_unmap: memunmap(mem_virt); err_release_fw: release_firmware(firmware); @@ -94,6 +85,12 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; } + ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id); + if (ret) { + dev_err(core->dev, "auth and reset failed: %d\n", ret); + return ret; + } + ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, cp_config->cp_size, cp_config->cp_nonpixel_start, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h index b2c541367fc6..b51471fb32c7 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h @@ -102,7 +102,7 @@ enum hfi_matrix_coefficients { struct iris_hfi_prop_type_handle { u32 type; - int (*handle)(struct iris_inst *inst); + int (*handle)(struct iris_inst *inst, u32 plane); }; struct iris_hfi_command_ops { @@ -140,6 +140,7 @@ struct hfi_subscription_params { u32 color_info; u32 profile; u32 level; + u32 tier; }; u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 64f887d9a17d..e1788c266bb1 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -21,6 +21,10 @@ static u32 iris_hfi_gen1_buf_type_from_driver(enum iris_buffer_type buffer_type) return HFI_BUFFER_INTERNAL_SCRATCH; case BUF_SCRATCH_1: return HFI_BUFFER_INTERNAL_SCRATCH_1; + case BUF_SCRATCH_2: + return HFI_BUFFER_INTERNAL_SCRATCH_2; + case BUF_ARP: + return HFI_BUFFER_INTERNAL_PERSIST; default: return -EINVAL; } @@ -88,16 +92,34 @@ static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) static int iris_hfi_gen1_session_open(struct iris_inst *inst) { struct hfi_session_open_pkt packet; + u32 codec = 0; int ret; if (inst->state != IRIS_INST_DEINIT) return -EALREADY; + switch (inst->codec) { + case V4L2_PIX_FMT_H264: + codec = HFI_VIDEO_CODEC_H264; + break; + case V4L2_PIX_FMT_HEVC: + codec = HFI_VIDEO_CODEC_HEVC; + break; + case V4L2_PIX_FMT_VP9: + codec = HFI_VIDEO_CODEC_VP9; + break; + } + packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; packet.shdr.session_id = inst->session_id; - packet.session_domain = HFI_SESSION_TYPE_DEC; - packet.session_codec = HFI_VIDEO_CODEC_H264; + + if (inst->domain == DECODER) + packet.session_domain = HFI_SESSION_TYPE_DEC; + else + packet.session_domain = HFI_SESSION_TYPE_ENC; + + packet.session_codec = codec; reinit_completion(&inst->completion); @@ -171,45 +193,70 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) u32 flush_type = 0; int ret = 0; - if ((V4L2_TYPE_IS_OUTPUT(plane) && - inst->state == IRIS_INST_INPUT_STREAMING) || - (V4L2_TYPE_IS_CAPTURE(plane) && - inst->state == IRIS_INST_OUTPUT_STREAMING) || - inst->state == IRIS_INST_ERROR) { - reinit_completion(&inst->completion); - iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); - ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); - if (!ret) - ret = iris_wait_for_session_response(inst, false); - - reinit_completion(&inst->completion); - iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_RELEASE_RESOURCES); - ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); - if (!ret) - ret = iris_wait_for_session_response(inst, false); - - iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + if (inst->domain == DECODER) { + if (inst->state == IRIS_INST_STREAMING) { + if (V4L2_TYPE_IS_OUTPUT(plane)) + flush_type = HFI_FLUSH_ALL; + else if (V4L2_TYPE_IS_CAPTURE(plane)) + flush_type = HFI_FLUSH_OUTPUT; + + reinit_completion(&inst->flush_completion); + + flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); + flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; + flush_pkt.shdr.session_id = inst->session_id; + flush_pkt.flush_type = flush_type; + + ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); + if (!ret) { + inst->flush_responses_pending++; + ret = iris_wait_for_session_response(inst, true); + } + } else if (inst->sub_state & IRIS_INST_SUB_LOAD_RESOURCES) { + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, + HFI_CMD_SESSION_RELEASE_RESOURCES); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + + iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + VB2_BUF_STATE_ERROR); + iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + VB2_BUF_STATE_ERROR); + } + } else { + if (inst->state == IRIS_INST_STREAMING || + inst->state == IRIS_INST_INPUT_STREAMING || + inst->state == IRIS_INST_ERROR) { + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, + HFI_CMD_SESSION_RELEASE_RESOURCES); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + } iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, VB2_BUF_STATE_ERROR); iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, VB2_BUF_STATE_ERROR); - } else if (inst->state == IRIS_INST_STREAMING) { - if (V4L2_TYPE_IS_OUTPUT(plane)) - flush_type = HFI_FLUSH_ALL; - else if (V4L2_TYPE_IS_CAPTURE(plane)) - flush_type = HFI_FLUSH_OUTPUT; - - reinit_completion(&inst->flush_completion); - - flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); - flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; - flush_pkt.shdr.session_id = inst->session_id; - flush_pkt.flush_type = flush_type; - - ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); - if (!ret) - ret = iris_wait_for_session_response(inst, true); } return ret; @@ -226,23 +273,44 @@ static int iris_hfi_gen1_session_continue(struct iris_inst *inst, u32 plane) static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_buffer *buf) { - struct hfi_session_empty_buffer_compressed_pkt ip_pkt; - - ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); - ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; - ip_pkt.shdr.session_id = inst->session_id; - ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); - ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); - ip_pkt.flags = buf->flags; - ip_pkt.mark_target = 0; - ip_pkt.mark_data = 0; - ip_pkt.offset = buf->data_offset; - ip_pkt.alloc_len = buf->buffer_size; - ip_pkt.filled_len = buf->data_size; - ip_pkt.input_tag = buf->index; - ip_pkt.packet_buffer = buf->device_addr; - - return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + struct hfi_session_empty_buffer_compressed_pkt com_ip_pkt; + struct hfi_session_empty_buffer_uncompressed_pkt uncom_ip_pkt; + + if (inst->domain == DECODER) { + com_ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); + com_ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + com_ip_pkt.shdr.session_id = inst->session_id; + com_ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); + com_ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); + com_ip_pkt.flags = buf->flags; + com_ip_pkt.mark_target = 0; + com_ip_pkt.mark_data = 0; + com_ip_pkt.offset = buf->data_offset; + com_ip_pkt.alloc_len = buf->buffer_size; + com_ip_pkt.filled_len = buf->data_size; + com_ip_pkt.input_tag = buf->index; + com_ip_pkt.packet_buffer = buf->device_addr; + return iris_hfi_queue_cmd_write(inst->core, &com_ip_pkt, + com_ip_pkt.shdr.hdr.size); + } else { + uncom_ip_pkt.shdr.hdr.size = + sizeof(struct hfi_session_empty_buffer_uncompressed_pkt); + uncom_ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + uncom_ip_pkt.shdr.session_id = inst->session_id; + uncom_ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); + uncom_ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); + uncom_ip_pkt.view_id = 0; + uncom_ip_pkt.flags = buf->flags; + uncom_ip_pkt.mark_target = 0; + uncom_ip_pkt.mark_data = 0; + uncom_ip_pkt.offset = buf->data_offset; + uncom_ip_pkt.alloc_len = buf->buffer_size; + uncom_ip_pkt.filled_len = buf->data_size; + uncom_ip_pkt.input_tag = buf->index; + uncom_ip_pkt.packet_buffer = buf->device_addr; + return iris_hfi_queue_cmd_write(inst->core, &uncom_ip_pkt, + uncom_ip_pkt.shdr.hdr.size); + } } static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf) @@ -315,6 +383,8 @@ static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iri case BUF_PERSIST: case BUF_BIN: case BUF_SCRATCH_1: + case BUF_SCRATCH_2: + case BUF_ARP: return iris_hfi_gen1_queue_internal_buffer(inst, buf); default: return -EINVAL; @@ -380,14 +450,31 @@ exit: static int iris_hfi_gen1_session_drain(struct iris_inst *inst, u32 plane) { - struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0}; + if (inst->domain == DECODER) { + struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0}; + + ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); + ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + ip_pkt.shdr.session_id = inst->session_id; + ip_pkt.flags = HFI_BUFFERFLAG_EOS; + ip_pkt.packet_buffer = 0xdeadb000; + + return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + } + + if (inst->domain == ENCODER) { + struct hfi_session_empty_buffer_uncompressed_pkt ip_pkt = {0}; - ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); - ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; - ip_pkt.shdr.session_id = inst->session_id; - ip_pkt.flags = HFI_BUFFERFLAG_EOS; + ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_uncompressed_pkt); + ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + ip_pkt.shdr.session_id = inst->session_id; + ip_pkt.flags = HFI_BUFFERFLAG_EOS; + ip_pkt.packet_buffer = 0xdeadb000; - return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + } + + return -EINVAL; } static int @@ -490,7 +577,23 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); break; } - case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: { + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: { + struct hfi_profile_level *in = pdata, *pl = prop_data; + + pl->level = in->level; + pl->profile = in->profile; + if (pl->profile <= 0) + /* Profile not supported, falling back to high */ + pl->profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + + if (!pl->level) + /* Level not supported, falling back to 1 */ + pl->level = 1; + + packet->shdr.hdr.size += sizeof(u32) + sizeof(*pl); + break; + } + case HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER: { struct hfi_enable *en = prop_data; u32 *in = pdata; @@ -498,6 +601,90 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p packet->shdr.hdr.size += sizeof(u32) + sizeof(*en); break; } + case HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE: { + struct hfi_bitrate *brate = prop_data; + u32 *in = pdata; + + brate->bitrate = *in; + brate->layer_id = 0; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*brate); + break; + } + case HFI_PROPERTY_PARAM_VENC_RATE_CONTROL: { + u32 *in = pdata; + + switch (*in) { + case HFI_RATE_CONTROL_OFF: + case HFI_RATE_CONTROL_CBR_CFR: + case HFI_RATE_CONTROL_CBR_VFR: + case HFI_RATE_CONTROL_VBR_CFR: + case HFI_RATE_CONTROL_VBR_VFR: + case HFI_RATE_CONTROL_CQ: + break; + default: + return -EINVAL; + } + + packet->data[1] = *in; + packet->shdr.hdr.size += sizeof(u32) * 2; + break; + } + case HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL: { + struct hfi_h264_entropy_control *entropy = prop_data; + u32 *in = pdata; + + entropy->entropy_mode = *in; + if (entropy->entropy_mode == HFI_H264_ENTROPY_CABAC) + entropy->cabac_model = HFI_H264_CABAC_MODEL_0; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*entropy); + break; + } + case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2: { + struct hfi_quantization_range_v2 *range = prop_data; + struct hfi_quantization_range_v2 *in = pdata; + u32 min_qp, max_qp; + + min_qp = in->min_qp.qp_packed; + max_qp = in->max_qp.qp_packed; + + /* We'll be packing in the qp, so make sure we + * won't be losing data when masking + */ + if (min_qp > 0xff || max_qp > 0xff) + return -ERANGE; + + range->min_qp.layer_id = 0xFF; + range->max_qp.layer_id = 0xFF; + range->min_qp.qp_packed = (min_qp & 0xFF) | ((min_qp & 0xFF) << 8) | + ((min_qp & 0xFF) << 16); + range->max_qp.qp_packed = (max_qp & 0xFF) | ((max_qp & 0xFF) << 8) | + ((max_qp & 0xFF) << 16); + range->min_qp.enable = 7; + range->max_qp.enable = 7; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*range); + break; + } + case HFI_PROPERTY_CONFIG_FRAME_RATE: { + struct hfi_framerate *frate = prop_data; + struct hfi_framerate *in = pdata; + + frate->buffer_type = in->buffer_type; + frate->framerate = in->framerate; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*frate); + break; + } + case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: { + struct hfi_uncompressed_plane_actual_info *plane_actual_info = prop_data; + struct hfi_uncompressed_plane_actual_info *in = pdata; + + plane_actual_info->buffer_type = in->buffer_type; + plane_actual_info->num_planes = in->num_planes; + plane_actual_info->plane_format[0] = in->plane_format[0]; + if (in->num_planes > 1) + plane_actual_info->plane_format[1] = in->plane_format[1]; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*plane_actual_info); + break; + } default: return -EINVAL; } @@ -540,28 +727,33 @@ static int iris_hfi_gen1_session_set_property(struct iris_inst *inst, u32 packet return hfi_gen1_set_property(inst, packet_type, payload, payload_size); } -static int iris_hfi_gen1_set_resolution(struct iris_inst *inst) +static int iris_hfi_gen1_set_resolution(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE; struct hfi_framesize fs; int ret; - fs.buffer_type = HFI_BUFFER_INPUT; - fs.width = inst->fmt_src->fmt.pix_mp.width; - fs.height = inst->fmt_src->fmt.pix_mp.height; + if (!iris_drc_pending(inst)) { + fs.buffer_type = HFI_BUFFER_INPUT; + fs.width = inst->fmt_src->fmt.pix_mp.width; + fs.height = inst->fmt_src->fmt.pix_mp.height; - ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); - if (ret) - return ret; + ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); + if (ret) + return ret; + } + if (inst->domain == DECODER) + fs.buffer_type = HFI_BUFFER_OUTPUT2; + else + fs.buffer_type = HFI_BUFFER_OUTPUT; - fs.buffer_type = HFI_BUFFER_OUTPUT2; fs.width = inst->fmt_dst->fmt.pix_mp.width; fs.height = inst->fmt_dst->fmt.pix_mp.height; return hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); } -static int iris_hfi_gen1_decide_core(struct iris_inst *inst) +static int iris_hfi_gen1_decide_core(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; struct hfi_videocores_usage_type cu; @@ -571,36 +763,45 @@ static int iris_hfi_gen1_decide_core(struct iris_inst *inst) return hfi_gen1_set_property(inst, ptype, &cu, sizeof(cu)); } -static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst) +static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT; - u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; struct hfi_uncompressed_format_select fmt; + u32 pixelformat; int ret; - if (iris_split_mode_enabled(inst)) { - fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12_UBWC : 0; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + if (iris_split_mode_enabled(inst)) { + fmt.buffer_type = HFI_BUFFER_OUTPUT; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12_UBWC : 0; - ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); - if (ret) - return ret; + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + if (ret) + return ret; - fmt.buffer_type = HFI_BUFFER_OUTPUT2; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + fmt.buffer_type = HFI_BUFFER_OUTPUT2; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; - ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + } else { + fmt.buffer_type = HFI_BUFFER_OUTPUT; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + } } else { - fmt.buffer_type = HFI_BUFFER_OUTPUT; + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + fmt.buffer_type = HFI_BUFFER_INPUT; fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; - ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } return ret; } -static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst) +static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; struct hfi_uncompressed_plane_actual_constraints_info pconstraint; @@ -620,7 +821,7 @@ static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst) return hfi_gen1_set_property(inst, ptype, &pconstraint, sizeof(pconstraint)); } -static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) +static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL; struct hfi_buffer_count_actual buf_count; @@ -634,20 +835,28 @@ static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) if (ret) return ret; - if (iris_split_mode_enabled(inst)) { - buf_count.type = HFI_BUFFER_OUTPUT; - buf_count.count_actual = VIDEO_MAX_FRAME; - buf_count.count_min_host = VIDEO_MAX_FRAME; + if (inst->domain == DECODER) { + if (iris_split_mode_enabled(inst)) { + buf_count.type = HFI_BUFFER_OUTPUT; + buf_count.count_actual = VIDEO_MAX_FRAME; + buf_count.count_min_host = VIDEO_MAX_FRAME; - ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); - if (ret) - return ret; + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + if (ret) + return ret; - buf_count.type = HFI_BUFFER_OUTPUT2; - buf_count.count_actual = iris_vpu_buf_count(inst, BUF_DPB); - buf_count.count_min_host = iris_vpu_buf_count(inst, BUF_DPB); + buf_count.type = HFI_BUFFER_OUTPUT2; + buf_count.count_actual = iris_vpu_buf_count(inst, BUF_DPB); + buf_count.count_min_host = iris_vpu_buf_count(inst, BUF_DPB); - ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + } else { + buf_count.type = HFI_BUFFER_OUTPUT; + buf_count.count_actual = VIDEO_MAX_FRAME; + buf_count.count_min_host = VIDEO_MAX_FRAME; + + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + } } else { buf_count.type = HFI_BUFFER_OUTPUT; buf_count.count_actual = VIDEO_MAX_FRAME; @@ -659,7 +868,7 @@ static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) return ret; } -static int iris_hfi_gen1_set_multistream(struct iris_inst *inst) +static int iris_hfi_gen1_set_multistream(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM; struct hfi_multi_stream multi = {0}; @@ -694,7 +903,7 @@ static int iris_hfi_gen1_set_multistream(struct iris_inst *inst) return ret; } -static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) +static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL; struct hfi_buffer_size_actual bufsz; @@ -702,7 +911,7 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) if (iris_split_mode_enabled(inst)) { bufsz.type = HFI_BUFFER_OUTPUT; - bufsz.size = iris_vpu_buf_size(inst, BUF_DPB); + bufsz.size = inst->core->iris_platform_data->get_vpu_buffer_size(inst, BUF_DPB); ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz)); if (ret) @@ -729,14 +938,49 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) return ret; } +static int iris_hfi_gen1_set_frame_rate(struct iris_inst *inst, u32 plane) +{ + const u32 ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; + struct hfi_framerate frate; + + if (V4L2_TYPE_IS_OUTPUT(plane)) + return 0; + + frate.buffer_type = HFI_BUFFER_OUTPUT; + frate.framerate = inst->frame_rate << 16; + + return hfi_gen1_set_property(inst, ptype, &frate, sizeof(frate)); +} + +static int iris_hfi_gen1_set_stride(struct iris_inst *inst, u32 plane) +{ + const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO; + struct hfi_uncompressed_plane_actual_info plane_actual_info; + + plane_actual_info.buffer_type = HFI_BUFFER_INPUT; + plane_actual_info.num_planes = 2; + plane_actual_info.plane_format[0].actual_stride = + ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + plane_actual_info.plane_format[0].actual_plane_buffer_height = + ALIGN(inst->fmt_src->fmt.pix_mp.height, 32); + plane_actual_info.plane_format[1].actual_stride = + ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + plane_actual_info.plane_format[1].actual_plane_buffer_height = + (ALIGN(inst->fmt_src->fmt.pix_mp.height, 32)) / 2; + + return hfi_gen1_set_property(inst, ptype, &plane_actual_info, sizeof(plane_actual_info)); +} + static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 plane) { + struct iris_hfi_prop_type_handle const *handler = NULL; + u32 handler_size = 0; struct iris_core *core = inst->core; u32 config_params_size, i, j; const u32 *config_params; int ret; - static const struct iris_hfi_prop_type_handle prop_type_handle_inp_arr[] = { + static const struct iris_hfi_prop_type_handle vdec_prop_type_handle_inp_arr[] = { {HFI_PROPERTY_PARAM_FRAME_SIZE, iris_hfi_gen1_set_resolution}, {HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE, @@ -753,7 +997,7 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p iris_hfi_gen1_set_bufsize}, }; - static const struct iris_hfi_prop_type_handle prop_type_handle_out_arr[] = { + static const struct iris_hfi_prop_type_handle vdec_prop_type_handle_out_arr[] = { {HFI_PROPERTY_PARAM_FRAME_SIZE, iris_hfi_gen1_set_resolution}, {HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, @@ -768,29 +1012,43 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p iris_hfi_gen1_set_bufsize}, }; - config_params = core->iris_platform_data->input_config_params; - config_params_size = core->iris_platform_data->input_config_params_size; - - if (V4L2_TYPE_IS_OUTPUT(plane)) { - for (i = 0; i < config_params_size; i++) { - for (j = 0; j < ARRAY_SIZE(prop_type_handle_inp_arr); j++) { - if (prop_type_handle_inp_arr[j].type == config_params[i]) { - ret = prop_type_handle_inp_arr[j].handle(inst); - if (ret) - return ret; - break; - } - } + static const struct iris_hfi_prop_type_handle venc_prop_type_handle_inp_arr[] = { + {HFI_PROPERTY_CONFIG_FRAME_RATE, + iris_hfi_gen1_set_frame_rate}, + {HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + iris_hfi_gen1_set_stride}, + {HFI_PROPERTY_PARAM_FRAME_SIZE, + iris_hfi_gen1_set_resolution}, + {HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + iris_hfi_gen1_set_raw_format}, + {HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, + iris_hfi_gen1_set_num_bufs}, + }; + + if (inst->domain == DECODER) { + config_params = core->iris_platform_data->dec_input_config_params_default; + config_params_size = core->iris_platform_data->dec_input_config_params_default_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + handler = vdec_prop_type_handle_inp_arr; + handler_size = ARRAY_SIZE(vdec_prop_type_handle_inp_arr); + } else if (V4L2_TYPE_IS_CAPTURE(plane)) { + handler = vdec_prop_type_handle_out_arr; + handler_size = ARRAY_SIZE(vdec_prop_type_handle_out_arr); } - } else if (V4L2_TYPE_IS_CAPTURE(plane)) { - for (i = 0; i < config_params_size; i++) { - for (j = 0; j < ARRAY_SIZE(prop_type_handle_out_arr); j++) { - if (prop_type_handle_out_arr[j].type == config_params[i]) { - ret = prop_type_handle_out_arr[j].handle(inst); - if (ret) - return ret; - break; - } + } else { + config_params = core->iris_platform_data->enc_input_config_params; + config_params_size = core->iris_platform_data->enc_input_config_params_size; + handler = venc_prop_type_handle_inp_arr; + handler_size = ARRAY_SIZE(venc_prop_type_handle_inp_arr); + } + + for (i = 0; i < config_params_size; i++) { + for (j = 0; j < handler_size; j++) { + if (handler[j].type == config_params[i]) { + ret = handler[j].handle(inst, plane); + if (ret) + return ret; + break; } } } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 9f246816a286..42226ccee3d9 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -10,9 +10,12 @@ #define HFI_VIDEO_ARCH_OX 0x1 +#define HFI_SESSION_TYPE_ENC 1 #define HFI_SESSION_TYPE_DEC 2 #define HFI_VIDEO_CODEC_H264 0x00000002 +#define HFI_VIDEO_CODEC_HEVC 0x00002000 +#define HFI_VIDEO_CODEC_VP9 0x00004000 #define HFI_ERR_NONE 0x0 @@ -65,25 +68,28 @@ #define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 -#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER 0x1200001 #define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e #define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 #define HFI_BUFFER_INPUT 0x1 #define HFI_BUFFER_OUTPUT 0x2 #define HFI_BUFFER_OUTPUT2 0x3 +#define HFI_BUFFER_INTERNAL_PERSIST 0x4 #define HFI_BUFFER_INTERNAL_PERSIST_1 0x5 #define HFI_BUFFER_INTERNAL_SCRATCH 0x6 #define HFI_BUFFER_INTERNAL_SCRATCH_1 0x7 +#define HFI_BUFFER_INTERNAL_SCRATCH_2 0x8 #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 #define HFI_PROPERTY_PARAM_FRAME_SIZE 0x1001 +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO 0x1002 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT 0x1003 #define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT 0x1005 #define HFI_PROPERTY_PARAM_WORK_MODE 0x1015 #define HFI_PROPERTY_PARAM_WORK_ROUTE 0x1017 +#define HFI_PROPERTY_CONFIG_FRAME_RATE 0x2001 #define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE 0x2002 #define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM 0x1003001 @@ -110,13 +116,32 @@ #define HFI_MSG_SESSION_RELEASE_RESOURCES 0x22100a #define HFI_MSG_SESSION_RELEASE_BUFFERS 0x22100c -#define HFI_PICTURE_I 0x00000001 -#define HFI_PICTURE_P 0x00000002 -#define HFI_PICTURE_B 0x00000004 -#define HFI_PICTURE_IDR 0x00000008 +#define HFI_GEN1_PICTURE_I 0x00000001 +#define HFI_GEN1_PICTURE_P 0x00000002 +#define HFI_GEN1_PICTURE_B 0x00000004 +#define HFI_GEN1_PICTURE_IDR 0x00000008 #define HFI_FRAME_NOTCODED 0x7f002000 #define HFI_FRAME_YUV 0x7f004000 #define HFI_UNUSED_PICT 0x10000000 +#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HFI_RATE_CONTROL_OFF 0x1000001 +#define HFI_RATE_CONTROL_VBR_VFR 0x1000002 +#define HFI_RATE_CONTROL_VBR_CFR 0x1000003 +#define HFI_RATE_CONTROL_CBR_VFR 0x1000004 +#define HFI_RATE_CONTROL_CBR_CFR 0x1000005 +#define HFI_RATE_CONTROL_CQ 0x1000008 + +#define HFI_H264_ENTROPY_CAVLC 0x1 +#define HFI_H264_ENTROPY_CABAC 0x2 + +#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL 0x2005002 +#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL 0x2005003 +#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL 0x2005004 +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 0x2005009 +#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020 +#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE 0x2006001 +#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER 0x2006008 struct hfi_pkt_hdr { u32 size; @@ -191,6 +216,23 @@ struct hfi_session_empty_buffer_compressed_pkt { u32 data; }; +struct hfi_session_empty_buffer_uncompressed_pkt { + struct hfi_session_hdr_pkt shdr; + u32 view_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; + u32 mark_data; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 input_tag; + u32 packet_buffer; + u32 extradata_buffer; + u32 data; +}; + struct hfi_session_fill_buffer_pkt { struct hfi_session_hdr_pkt shdr; u32 stream_id; @@ -337,6 +379,17 @@ struct hfi_uncompressed_plane_actual_constraints_info { struct hfi_uncompressed_plane_constraints plane_format[2]; }; +struct hfi_uncompressed_plane_actual { + int actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hfi_uncompressed_plane_actual_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_actual plane_format[2]; +}; + struct hfi_buffer_count_actual { u32 type; u32 count_actual; @@ -364,6 +417,36 @@ struct hfi_buffer_requirements { u32 alignment; }; +struct hfi_bitrate { + u32 bitrate; + u32 layer_id; +}; + +#define HFI_H264_CABAC_MODEL_0 0x1 + +struct hfi_h264_entropy_control { + u32 entropy_mode; + u32 cabac_model; +}; + +struct hfi_quantization_v2 { + u32 qp_packed; + u32 layer_id; + u32 enable; + u32 reserved[3]; +}; + +struct hfi_quantization_range_v2 { + struct hfi_quantization_v2 min_qp; + struct hfi_quantization_v2 max_qp; + u32 reserved[4]; +}; + +struct hfi_framerate { + u32 buffer_type; + u32 framerate; +}; + struct hfi_event_data { u32 error; u32 height; @@ -395,6 +478,26 @@ struct hfi_msg_session_empty_buffer_done_pkt { u32 data[]; }; +struct hfi_msg_session_fbd_compressed_pkt { + struct hfi_session_hdr_pkt shdr; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 error_type; + u32 flags; + u32 mark_target; + u32 mark_data; + u32 stats; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 input_tag; + u32 output_tag; + u32 picture_type; + u32 packet_buffer; + u32 extradata_buffer; + u32 data[]; +}; + struct hfi_msg_session_fbd_uncompressed_plane0_pkt { struct hfi_session_hdr_pkt shdr; u32 stream_id; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c index b72d503dd740..8e864c239e29 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c @@ -200,14 +200,14 @@ static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst, iris_hfi_gen1_read_changed_params(inst, pkt); - if (inst->state != IRIS_INST_ERROR) { - reinit_completion(&inst->flush_completion); + if (inst->state != IRIS_INST_ERROR && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; flush_pkt.shdr.session_id = inst->session_id; flush_pkt.flush_type = HFI_FLUSH_OUTPUT; - iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size); + if (!iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size)) + inst->flush_responses_pending++; } iris_vdec_src_change(inst); @@ -348,6 +348,10 @@ static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) struct iris_buffer *buf = NULL; bool found = false; + /* EOS buffer sent via drain won't be in v4l2 buffer list */ + if (pkt->packet_buffer == 0xdeadb000) + return; + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { buf = to_iris_buffer(&m2m_buffer->vb); if (buf->index == pkt->input_tag) { @@ -383,24 +387,43 @@ error: static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) { - struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt = packet; + struct hfi_msg_session_fbd_uncompressed_plane0_pkt *uncom_pkt = packet; + struct hfi_msg_session_fbd_compressed_pkt *com_pkt = packet; struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; struct v4l2_m2m_buffer *m2m_buffer, *n; struct hfi_session_flush_pkt flush_pkt; - u32 timestamp_hi = pkt->time_stamp_hi; - u32 timestamp_lo = pkt->time_stamp_lo; + u32 timestamp_hi; + u32 timestamp_lo; struct iris_core *core = inst->core; - u32 filled_len = pkt->filled_len; - u32 pic_type = pkt->picture_type; - u32 output_tag = pkt->output_tag; + u32 filled_len; + u32 pic_type; + u32 output_tag; struct iris_buffer *buf, *iter; struct iris_buffers *buffers; - u32 hfi_flags = pkt->flags; - u32 offset = pkt->offset; + u32 hfi_flags; + u32 offset; u64 timestamp_us = 0; bool found = false; u32 flags = 0; + if (inst->domain == DECODER) { + timestamp_hi = uncom_pkt->time_stamp_hi; + timestamp_lo = uncom_pkt->time_stamp_lo; + filled_len = uncom_pkt->filled_len; + pic_type = uncom_pkt->picture_type; + output_tag = uncom_pkt->output_tag; + hfi_flags = uncom_pkt->flags; + offset = uncom_pkt->offset; + } else { + timestamp_hi = com_pkt->time_stamp_hi; + timestamp_lo = com_pkt->time_stamp_lo; + filled_len = com_pkt->filled_len; + pic_type = com_pkt->picture_type; + output_tag = com_pkt->output_tag; + hfi_flags = com_pkt->flags; + offset = com_pkt->offset; + } + if ((hfi_flags & HFI_BUFFERFLAG_EOS) && !filled_len) { reinit_completion(&inst->flush_completion); @@ -408,13 +431,14 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; flush_pkt.shdr.session_id = inst->session_id; flush_pkt.flush_type = HFI_FLUSH_OUTPUT; - iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); - iris_inst_sub_state_change_drain_last(inst); + if (!iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size)) + inst->flush_responses_pending++; - return; + iris_inst_sub_state_change_drain_last(inst); } - if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) { + if (iris_split_mode_enabled(inst) && inst->domain == DECODER && + uncom_pkt->stream_id == 0) { buffers = &inst->buffers[BUF_DPB]; if (!buffers) goto error; @@ -455,19 +479,30 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) timestamp_us = timestamp_hi; timestamp_us = (timestamp_us << 32) | timestamp_lo; } else { - flags |= V4L2_BUF_FLAG_LAST; + if (inst->domain == DECODER && uncom_pkt->stream_id == 1 && + !inst->last_buffer_dequeued) { + if (iris_drc_pending(inst) || iris_drain_pending(inst)) { + flags |= V4L2_BUF_FLAG_LAST; + inst->last_buffer_dequeued = true; + } + } else if (inst->domain == ENCODER) { + if (!inst->last_buffer_dequeued && iris_drain_pending(inst)) { + flags |= V4L2_BUF_FLAG_LAST; + inst->last_buffer_dequeued = true; + } + } } buf->timestamp = timestamp_us; switch (pic_type) { - case HFI_PICTURE_IDR: - case HFI_PICTURE_I: + case HFI_GEN1_PICTURE_IDR: + case HFI_GEN1_PICTURE_I: flags |= V4L2_BUF_FLAG_KEYFRAME; break; - case HFI_PICTURE_P: + case HFI_GEN1_PICTURE_P: flags |= V4L2_BUF_FLAG_PFRAME; break; - case HFI_PICTURE_B: + case HFI_GEN1_PICTURE_B: flags |= V4L2_BUF_FLAG_BFRAME; break; case HFI_FRAME_NOTCODED: @@ -481,6 +516,12 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) buf->attr |= BUF_ATTR_DEQUEUED; buf->attr |= BUF_ATTR_BUFFER_DONE; + if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT) + flags |= V4L2_BUF_FLAG_ERROR; + + if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) + flags |= V4L2_BUF_FLAG_ERROR; + buf->flags |= flags; iris_vb2_buffer_done(inst, buf); @@ -536,7 +577,7 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { }, { .pkt = HFI_MSG_SESSION_FILL_BUFFER, - .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), + .pkt_sz = sizeof(struct hfi_msg_session_fbd_compressed_pkt), }, { .pkt = HFI_MSG_SESSION_FLUSH, @@ -558,7 +599,6 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response const struct iris_hfi_gen1_response_pkt_info *pkt_info; struct device *dev = core->dev; struct hfi_session_pkt *pkt; - struct completion *done; struct iris_inst *inst; bool found = false; u32 i; @@ -619,9 +659,12 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response if (shdr->error_type != HFI_ERR_NONE) iris_inst_change_state(inst, IRIS_INST_ERROR); - done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ? - &inst->flush_completion : &inst->completion; - complete(done); + if (pkt_info->pkt == HFI_MSG_SESSION_FLUSH) { + if (!(--inst->flush_responses_pending)) + complete(&inst->flush_completion); + } else { + complete(&inst->completion); + } } mutex_unlock(&inst->lock); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index a908b41e2868..4ce71a142508 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -88,33 +88,63 @@ static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core) return ret; } -static u32 iris_hfi_gen2_get_port(u32 plane) +static u32 iris_hfi_gen2_get_port(struct iris_inst *inst, u32 plane) { - switch (plane) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return HFI_PORT_BITSTREAM; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return HFI_PORT_RAW; - default: - return HFI_PORT_NONE; + if (inst->domain == DECODER) { + switch (plane) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return HFI_PORT_BITSTREAM; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return HFI_PORT_RAW; + default: + return HFI_PORT_NONE; + } + } else { + switch (plane) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return HFI_PORT_RAW; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return HFI_PORT_BITSTREAM; + default: + return HFI_PORT_NONE; + } } } -static u32 iris_hfi_gen2_get_port_from_buf_type(enum iris_buffer_type buffer_type) +static u32 iris_hfi_gen2_get_port_from_buf_type(struct iris_inst *inst, + enum iris_buffer_type buffer_type) { - switch (buffer_type) { - case BUF_INPUT: - case BUF_BIN: - case BUF_COMV: - case BUF_NON_COMV: - case BUF_LINE: - return HFI_PORT_BITSTREAM; - case BUF_OUTPUT: - case BUF_DPB: - return HFI_PORT_RAW; - case BUF_PERSIST: - default: - return HFI_PORT_NONE; + if (inst->domain == DECODER) { + switch (buffer_type) { + case BUF_INPUT: + case BUF_BIN: + case BUF_COMV: + case BUF_NON_COMV: + case BUF_LINE: + return HFI_PORT_BITSTREAM; + case BUF_OUTPUT: + case BUF_DPB: + return HFI_PORT_RAW; + case BUF_PERSIST: + default: + return HFI_PORT_NONE; + } + } else { + switch (buffer_type) { + case BUF_INPUT: + case BUF_VPSS: + return HFI_PORT_RAW; + case BUF_OUTPUT: + case BUF_BIN: + case BUF_COMV: + case BUF_NON_COMV: + case BUF_LINE: + case BUF_SCRATCH_2: + return HFI_PORT_BITSTREAM; + case BUF_ARP: + default: + return HFI_PORT_NONE; + } } } @@ -136,34 +166,77 @@ static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 packet inst_hfi_gen2->packet->size); } -static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst) +static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) { - struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 resolution = inst->fmt_src->fmt.pix_mp.width << 16 | inst->fmt_src->fmt.pix_mp.height; + u32 port = iris_hfi_gen2_get_port(inst, plane); + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_RAW_RESOLUTION, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_32_PACKED, + &resolution, + sizeof(u32)); +} - inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; +static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst, u32 plane) +{ + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 port = iris_hfi_gen2_get_port(inst, plane); + enum hfi_packet_payload_info payload_type; + u32 resolution, codec_align; + + if (inst->domain == DECODER) { + resolution = inst->fmt_src->fmt.pix_mp.width << 16 | + inst->fmt_src->fmt.pix_mp.height; + inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; + payload_type = HFI_PAYLOAD_U32; + } else { + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + resolution = ALIGN(inst->fmt_dst->fmt.pix_mp.width, codec_align) << 16 | + ALIGN(inst->fmt_dst->fmt.pix_mp.height, codec_align); + inst_hfi_gen2->dst_subcr_params.bitstream_resolution = resolution; + payload_type = HFI_PAYLOAD_32_PACKED; + } return iris_hfi_gen2_session_set_property(inst, HFI_PROP_BITSTREAM_RESOLUTION, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U32, + payload_type, &resolution, sizeof(u32)); } -static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst) +static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) { - u32 bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); - u32 right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - u32 left_offset = inst->crop.left; - u32 top_offset = inst->crop.top; + u32 port = iris_hfi_gen2_get_port(inst, plane); + u32 bottom_offset, right_offset; + u32 left_offset, top_offset; u32 payload[2]; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); + right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; + } else { + bottom_offset = (inst->fmt_dst->fmt.pix_mp.height - inst->compose.height); + right_offset = (inst->fmt_dst->fmt.pix_mp.width - inst->compose.width); + left_offset = inst->compose.left; + top_offset = inst->compose.top; + } + } else { + bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); + right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; + } + payload[0] = FIELD_PREP(GENMASK(31, 16), left_offset) | top_offset; payload[1] = FIELD_PREP(GENMASK(31, 16), right_offset) | bottom_offset; inst_hfi_gen2->src_subcr_params.crop_offsets[0] = payload[0]; @@ -178,10 +251,10 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst) sizeof(u64)); } -static int iris_hfi_gen2_set_bit_dpeth(struct iris_inst *inst) +static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 bitdepth = BIT_DEPTH_8; inst_hfi_gen2->src_subcr_params.bit_depth = bitdepth; @@ -195,10 +268,10 @@ static int iris_hfi_gen2_set_bit_dpeth(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst) +static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 coded_frames = 0; if (inst->fw_caps[CODED_FRAMES].value == CODED_FRAMES_PROGRESSIVE) @@ -214,11 +287,11 @@ static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst) +static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 min_output = inst->buffers[BUF_OUTPUT].min_count; + u32 port = iris_hfi_gen2_get_port(inst, plane); inst_hfi_gen2->src_subcr_params.fw_min_count = min_output; @@ -231,10 +304,10 @@ static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst) +static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 poc = 0; inst_hfi_gen2->src_subcr_params.pic_order_cnt = poc; @@ -248,16 +321,16 @@ static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst) +static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); struct v4l2_pix_format_mplane *pixmp = &inst->fmt_src->fmt.pix_mp; u32 video_signal_type_present_flag = 0, color_info; u32 matrix_coeff = HFI_MATRIX_COEFF_RESERVED; u32 video_format = UNSPECIFIED_COLOR_FORMAT; u32 full_range = V4L2_QUANTIZATION_DEFAULT; u32 transfer_char = HFI_TRANSFER_RESERVED; + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 colour_description_present_flag = 0; u32 primaries = HFI_PRIMARIES_RESERVED; @@ -291,11 +364,23 @@ static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_profile(struct iris_inst *inst) +static int iris_hfi_gen2_set_profile(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - u32 profile = inst->fw_caps[PROFILE].value; + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 profile = 0; + + switch (inst->codec) { + case V4L2_PIX_FMT_HEVC: + profile = inst->fw_caps[PROFILE_HEVC].value; + break; + case V4L2_PIX_FMT_VP9: + profile = inst->fw_caps[PROFILE_VP9].value; + break; + case V4L2_PIX_FMT_H264: + profile = inst->fw_caps[PROFILE_H264].value; + break; + } inst_hfi_gen2->src_subcr_params.profile = profile; @@ -308,11 +393,23 @@ static int iris_hfi_gen2_set_profile(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_level(struct iris_inst *inst) +static int iris_hfi_gen2_set_level(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - u32 level = inst->fw_caps[LEVEL].value; + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 level = 0; + + switch (inst->codec) { + case V4L2_PIX_FMT_HEVC: + level = inst->fw_caps[LEVEL_HEVC].value; + break; + case V4L2_PIX_FMT_VP9: + level = inst->fw_caps[LEVEL_VP9].value; + break; + case V4L2_PIX_FMT_H264: + level = inst->fw_caps[LEVEL_H264].value; + break; + } inst_hfi_gen2->src_subcr_params.level = level; @@ -325,33 +422,47 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst) +static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) { - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 hfi_colorformat, pixelformat; - pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + } else { + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + } return iris_hfi_gen2_session_set_property(inst, HFI_PROP_COLOR_FORMAT, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U32, + HFI_PAYLOAD_U32_ENUM, &hfi_colorformat, sizeof(u32)); } -static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst) +static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst, u32 plane) { - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - u32 scanline_y = inst->fmt_dst->fmt.pix_mp.height; - u32 stride_y = inst->fmt_dst->fmt.pix_mp.width; - u32 scanline_uv = scanline_y / 2; - u32 stride_uv = stride_y; + u32 pixelformat, stride_y, stride_uv, scanline_y, scanline_uv; + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 payload[2]; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + stride_y = inst->fmt_dst->fmt.pix_mp.width; + scanline_y = inst->fmt_dst->fmt.pix_mp.height; + } else { + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + stride_y = ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + scanline_y = ALIGN(inst->fmt_src->fmt.pix_mp.height, 32); + } + + stride_uv = stride_y; + scanline_uv = scanline_y / 2; + if (pixelformat != V4L2_PIX_FMT_NV12) return 0; @@ -362,23 +473,55 @@ static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst) HFI_PROP_LINEAR_STRIDE_SCANLINE, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U64, + HFI_PAYLOAD_64_PACKED, &payload, sizeof(u64)); } +static int iris_hfi_gen2_set_tier(struct iris_inst *inst, u32 plane) +{ + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 tier = inst->fw_caps[TIER].value; + + inst_hfi_gen2->src_subcr_params.tier = tier; + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_TIER, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_U32_ENUM, + &tier, + sizeof(u32)); +} + +static int iris_hfi_gen2_set_frame_rate(struct iris_inst *inst, u32 plane) +{ + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + u32 frame_rate = inst->frame_rate << 16; + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_Q16, + &frame_rate, + sizeof(u32)); +} + static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) { - struct iris_core *core = inst->core; - u32 config_params_size, i, j; - const u32 *config_params; + const struct iris_platform_data *pdata = inst->core->iris_platform_data; + u32 config_params_size = 0, i, j; + const u32 *config_params = NULL; int ret; static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = { + {HFI_PROP_RAW_RESOLUTION, iris_hfi_gen2_set_raw_resolution }, {HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution }, {HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets }, {HFI_PROP_CODED_FRAMES, iris_hfi_gen2_set_coded_frames }, - {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, iris_hfi_gen2_set_bit_dpeth }, + {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, iris_hfi_gen2_set_bit_depth }, {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, iris_hfi_gen2_set_min_output_count }, {HFI_PROP_PIC_ORDER_CNT_TYPE, iris_hfi_gen2_set_picture_order_count }, {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, @@ -386,14 +529,36 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, + {HFI_PROP_TIER, iris_hfi_gen2_set_tier }, + {HFI_PROP_FRAME_RATE, iris_hfi_gen2_set_frame_rate }, }; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - config_params = core->iris_platform_data->input_config_params; - config_params_size = core->iris_platform_data->input_config_params_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + if (inst->codec == V4L2_PIX_FMT_H264) { + config_params = pdata->dec_input_config_params_default; + config_params_size = pdata->dec_input_config_params_default_size; + } else if (inst->codec == V4L2_PIX_FMT_HEVC) { + config_params = pdata->dec_input_config_params_hevc; + config_params_size = pdata->dec_input_config_params_hevc_size; + } else if (inst->codec == V4L2_PIX_FMT_VP9) { + config_params = pdata->dec_input_config_params_vp9; + config_params_size = pdata->dec_input_config_params_vp9_size; + } else { + return -EINVAL; + } + } else { + config_params = pdata->dec_output_config_params; + config_params_size = pdata->dec_output_config_params_size; + } } else { - config_params = core->iris_platform_data->output_config_params; - config_params_size = core->iris_platform_data->output_config_params_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + config_params = pdata->enc_input_config_params; + config_params_size = pdata->enc_input_config_params_size; + } else { + config_params = pdata->enc_output_config_params; + config_params_size = pdata->enc_output_config_params_size; + } } if (!config_params || !config_params_size) @@ -402,7 +567,7 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p for (i = 0; i < config_params_size; i++) { for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) { if (prop_type_handle_arr[j].type == config_params[i]) { - ret = prop_type_handle_arr[j].handle(inst); + ret = prop_type_handle_arr[j].handle(inst, plane); if (ret) return ret; break; @@ -416,7 +581,24 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 codec = HFI_CODEC_DECODE_AVC; + u32 codec = 0; + + switch (inst->codec) { + case V4L2_PIX_FMT_H264: + if (inst->domain == ENCODER) + codec = HFI_CODEC_ENCODE_AVC; + else + codec = HFI_CODEC_DECODE_AVC; + break; + case V4L2_PIX_FMT_HEVC: + if (inst->domain == ENCODER) + codec = HFI_CODEC_ENCODE_HEVC; + else + codec = HFI_CODEC_DECODE_HEVC; + break; + case V4L2_PIX_FMT_VP9: + codec = HFI_CODEC_DECODE_VP9; + } iris_hfi_gen2_packet_session_property(inst, HFI_PROP_CODEC, @@ -481,9 +663,11 @@ static int iris_hfi_gen2_session_open(struct iris_inst *inst) if (ret) goto fail_free_packet; - ret = iris_hfi_gen2_session_set_default_header(inst); - if (ret) - goto fail_free_packet; + if (inst->domain == DECODER) { + ret = iris_hfi_gen2_session_set_default_header(inst); + if (ret) + goto fail_free_packet; + } return 0; @@ -532,7 +716,7 @@ static int iris_hfi_gen2_session_subscribe_mode(struct iris_inst *inst, cmd, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, payload_type, payload, @@ -548,20 +732,38 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan struct hfi_subscription_params subsc_params; u32 prop_type, payload_size, payload_type; struct iris_core *core = inst->core; - const u32 *change_param; - u32 change_param_size; + const u32 *change_param = NULL; + u32 change_param_size = 0; u32 payload[32] = {0}; u32 hfi_port = 0, i; int ret; + if (inst->domain == ENCODER) + return 0; + if ((V4L2_TYPE_IS_OUTPUT(plane) && inst_hfi_gen2->ipsc_properties_set) || (V4L2_TYPE_IS_CAPTURE(plane) && inst_hfi_gen2->opsc_properties_set)) { dev_err(core->dev, "invalid plane\n"); return 0; } - change_param = core->iris_platform_data->input_config_params; - change_param_size = core->iris_platform_data->input_config_params_size; + switch (inst->codec) { + case V4L2_PIX_FMT_H264: + change_param = core->iris_platform_data->dec_input_config_params_default; + change_param_size = + core->iris_platform_data->dec_input_config_params_default_size; + break; + case V4L2_PIX_FMT_HEVC: + change_param = core->iris_platform_data->dec_input_config_params_hevc; + change_param_size = + core->iris_platform_data->dec_input_config_params_hevc_size; + break; + case V4L2_PIX_FMT_VP9: + change_param = core->iris_platform_data->dec_input_config_params_vp9; + change_param_size = + core->iris_platform_data->dec_input_config_params_vp9_size; + break; + } payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; @@ -580,7 +782,7 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan if (V4L2_TYPE_IS_OUTPUT(plane)) { inst_hfi_gen2->ipsc_properties_set = true; } else { - hfi_port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + hfi_port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); memcpy(&inst_hfi_gen2->dst_subcr_params, &inst_hfi_gen2->src_subcr_params, sizeof(inst_hfi_gen2->src_subcr_params)); @@ -608,6 +810,11 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan payload_size = sizeof(u32); payload_type = HFI_PAYLOAD_U32; break; + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: + payload[0] = subsc_params.bit_depth; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: payload[0] = subsc_params.fw_min_count; payload_size = sizeof(u32); @@ -633,6 +840,11 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan payload_size = sizeof(u32); payload_type = HFI_PAYLOAD_U32; break; + case HFI_PROP_TIER: + payload[0] = subsc_params.tier; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; default: prop_type = 0; ret = -EINVAL; @@ -659,18 +871,36 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) { struct iris_core *core = inst->core; - u32 subscribe_prop_size, i; - const u32 *subcribe_prop; + u32 subscribe_prop_size = 0, i; + const u32 *subcribe_prop = NULL; u32 payload[32] = {0}; payload[0] = HFI_MODE_PROPERTY; + if (inst->domain == ENCODER) + return 0; + if (V4L2_TYPE_IS_OUTPUT(plane)) { subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; subcribe_prop = core->iris_platform_data->dec_input_prop; } else { - subscribe_prop_size = core->iris_platform_data->dec_output_prop_size; - subcribe_prop = core->iris_platform_data->dec_output_prop; + switch (inst->codec) { + case V4L2_PIX_FMT_H264: + subcribe_prop = core->iris_platform_data->dec_output_prop_avc; + subscribe_prop_size = + core->iris_platform_data->dec_output_prop_avc_size; + break; + case V4L2_PIX_FMT_HEVC: + subcribe_prop = core->iris_platform_data->dec_output_prop_hevc; + subscribe_prop_size = + core->iris_platform_data->dec_output_prop_hevc_size; + break; + case V4L2_PIX_FMT_VP9: + subcribe_prop = core->iris_platform_data->dec_output_prop_vp9; + subscribe_prop_size = + core->iris_platform_data->dec_output_prop_vp9_size; + break; + } } for (i = 0; i < subscribe_prop_size; i++) @@ -701,7 +931,7 @@ static int iris_hfi_gen2_session_start(struct iris_inst *inst, u32 plane) HFI_CMD_START, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -723,7 +953,7 @@ static int iris_hfi_gen2_session_stop(struct iris_inst *inst, u32 plane) (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED | HFI_HOST_FLAGS_NON_DISCARDABLE), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -745,7 +975,7 @@ static int iris_hfi_gen2_session_pause(struct iris_inst *inst, u32 plane) HFI_CMD_PAUSE, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -764,7 +994,7 @@ static int iris_hfi_gen2_session_resume_drc(struct iris_inst *inst, u32 plane) HFI_CMD_RESUME, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_U32, &payload, @@ -783,7 +1013,7 @@ static int iris_hfi_gen2_session_resume_drain(struct iris_inst *inst, u32 plane) HFI_CMD_RESUME, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_U32, &payload, @@ -805,7 +1035,7 @@ static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane) (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED | HFI_HOST_FLAGS_NON_DISCARDABLE), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -815,13 +1045,19 @@ static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane) inst_hfi_gen2->packet->size); } -static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type) +static u32 iris_hfi_gen2_buf_type_from_driver(u32 domain, enum iris_buffer_type buffer_type) { switch (buffer_type) { case BUF_INPUT: - return HFI_BUFFER_BITSTREAM; + if (domain == DECODER) + return HFI_BUFFER_BITSTREAM; + else + return HFI_BUFFER_RAW; case BUF_OUTPUT: - return HFI_BUFFER_RAW; + if (domain == DECODER) + return HFI_BUFFER_RAW; + else + return HFI_BUFFER_BITSTREAM; case BUF_BIN: return HFI_BUFFER_BIN; case BUF_COMV: @@ -831,9 +1067,14 @@ static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type) case BUF_LINE: return HFI_BUFFER_LINE; case BUF_DPB: + case BUF_SCRATCH_2: return HFI_BUFFER_DPB; case BUF_PERSIST: return HFI_BUFFER_PERSIST; + case BUF_ARP: + return HFI_BUFFER_ARP; + case BUF_VPSS: + return HFI_BUFFER_VPSS; default: return 0; } @@ -856,16 +1097,17 @@ static int iris_set_num_comv(struct iris_inst *inst) &num_comv, sizeof(u32)); } -static void iris_hfi_gen2_get_buffer(struct iris_buffer *buffer, struct iris_hfi_buffer *buf) +static void iris_hfi_gen2_get_buffer(u32 domain, struct iris_buffer *buffer, + struct iris_hfi_buffer *buf) { memset(buf, 0, sizeof(*buf)); - buf->type = iris_hfi_gen2_buf_type_from_driver(buffer->type); + buf->type = iris_hfi_gen2_buf_type_from_driver(domain, buffer->type); buf->index = buffer->index; buf->base_address = buffer->device_addr; buf->addr_offset = 0; buf->buffer_size = buffer->buffer_size; - if (buffer->type == BUF_INPUT) + if (domain == DECODER && buffer->type == BUF_INPUT) buf->buffer_size = ALIGN(buffer->buffer_size, 256); buf->data_offset = buffer->data_offset; buf->data_size = buffer->data_size; @@ -882,14 +1124,14 @@ static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct iri u32 port; int ret; - iris_hfi_gen2_get_buffer(buffer, &hfi_buffer); + iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_buffer); if (buffer->type == BUF_COMV) { ret = iris_set_num_comv(inst); if (ret) return ret; } - port = iris_hfi_gen2_get_port_from_buf_type(buffer->type); + port = iris_hfi_gen2_get_port_from_buf_type(inst, buffer->type); iris_hfi_gen2_packet_session_command(inst, HFI_CMD_BUFFER, HFI_HOST_FLAGS_INTR_REQUIRED, @@ -909,9 +1151,9 @@ static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct i struct iris_hfi_buffer hfi_buffer; u32 port; - iris_hfi_gen2_get_buffer(buffer, &hfi_buffer); + iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_buffer); hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE; - port = iris_hfi_gen2_get_port_from_buf_type(buffer->type); + port = iris_hfi_gen2_get_port_from_buf_type(inst, buffer->type); iris_hfi_gen2_packet_session_command(inst, HFI_CMD_BUFFER, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 806f8bb7f505..aa1f795f5626 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -46,20 +46,51 @@ #define HFI_PROP_CROP_OFFSETS 0x03000105 #define HFI_PROP_PROFILE 0x03000107 #define HFI_PROP_LEVEL 0x03000108 +#define HFI_PROP_TIER 0x03000109 #define HFI_PROP_STAGE 0x0300010a #define HFI_PROP_PIPE 0x0300010b +#define HFI_PROP_FRAME_RATE 0x0300010c #define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f #define HFI_PROP_CODED_FRAMES 0x03000120 #define HFI_PROP_CABAC_SESSION 0x03000121 #define HFI_PROP_BUFFER_HOST_MAX_COUNT 0x03000123 #define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT 0x03000124 #define HFI_PROP_PIC_ORDER_CNT_TYPE 0x03000128 + +enum hfi_rate_control { + HFI_RC_VBR_CFR = 0x00000000, + HFI_RC_CBR_CFR = 0x00000001, + HFI_RC_CQ = 0x00000002, + HFI_RC_OFF = 0x00000003, + HFI_RC_CBR_VFR = 0x00000004, + HFI_RC_LOSSLESS = 0x00000005, +}; + +#define HFI_PROP_RATE_CONTROL 0x0300012a +#define HFI_PROP_QP_PACKED 0x0300012e +#define HFI_PROP_MIN_QP_PACKED 0x0300012f +#define HFI_PROP_MAX_QP_PACKED 0x03000130 +#define HFI_PROP_TOTAL_BITRATE 0x0300013b +#define HFI_PROP_MAX_GOP_FRAMES 0x03000146 +#define HFI_PROP_MAX_B_FRAMES 0x03000147 #define HFI_PROP_QUALITY_MODE 0x03000148 + +enum hfi_seq_header_mode { + HFI_SEQ_HEADER_SEPERATE_FRAME = 0x00000001, + HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME = 0x00000002, + HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME = 0x00000004, + HFI_SEQ_HEADER_METADATA = 0x00000008, +}; + +#define HFI_PROP_SEQ_HEADER_MODE 0x03000149 #define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155 #define HFI_PROP_PICTURE_TYPE 0x03000162 #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 #define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169 #define HFI_PROP_NO_OUTPUT 0x0300016a +#define HFI_PROP_BUFFER_MARK 0x0300016c +#define HFI_PROP_RAW_RESOLUTION 0x03000178 +#define HFI_PROP_TOTAL_PEAK_BITRATE 0x0300017C #define HFI_PROP_COMV_BUFFER_COUNT 0x03000193 #define HFI_PROP_END 0x03FFFFFF @@ -104,15 +135,19 @@ enum hfi_color_format { enum hfi_codec_type { HFI_CODEC_DECODE_AVC = 1, HFI_CODEC_ENCODE_AVC = 2, + HFI_CODEC_DECODE_HEVC = 3, + HFI_CODEC_ENCODE_HEVC = 4, + HFI_CODEC_DECODE_VP9 = 5, }; enum hfi_picture_type { - HFI_PICTURE_IDR = 0x00000001, - HFI_PICTURE_P = 0x00000002, - HFI_PICTURE_B = 0x00000004, - HFI_PICTURE_I = 0x00000008, - HFI_PICTURE_CRA = 0x00000010, - HFI_PICTURE_BLA = 0x00000020, + HFI_GEN2_PICTURE_IDR = 0x00000001, + HFI_GEN2_PICTURE_P = 0x00000002, + HFI_GEN2_PICTURE_B = 0x00000004, + HFI_GEN2_PICTURE_I = 0x00000008, + HFI_GEN2_PICTURE_CRA = 0x00000010, + HFI_GEN2_PICTURE_BLA = 0x00000020, + HFI_GEN2_PICTURE_NOSHOW = 0x00000040, }; enum hfi_buffer_type { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index b75a01641d5d..2f1f118eae4f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -29,7 +29,8 @@ struct iris_hfi_gen2_packet_handle { int (*handle)(struct iris_inst *inst, struct iris_hfi_packet *pkt); }; -static u32 iris_hfi_gen2_buf_type_to_driver(enum hfi_buffer_type buf_type) +static u32 iris_hfi_gen2_buf_type_to_driver(struct iris_inst *inst, + enum hfi_buffer_type buf_type) { switch (buf_type) { case HFI_BUFFER_BITSTREAM: @@ -47,7 +48,10 @@ static u32 iris_hfi_gen2_buf_type_to_driver(enum hfi_buffer_type buf_type) case HFI_BUFFER_LINE: return BUF_LINE; case HFI_BUFFER_DPB: - return BUF_DPB; + if (inst->domain == DECODER) + return BUF_DPB; + else + return BUF_SCRATCH_2; case HFI_BUFFER_PERSIST: return BUF_PERSIST; default: @@ -87,15 +91,18 @@ static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type) static int iris_hfi_gen2_get_driver_buffer_flags(struct iris_inst *inst, u32 hfi_flags) { - u32 keyframe = HFI_PICTURE_IDR | HFI_PICTURE_I | HFI_PICTURE_CRA | HFI_PICTURE_BLA; struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 keyframe = HFI_GEN2_PICTURE_IDR | HFI_GEN2_PICTURE_I | + HFI_GEN2_PICTURE_CRA | HFI_GEN2_PICTURE_BLA; u32 driver_flags = 0; - if (inst_hfi_gen2->hfi_frame_info.picture_type & keyframe) + if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_NOSHOW) + driver_flags |= V4L2_BUF_FLAG_ERROR; + else if (inst_hfi_gen2->hfi_frame_info.picture_type & keyframe) driver_flags |= V4L2_BUF_FLAG_KEYFRAME; - else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_P) + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_P) driver_flags |= V4L2_BUF_FLAG_PFRAME; - else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_B) + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_B) driver_flags |= V4L2_BUF_FLAG_BFRAME; if (inst_hfi_gen2->hfi_frame_info.data_corrupt || inst_hfi_gen2->hfi_frame_info.overflow) @@ -265,7 +272,8 @@ static int iris_hfi_gen2_handle_system_error(struct iris_core *core, { struct iris_inst *instance; - dev_err(core->dev, "received system error of type %#x\n", pkt->type); + if (pkt) + dev_err(core->dev, "received system error of type %#x\n", pkt->type); core->state = IRIS_CORE_ERROR; @@ -377,6 +385,11 @@ static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst, buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags); + if (!buf->data_size && inst->state == IRIS_INST_STREAMING && + !(hfi_buffer->flags & HFI_BUF_FW_FLAG_LAST)) { + buf->flags |= V4L2_BUF_FLAG_ERROR; + } + return 0; } @@ -412,11 +425,10 @@ static void iris_hfi_gen2_handle_dequeue_buffers(struct iris_inst *inst) static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, struct iris_hfi_buffer *buffer) { - u32 buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type); + u32 buf_type = iris_hfi_gen2_buf_type_to_driver(inst, buffer->type); struct iris_buffers *buffers = &inst->buffers[buf_type]; struct iris_buffer *buf, *iter; bool found = false; - int ret = 0; list_for_each_entry(iter, &buffers->list, list) { if (iter->device_addr == buffer->base_address) { @@ -429,10 +441,8 @@ static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, return -EINVAL; buf->attr &= ~BUF_ATTR_QUEUED; - if (buf->attr & BUF_ATTR_PENDING_RELEASE) - ret = iris_destroy_internal_buffer(inst, buf); - return ret; + return iris_destroy_internal_buffer(inst, buf); } static int iris_hfi_gen2_handle_session_stop(struct iris_inst *inst, @@ -470,12 +480,22 @@ static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst, if (!iris_hfi_gen2_is_valid_hfi_port(pkt->port, buffer->type)) return 0; - if (buffer->type == HFI_BUFFER_BITSTREAM) - return iris_hfi_gen2_handle_input_buffer(inst, buffer); - else if (buffer->type == HFI_BUFFER_RAW) - return iris_hfi_gen2_handle_output_buffer(inst, buffer); - else - return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + if (inst->domain == DECODER) { + if (buffer->type == HFI_BUFFER_BITSTREAM) + return iris_hfi_gen2_handle_input_buffer(inst, buffer); + else if (buffer->type == HFI_BUFFER_RAW) + return iris_hfi_gen2_handle_output_buffer(inst, buffer); + else + return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + } else { + if (buffer->type == HFI_BUFFER_RAW) + return iris_hfi_gen2_handle_input_buffer(inst, buffer); + else if (buffer->type == HFI_BUFFER_BITSTREAM) + return iris_hfi_gen2_handle_output_buffer(inst, buffer); + else + return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + } + return 0; } static int iris_hfi_gen2_handle_session_drain(struct iris_inst *inst, @@ -563,9 +583,23 @@ static void iris_hfi_gen2_read_input_subcr_params(struct iris_inst *inst) inst->crop.width = pixmp_ip->width - ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; - inst->fw_caps[PROFILE].value = subsc_params.profile; - inst->fw_caps[LEVEL].value = subsc_params.level; + switch (inst->codec) { + case V4L2_PIX_FMT_HEVC: + inst->fw_caps[PROFILE_HEVC].value = subsc_params.profile; + inst->fw_caps[LEVEL_HEVC].value = subsc_params.level; + break; + case V4L2_PIX_FMT_VP9: + inst->fw_caps[PROFILE_VP9].value = subsc_params.profile; + inst->fw_caps[LEVEL_VP9].value = subsc_params.level; + break; + case V4L2_PIX_FMT_H264: + inst->fw_caps[PROFILE_H264].value = subsc_params.profile; + inst->fw_caps[LEVEL_H264].value = subsc_params.level; + break; + } + inst->fw_caps[POC].value = subsc_params.pic_order_cnt; + inst->fw_caps[TIER].value = subsc_params.tier; if (subsc_params.bit_depth != BIT_DEPTH_8 || !(subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)) { @@ -636,9 +670,6 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - if (pkt->port != HFI_PORT_BITSTREAM) - return 0; - if (pkt->flags & HFI_FW_FLAGS_INFORMATION) return 0; @@ -650,6 +681,9 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, inst_hfi_gen2->src_subcr_params.crop_offsets[0] = pkt->payload[0]; inst_hfi_gen2->src_subcr_params.crop_offsets[1] = pkt->payload[1]; break; + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: + inst_hfi_gen2->src_subcr_params.bit_depth = pkt->payload[0]; + break; case HFI_PROP_CODED_FRAMES: inst_hfi_gen2->src_subcr_params.coded_frames = pkt->payload[0]; break; @@ -668,6 +702,9 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, case HFI_PROP_LEVEL: inst_hfi_gen2->src_subcr_params.level = pkt->payload[0]; break; + case HFI_PROP_TIER: + inst_hfi_gen2->src_subcr_params.tier = pkt->payload[0]; + break; case HFI_PROP_PICTURE_TYPE: inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; break; @@ -791,8 +828,21 @@ static void iris_hfi_gen2_init_src_change_param(struct iris_inst *inst) full_range, video_format, video_signal_type_present_flag); - subsc_params->profile = inst->fw_caps[PROFILE].value; - subsc_params->level = inst->fw_caps[LEVEL].value; + switch (inst->codec) { + case V4L2_PIX_FMT_HEVC: + subsc_params->profile = inst->fw_caps[PROFILE_HEVC].value; + subsc_params->level = inst->fw_caps[LEVEL_HEVC].value; + break; + case V4L2_PIX_FMT_VP9: + subsc_params->profile = inst->fw_caps[PROFILE_VP9].value; + subsc_params->level = inst->fw_caps[LEVEL_VP9].value; + break; + case V4L2_PIX_FMT_H264: + subsc_params->profile = inst->fw_caps[PROFILE_H264].value; + subsc_params->level = inst->fw_caps[LEVEL_H264].value; + break; + } + subsc_params->pic_order_cnt = inst->fw_caps[POC].value; subsc_params->bit_depth = inst->fw_caps[BIT_DEPTH].value; if (inst->fw_caps[CODED_FRAMES].value == diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c index fac7df0c4d1a..b3ed06297953 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c @@ -113,7 +113,7 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s { struct iris_iface_q_info *q_info = &core->command_queue; - if (core->state == IRIS_CORE_ERROR) + if (core->state == IRIS_CORE_ERROR || core->state == IRIS_CORE_DEINIT) return -EINVAL; if (!iris_hfi_queue_write(q_info, pkt, pkt_size)) { @@ -142,7 +142,6 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size) } mutex_unlock(&core->lock); - pm_runtime_mark_last_busy(core->dev); pm_runtime_put_autosuspend(core->dev); return 0; diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index caa3c6507006..5982d7adefea 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -12,6 +12,20 @@ #include "iris_core.h" #include "iris_utils.h" +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 + +enum iris_fmt_type { + IRIS_FMT_H264, + IRIS_FMT_HEVC, + IRIS_FMT_VP9, +}; + +struct iris_fmt { + u32 pixfmt; + u32 type; +}; + /** * struct iris_inst - holds per video instance parameters * @@ -24,9 +38,12 @@ * @fmt_src: structure of v4l2_format for source * @fmt_dst: structure of v4l2_format for destination * @ctrl_handler: reference of v4l2 ctrl handler + * @domain: domain type: encoder or decoder * @crop: structure of crop info + * @compose: structure of compose info * @completion: structure of signal completions * @flush_completion: structure of signal completions for flush cmd + * @flush_responses_pending: counter to track number of pending flush responses * @fw_caps: array of supported instance firmware capabilities * @buffers: array of different iris buffers * @fw_min_count: minimnum count of buffers needed by fw @@ -42,6 +59,11 @@ * @sequence_out: a sequence counter for output queue * @tss: timestamp metadata * @metadata_idx: index for metadata buffer + * @codec: codec type + * @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver + * @frame_rate: frame rate of current instance + * @operating_rate: operating rate of current instance + * @hfi_rc_type: rate control type */ struct iris_inst { @@ -54,9 +76,12 @@ struct iris_inst { struct v4l2_format *fmt_src; struct v4l2_format *fmt_dst; struct v4l2_ctrl_handler ctrl_handler; + enum domain_type domain; struct iris_hfi_rect_desc crop; + struct iris_hfi_rect_desc compose; struct completion completion; struct completion flush_completion; + u32 flush_responses_pending; struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; struct iris_buffers buffers[BUF_TYPE_MAX]; u32 fw_min_count; @@ -72,6 +97,11 @@ struct iris_inst { u32 sequence_out; struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; u32 metadata_idx; + u32 codec; + bool last_buffer_dequeued; + u32 frame_rate; + u32 operating_rate; + u32 hfi_rc_type; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index ac76d9e1ef9c..58d05e0a112e 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -7,6 +7,7 @@ #define __IRIS_PLATFORM_COMMON_H__ #include <linux/bits.h> +#include "iris_buffer.h" struct iris_core; struct iris_inst; @@ -21,6 +22,13 @@ struct iris_inst; #define DEFAULT_MAX_HOST_BUF_COUNT 64 #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 #define DEFAULT_FPS 30 +#define MAXIMUM_FPS 480 +#define NUM_MBS_8K ((8192 * 4352) / 256) +#define MIN_QP_8BIT 1 +#define MAX_QP 51 +#define MAX_QP_HEVC 63 +#define DEFAULT_QP 20 +#define BITRATE_DEFAULT 20000000 enum stage_type { STAGE_1 = 1, @@ -37,11 +45,15 @@ extern struct iris_platform_data qcs8300_data; extern struct iris_platform_data sm8250_data; extern struct iris_platform_data sm8550_data; extern struct iris_platform_data sm8650_data; +extern struct iris_platform_data sm8750_data; enum platform_clk_type { - IRIS_AXI_CLK, + IRIS_AXI_CLK, /* AXI0 in case of platforms with multiple AXI clocks */ IRIS_CTRL_CLK, IRIS_HW_CLK, + IRIS_AXI1_CLK, + IRIS_CTRL_FREERUN_CLK, + IRIS_HW_FREERUN_CLK, }; struct platform_clk_data { @@ -77,19 +89,57 @@ struct platform_inst_caps { u32 mb_cycles_fw; u32 mb_cycles_fw_vpp; u32 num_comv; + u32 max_frame_rate; + u32 max_operating_rate; }; enum platform_inst_fw_cap_type { - PROFILE = 1, - LEVEL, + PROFILE_H264 = 1, + PROFILE_HEVC, + PROFILE_VP9, + LEVEL_H264, + LEVEL_HEVC, + LEVEL_VP9, INPUT_BUF_HOST_MAX_COUNT, + OUTPUT_BUF_HOST_MAX_COUNT, STAGE, PIPE, POC, CODED_FRAMES, BIT_DEPTH, RAP_FRAME, - DEBLOCK, + TIER, + HEADER_MODE, + PREPEND_SPSPPS_TO_IDR, + BITRATE, + BITRATE_PEAK, + BITRATE_MODE, + FRAME_SKIP_MODE, + FRAME_RC_ENABLE, + GOP_SIZE, + ENTROPY_MODE, + MIN_FRAME_QP_H264, + MIN_FRAME_QP_HEVC, + MAX_FRAME_QP_H264, + MAX_FRAME_QP_HEVC, + I_FRAME_MIN_QP_H264, + I_FRAME_MIN_QP_HEVC, + P_FRAME_MIN_QP_H264, + P_FRAME_MIN_QP_HEVC, + B_FRAME_MIN_QP_H264, + B_FRAME_MIN_QP_HEVC, + I_FRAME_MAX_QP_H264, + I_FRAME_MAX_QP_HEVC, + P_FRAME_MAX_QP_H264, + P_FRAME_MAX_QP_HEVC, + B_FRAME_MAX_QP_H264, + B_FRAME_MAX_QP_HEVC, + I_FRAME_QP_H264, + I_FRAME_QP_HEVC, + P_FRAME_QP_H264, + P_FRAME_QP_HEVC, + B_FRAME_QP_H264, + B_FRAME_QP_HEVC, INST_FW_CAP_MAX, }; @@ -144,6 +194,7 @@ struct iris_platform_data { void (*init_hfi_command_ops)(struct iris_core *core); void (*init_hfi_response_ops)(struct iris_core *core); struct iris_inst *(*get_instance)(void); + u32 (*get_vpu_buffer_size)(struct iris_inst *inst, enum iris_buffer_type buffer_type); const struct vpu_ops *vpu_ops; void (*set_preset_registers)(struct iris_core *core); const struct icc_info *icc_tbl; @@ -164,27 +215,48 @@ struct iris_platform_data { const char *fwname; u32 pas_id; struct platform_inst_caps *inst_caps; - struct platform_inst_fw_cap *inst_fw_caps; - u32 inst_fw_caps_size; + struct platform_inst_fw_cap *inst_fw_caps_dec; + u32 inst_fw_caps_dec_size; + struct platform_inst_fw_cap *inst_fw_caps_enc; + u32 inst_fw_caps_enc_size; struct tz_cp_config *tz_cp_config_data; u32 core_arch; u32 hw_response_timeout; struct ubwc_config_data *ubwc_config; u32 num_vpp_pipe; u32 max_session_count; + /* max number of macroblocks per frame supported */ u32 max_core_mbpf; - const u32 *input_config_params; - unsigned int input_config_params_size; - const u32 *output_config_params; - unsigned int output_config_params_size; + /* max number of macroblocks per second supported */ + u32 max_core_mbps; + const u32 *dec_input_config_params_default; + unsigned int dec_input_config_params_default_size; + const u32 *dec_input_config_params_hevc; + unsigned int dec_input_config_params_hevc_size; + const u32 *dec_input_config_params_vp9; + unsigned int dec_input_config_params_vp9_size; + const u32 *dec_output_config_params; + unsigned int dec_output_config_params_size; + const u32 *enc_input_config_params; + unsigned int enc_input_config_params_size; + const u32 *enc_output_config_params; + unsigned int enc_output_config_params_size; const u32 *dec_input_prop; unsigned int dec_input_prop_size; - const u32 *dec_output_prop; - unsigned int dec_output_prop_size; + const u32 *dec_output_prop_avc; + unsigned int dec_output_prop_avc_size; + const u32 *dec_output_prop_hevc; + unsigned int dec_output_prop_hevc_size; + const u32 *dec_output_prop_vp9; + unsigned int dec_output_prop_vp9_size; const u32 *dec_ip_int_buf_tbl; unsigned int dec_ip_int_buf_tbl_size; const u32 *dec_op_int_buf_tbl; unsigned int dec_op_int_buf_tbl_size; + const u32 *enc_ip_int_buf_tbl; + unsigned int enc_ip_int_buf_tbl_size; + const u32 *enc_op_int_buf_tbl; + unsigned int enc_op_int_buf_tbl_size; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index 1e69ba15db0f..36d69cc73986 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025 Linaro Ltd */ #include "iris_core.h" @@ -8,16 +9,19 @@ #include "iris_hfi_gen2.h" #include "iris_hfi_gen2_defines.h" #include "iris_platform_common.h" +#include "iris_vpu_buffer.h" #include "iris_vpu_common.h" #include "iris_platform_qcs8300.h" #include "iris_platform_sm8650.h" +#include "iris_platform_sm8750.h" #define VIDEO_ARCH_LX 1 +#define BITRATE_MAX 245000000 -static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { +static struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { { - .cap_id = PROFILE, + .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | @@ -31,7 +35,29 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { .set = iris_set_u32_enum, }, { - .cap_id = LEVEL, + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | @@ -60,6 +86,60 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { .set = iris_set_u32_enum, }, { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { .cap_id = INPUT_BUF_HOST_MAX_COUNT, .min = DEFAULT_MAX_HOST_BUF_COUNT, .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, @@ -123,6 +203,393 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { }, }; +static struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen2, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_peak_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen2, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_u32, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen2, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = OUTPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, +}; + static struct platform_inst_caps platform_inst_cap_sm8550 = { .min_frame_width = 96, .max_frame_width = 8192, @@ -133,6 +600,8 @@ static struct platform_inst_caps platform_inst_cap_sm8550 = { .mb_cycles_fw = 489583, .mb_cycles_fw_vpp = 66234, .num_comv = 0, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, }; static void iris_set_sm8550_preset_registers(struct iris_core *core) @@ -181,9 +650,10 @@ static struct tz_cp_config tz_cp_config_sm8550 = { .cp_nonpixel_size = 0x24800000, }; -static const u32 sm8550_vdec_input_config_params[] = { +static const u32 sm8550_vdec_input_config_params_default[] = { HFI_PROP_BITSTREAM_RESOLUTION, HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, HFI_PROP_CODED_FRAMES, HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, HFI_PROP_PIC_ORDER_CNT_TYPE, @@ -192,20 +662,62 @@ static const u32 sm8550_vdec_input_config_params[] = { HFI_PROP_SIGNAL_COLOR_INFO, }; +static const u32 sm8550_vdec_input_config_param_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 sm8550_vdec_input_config_param_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 sm8550_venc_input_config_params[] = { + HFI_PROP_COLOR_FORMAT, + HFI_PROP_RAW_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + static const u32 sm8550_vdec_output_config_params[] = { HFI_PROP_COLOR_FORMAT, HFI_PROP_LINEAR_STRIDE_SCANLINE, }; +static const u32 sm8550_venc_output_config_params[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_FRAME_RATE, +}; + static const u32 sm8550_vdec_subscribe_input_properties[] = { HFI_PROP_NO_OUTPUT, }; -static const u32 sm8550_vdec_subscribe_output_properties[] = { +static const u32 sm8550_vdec_subscribe_output_properties_avc[] = { HFI_PROP_PICTURE_TYPE, HFI_PROP_CABAC_SESSION, }; +static const u32 sm8550_vdec_subscribe_output_properties_hevc[] = { + HFI_PROP_PICTURE_TYPE, +}; + +static const u32 sm8550_vdec_subscribe_output_properties_vp9[] = { + HFI_PROP_PICTURE_TYPE, +}; + static const u32 sm8550_dec_ip_int_buf_tbl[] = { BUF_BIN, BUF_COMV, @@ -217,10 +729,19 @@ static const u32 sm8550_dec_op_int_buf_tbl[] = { BUF_DPB, }; +static const u32 sm8550_enc_op_int_buf_tbl[] = { + BUF_BIN, + BUF_COMV, + BUF_NON_COMV, + BUF_LINE, + BUF_SCRATCH_2, +}; + struct iris_platform_data sm8550_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, .vpu_ops = &iris_vpu3_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -240,32 +761,63 @@ struct iris_platform_data sm8550_data = { .fwname = "qcom/vpu/vpu30_p4.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8550, - .inst_fw_caps = inst_fw_cap_sm8550, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, .num_vpp_pipe = 4, .max_session_count = 16, - .max_core_mbpf = ((8192 * 4352) / 256) * 2, - .input_config_params = - sm8550_vdec_input_config_params, - .input_config_params_size = - ARRAY_SIZE(sm8550_vdec_input_config_params), - .output_config_params = + .max_core_mbpf = NUM_MBS_8K * 2, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), - .dec_output_prop = sm8550_vdec_subscribe_output_properties, - .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; /* @@ -279,6 +831,7 @@ struct iris_platform_data sm8650_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu33_buf_size, .vpu_ops = &iris_vpu33_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -300,32 +853,144 @@ struct iris_platform_data sm8650_data = { .fwname = "qcom/vpu/vpu33_p4.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8550, - .inst_fw_caps = inst_fw_cap_sm8550, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K * 2, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; + +struct iris_platform_data sm8750_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu35_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8750_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8750_clk_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8750_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8750_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu35_p4.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, .num_vpp_pipe = 4, .max_session_count = 16, - .max_core_mbpf = ((8192 * 4352) / 256) * 2, - .input_config_params = - sm8550_vdec_input_config_params, - .input_config_params_size = - ARRAY_SIZE(sm8550_vdec_input_config_params), - .output_config_params = + .max_core_mbpf = NUM_MBS_8K * 2, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), - .dec_output_prop = sm8550_vdec_subscribe_output_properties, - .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; /* @@ -337,6 +1002,7 @@ struct iris_platform_data qcs8300_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, .vpu_ops = &iris_vpu3_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -356,8 +1022,10 @@ struct iris_platform_data qcs8300_data = { .fwname = "qcom/vpu/vpu30_p4_s6.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_qcs8300, - .inst_fw_caps = inst_fw_cap_qcs8300, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_qcs8300), + .inst_fw_caps_dec = inst_fw_cap_qcs8300_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_qcs8300_dec), + .inst_fw_caps_enc = inst_fw_cap_qcs8300_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_qcs8300_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, @@ -365,21 +1033,50 @@ struct iris_platform_data qcs8300_data = { .num_vpp_pipe = 2, .max_session_count = 16, .max_core_mbpf = ((4096 * 2176) / 256) * 4, - .input_config_params = - sm8550_vdec_input_config_params, - .input_config_params_size = - ARRAY_SIZE(sm8550_vdec_input_config_params), - .output_config_params = + .max_core_mbps = (((3840 * 2176) / 256) * 120), + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), - .dec_output_prop = sm8550_vdec_subscribe_output_properties, - .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index f82355d72fcf..35ea0efade73 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -3,51 +3,129 @@ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ -static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { +#define BITRATE_MAX 245000000 + +static struct platform_inst_fw_cap inst_fw_cap_qcs8300_dec[] = { { - .cap_id = PROFILE, + .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, .hfi_id = HFI_PROP_PROFILE, .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, .set = iris_set_u32_enum, }, { - .cap_id = LEVEL, + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, .hfi_id = HFI_PROP_LEVEL, .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, .set = iris_set_u32_enum, }, { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { .cap_id = INPUT_BUF_HOST_MAX_COUNT, .min = DEFAULT_MAX_HOST_BUF_COUNT, .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, @@ -111,6 +189,352 @@ static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { }, }; +static struct platform_inst_fw_cap inst_fw_cap_qcs8300_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + }, +}; + static struct platform_inst_caps platform_inst_cap_qcs8300 = { .min_frame_width = 96, .max_frame_width = 4096, @@ -121,4 +545,6 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .mb_cycles_fw = 326389, .mb_cycles_fw_vpp = 44156, .num_comv = 0, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, }; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c index 5c86fd7b7b6f..16486284f8ac 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c @@ -9,9 +9,15 @@ #include "iris_resources.h" #include "iris_hfi_gen1.h" #include "iris_hfi_gen1_defines.h" +#include "iris_vpu_buffer.h" #include "iris_vpu_common.h" -static struct platform_inst_fw_cap inst_fw_cap_sm8250[] = { +#define BITRATE_MIN 32000 +#define BITRATE_MAX 160000000 +#define BITRATE_PEAK_DEFAULT (BITRATE_DEFAULT * 2) +#define BITRATE_STEP 100 + +static struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { { .cap_id = PIPE, .min = PIPE_1, @@ -30,14 +36,199 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8250[] = { .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, .set = iris_set_stage, }, +}; + +static struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen1, + }, + { + .cap_id = BITRATE, + .min = BITRATE_MIN, + .max = BITRATE_MAX, + .step_or_mask = BITRATE_STEP, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen1, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, { - .cap_id = DEBLOCK, + .cap_id = FRAME_RC_ENABLE, .min = 0, .max = 1, .step_or_mask = 1, - .value = 0, - .hfi_id = HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER, - .set = iris_set_u32, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = (1 << 16) - 1, + .step_or_mask = 1, + .value = 30, + .set = iris_set_u32 + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen1, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MAX_QP_HEVC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, }, }; @@ -49,6 +240,8 @@ static struct platform_inst_caps platform_inst_cap_sm8250 = { .max_mbpf = 138240, .mb_cycles_vsp = 25, .mb_cycles_vpp = 200, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, }; static void iris_set_sm8250_preset_registers(struct iris_core *core) @@ -98,6 +291,14 @@ static const u32 sm8250_vdec_input_config_param_default[] = { HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE, }; +static const u32 sm8250_venc_input_config_param[] = { + HFI_PROPERTY_CONFIG_FRAME_RATE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + HFI_PROPERTY_PARAM_FRAME_SIZE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, +}; + static const u32 sm8250_dec_ip_int_buf_tbl[] = { BUF_BIN, BUF_SCRATCH_1, @@ -107,10 +308,17 @@ static const u32 sm8250_dec_op_int_buf_tbl[] = { BUF_DPB, }; +static const u32 sm8250_enc_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_SCRATCH_1, + BUF_SCRATCH_2, +}; + struct iris_platform_data sm8250_data = { .get_instance = iris_hfi_gen1_get_instance, .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, .vpu_ops = &iris_vpu2_ops, .set_preset_registers = iris_set_sm8250_preset_registers, .icc_tbl = sm8250_icc_table, @@ -130,20 +338,29 @@ struct iris_platform_data sm8250_data = { .fwname = "qcom/vpu-1.0/venus.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8250, - .inst_fw_caps = inst_fw_cap_sm8250, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8250), + .inst_fw_caps_dec = inst_fw_cap_sm8250_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), .tz_cp_config_data = &tz_cp_config_sm8250, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .num_vpp_pipe = 4, .max_session_count = 16, - .max_core_mbpf = (8192 * 4352) / 256, - .input_config_params = + .max_core_mbpf = NUM_MBS_8K, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = sm8250_vdec_input_config_param_default, - .input_config_params_size = + .dec_input_config_params_default_size = ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), }; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8750.h b/drivers/media/platform/qcom/iris/iris_platform_sm8750.h new file mode 100644 index 000000000000..719056656a5b --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8750.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Linaro Ltd + */ + +#ifndef __MEDIA_IRIS_PLATFORM_SM8750_H__ +#define __MEDIA_IRIS_PLATFORM_SM8750_H__ + +static const char * const sm8750_clk_reset_table[] = { + "bus0", "bus1", "core", "vcodec0_core" +}; + +static const struct platform_clk_data sm8750_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, + {IRIS_AXI1_CLK, "iface1" }, + {IRIS_CTRL_FREERUN_CLK, "core_freerun" }, + {IRIS_HW_FREERUN_CLK, "vcodec0_core_freerun" }, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 9a7ce142f700..00e99be16e08 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -53,7 +53,7 @@ static int iris_init_power_domains(struct iris_core *core) struct dev_pm_domain_attach_data iris_opp_pd_data = { .pd_names = core->iris_platform_data->opp_pd_tbl, .num_pd_names = core->iris_platform_data->opp_pd_tbl_size, - .pd_flags = PD_FLAG_DEV_LINK_ON, + .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, }; ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); @@ -146,7 +146,7 @@ static int iris_init_resources(struct iris_core *core) return iris_init_resets(core); } -static int iris_register_video_device(struct iris_core *core) +static int iris_register_video_device(struct iris_core *core, enum domain_type type) { struct video_device *vdev; int ret; @@ -155,19 +155,29 @@ static int iris_register_video_device(struct iris_core *core) if (!vdev) return -ENOMEM; - strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); vdev->release = video_device_release; vdev->fops = core->iris_v4l2_file_ops; - vdev->ioctl_ops = core->iris_v4l2_ioctl_ops; vdev->vfl_dir = VFL_DIR_M2M; vdev->v4l2_dev = &core->v4l2_dev; vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + if (type == DECODER) { + strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); + vdev->ioctl_ops = core->iris_v4l2_ioctl_ops_dec; + core->vdev_dec = vdev; + } else if (type == ENCODER) { + strscpy(vdev->name, "qcom-iris-encoder", sizeof(vdev->name)); + vdev->ioctl_ops = core->iris_v4l2_ioctl_ops_enc; + core->vdev_enc = vdev; + } else { + ret = -EINVAL; + goto err_vdev_release; + } + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) goto err_vdev_release; - core->vdev_dec = vdev; video_set_drvdata(vdev, core); return 0; @@ -189,6 +199,7 @@ static void iris_remove(struct platform_device *pdev) iris_core_deinit(core); video_unregister_device(core->vdev_dec); + video_unregister_device(core->vdev_enc); v4l2_device_unregister(&core->v4l2_dev); @@ -258,17 +269,21 @@ static int iris_probe(struct platform_device *pdev) if (ret) return ret; - ret = iris_register_video_device(core); + ret = iris_register_video_device(core, DECODER); if (ret) goto err_v4l2_unreg; + ret = iris_register_video_device(core, ENCODER); + if (ret) + goto err_vdev_unreg_dec; + platform_set_drvdata(pdev, core); dma_mask = core->iris_platform_data->dma_mask; ret = dma_set_mask_and_coherent(dev, dma_mask); if (ret) - goto err_vdev_unreg; + goto err_vdev_unreg_enc; dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); dma_set_seg_boundary(&pdev->dev, DMA_BIT_MASK(32)); @@ -277,11 +292,13 @@ static int iris_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(core->dev); ret = devm_pm_runtime_enable(core->dev); if (ret) - goto err_vdev_unreg; + goto err_vdev_unreg_enc; return 0; -err_vdev_unreg: +err_vdev_unreg_enc: + video_unregister_device(core->vdev_enc); +err_vdev_unreg_dec: video_unregister_device(core->vdev_dec); err_v4l2_unreg: v4l2_device_unregister(&core->v4l2_dev); @@ -353,6 +370,10 @@ static const struct of_device_id iris_dt_match[] = { .compatible = "qcom,sm8650-iris", .data = &sm8650_data, }, + { + .compatible = "qcom,sm8750-iris", + .data = &sm8750_data, + }, { }, }; MODULE_DEVICE_TABLE(of, iris_dt_match); diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c index 5976e926c83d..d14472414750 100644 --- a/drivers/media/platform/qcom/iris/iris_state.c +++ b/drivers/media/platform/qcom/iris/iris_state.c @@ -122,7 +122,8 @@ static bool iris_inst_allow_sub_state(struct iris_inst *inst, enum iris_inst_sub return false; case IRIS_INST_OUTPUT_STREAMING: if (sub_state & (IRIS_INST_SUB_DRC_LAST | - IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE)) + IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE | + IRIS_INST_SUB_LOAD_RESOURCES)) return true; return false; case IRIS_INST_STREAMING: @@ -245,13 +246,13 @@ int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane) return iris_inst_change_sub_state(inst, 0, set_sub_state); } -static inline bool iris_drc_pending(struct iris_inst *inst) +bool iris_drc_pending(struct iris_inst *inst) { return inst->sub_state & IRIS_INST_SUB_DRC && inst->sub_state & IRIS_INST_SUB_DRC_LAST; } -static inline bool iris_drain_pending(struct iris_inst *inst) +bool iris_drain_pending(struct iris_inst *inst) { return inst->sub_state & IRIS_INST_SUB_DRAIN && inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; @@ -262,11 +263,11 @@ bool iris_allow_cmd(struct iris_inst *inst, u32 cmd) struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx); struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - if (cmd == V4L2_DEC_CMD_START) { + if (cmd == V4L2_DEC_CMD_START || cmd == V4L2_ENC_CMD_START) { if (vb2_is_streaming(src_q) || vb2_is_streaming(dst_q)) if (iris_drc_pending(inst) || iris_drain_pending(inst)) return true; - } else if (cmd == V4L2_DEC_CMD_STOP) { + } else if (cmd == V4L2_DEC_CMD_STOP || cmd == V4L2_ENC_CMD_STOP) { if (vb2_is_streaming(src_q)) if (inst->sub_state != IRIS_INST_SUB_DRAIN) return true; diff --git a/drivers/media/platform/qcom/iris/iris_state.h b/drivers/media/platform/qcom/iris/iris_state.h index 78c61aac5e7e..b09fa54cf17e 100644 --- a/drivers/media/platform/qcom/iris/iris_state.h +++ b/drivers/media/platform/qcom/iris/iris_state.h @@ -140,5 +140,7 @@ int iris_inst_sub_state_change_drain_last(struct iris_inst *inst); int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane); bool iris_allow_cmd(struct iris_inst *inst, u32 cmd); +bool iris_drc_pending(struct iris_inst *inst); +bool iris_drain_pending(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c index 83c70d6a2d90..85c70a62b1fd 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.c +++ b/drivers/media/platform/qcom/iris/iris_utils.c @@ -88,3 +88,39 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id) mutex_unlock(&core->lock); return NULL; } + +int iris_check_core_mbpf(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct iris_inst *instance; + u32 total_mbpf = 0; + + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) + total_mbpf += iris_get_mbpf(instance); + mutex_unlock(&core->lock); + + if (total_mbpf > core->iris_platform_data->max_core_mbpf) + return -ENOMEM; + + return 0; +} + +int iris_check_core_mbps(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct iris_inst *instance; + u32 total_mbps = 0, fps = 0; + + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) { + fps = max(instance->frame_rate, instance->operating_rate); + total_mbps += iris_get_mbpf(instance) * fps; + } + mutex_unlock(&core->lock); + + if (total_mbps > core->iris_platform_data->max_core_mbps) + return -ENOMEM; + + return 0; +} diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h index 49869cf7a376..75740181122f 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.h +++ b/drivers/media/platform/qcom/iris/iris_utils.h @@ -49,5 +49,7 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id); void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, enum vb2_buffer_state state); int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush); +int iris_check_core_mbpf(struct iris_inst *inst); +int iris_check_core_mbps(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index cdf11feb590b..139b821f7952 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -7,28 +7,13 @@ #include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> +#include "iris_common.h" #include "iris_instance.h" #include "iris_vb2.h" #include "iris_vdec.h" +#include "iris_venc.h" #include "iris_power.h" -static int iris_check_core_mbpf(struct iris_inst *inst) -{ - struct iris_core *core = inst->core; - struct iris_inst *instance; - u32 total_mbpf = 0; - - mutex_lock(&core->lock); - list_for_each_entry(instance, &core->instances, list) - total_mbpf += iris_get_mbpf(instance); - mutex_unlock(&core->lock); - - if (total_mbpf > core->iris_platform_data->max_core_mbpf) - return -ENOMEM; - - return 0; -} - static int iris_check_inst_mbpf(struct iris_inst *inst) { struct platform_inst_caps *caps; @@ -173,9 +158,6 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) inst = vb2_get_drv_priv(q); - if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) - return 0; - mutex_lock(&inst->lock); if (inst->state == IRIS_INST_ERROR) { ret = -EBUSY; @@ -194,16 +176,35 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) goto error; - if (V4L2_TYPE_IS_OUTPUT(q->type)) - ret = iris_vdec_streamon_input(inst); - else if (V4L2_TYPE_IS_CAPTURE(q->type)) - ret = iris_vdec_streamon_output(inst); + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (inst->domain == DECODER) + ret = iris_vdec_streamon_input(inst); + else + ret = iris_venc_streamon_input(inst); + } else if (V4L2_TYPE_IS_CAPTURE(q->type)) { + if (inst->domain == DECODER) + ret = iris_vdec_streamon_output(inst); + else + ret = iris_venc_streamon_output(inst); + } if (ret) goto error; buf_type = iris_v4l2_type_to_driver(q->type); - ret = iris_queue_deferred_buffers(inst, buf_type); + if (inst->domain == DECODER) { + if (inst->state == IRIS_INST_STREAMING) + ret = iris_queue_internal_deferred_buffers(inst, BUF_DPB); + if (!ret) + ret = iris_queue_deferred_buffers(inst, buf_type); + } else { + if (inst->state == IRIS_INST_STREAMING) { + ret = iris_queue_deferred_buffers(inst, BUF_INPUT); + if (!ret) + ret = iris_queue_deferred_buffers(inst, BUF_OUTPUT); + } + } + if (ret) goto error; @@ -235,7 +236,7 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) !V4L2_TYPE_IS_CAPTURE(q->type)) goto exit; - ret = iris_vdec_session_streamoff(inst, q->type); + ret = iris_session_streamoff(inst, q->type); if (ret) goto exit; @@ -259,13 +260,14 @@ int iris_vb2_buf_prepare(struct vb2_buffer *vb) return -EINVAL; } - if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && - vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) - return -EINVAL; - if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) - return -EINVAL; - + if (!(inst->sub_state & IRIS_INST_SUB_DRC)) { + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) + return -EINVAL; + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && + vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) + return -EINVAL; + } return 0; } @@ -304,7 +306,7 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) goto exit; } - if (V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) { + if (!inst->last_buffer_dequeued && V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) { if ((inst->sub_state & IRIS_INST_SUB_DRC && inst->sub_state & IRIS_INST_SUB_DRC_LAST) || (inst->sub_state & IRIS_INST_SUB_DRAIN && @@ -318,13 +320,17 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) v4l2_event_queue_fh(&inst->fh, &eos); v4l2_m2m_mark_stopped(m2m_ctx); } + inst->last_buffer_dequeued = true; goto exit; } } v4l2_m2m_buf_queue(m2m_ctx, vbuf); - ret = iris_vdec_qbuf(inst, vbuf); + if (inst->domain == DECODER) + ret = iris_vdec_qbuf(inst, vbuf); + else + ret = iris_venc_qbuf(inst, vbuf); exit: if (ret) { 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; diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h index b24932dc511a..ec1ce55d1375 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.h +++ b/drivers/media/platform/qcom/iris/iris_vdec.h @@ -13,6 +13,7 @@ void iris_vdec_inst_deinit(struct iris_inst *inst); int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat); int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); void iris_vdec_src_change(struct iris_inst *inst); int iris_vdec_streamon_input(struct iris_inst *inst); @@ -20,6 +21,5 @@ int iris_vdec_streamon_output(struct iris_inst *inst); int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); int iris_vdec_start_cmd(struct iris_inst *inst); int iris_vdec_stop_cmd(struct iris_inst *inst); -int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c new file mode 100644 index 000000000000..099bd5ed4ae0 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_venc.c @@ -0,0 +1,579 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <media/v4l2-event.h> +#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_venc.h" +#include "iris_vpu_buffer.h" + +int iris_venc_inst_init(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct v4l2_format *f; + + inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); + inst->fmt_dst = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); + if (!inst->fmt_src || !inst->fmt_dst) { + kfree(inst->fmt_src); + kfree(inst->fmt_dst); + return -ENOMEM; + } + + f = inst->fmt_dst; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + 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_OUTPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + 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; + + f = inst->fmt_src; + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; + f->fmt.pix_mp.width = ALIGN(DEFAULT_WIDTH, 128); + f->fmt.pix_mp.height = ALIGN(DEFAULT_HEIGHT, 32); + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(DEFAULT_WIDTH, 128); + f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); + inst->buffers[BUF_INPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->crop.left = 0; + inst->crop.top = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + + inst->operating_rate = DEFAULT_FPS; + inst->frame_rate = DEFAULT_FPS; + + memcpy(&inst->fw_caps[0], &core->inst_fw_caps_enc[0], + INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); + + return iris_ctrls_init(inst); +} + +void iris_venc_inst_deinit(struct iris_inst *inst) +{ + kfree(inst->fmt_dst); + kfree(inst->fmt_src); +} + +static const struct iris_fmt iris_venc_formats[] = { + [IRIS_FMT_H264] = { + .pixfmt = V4L2_PIX_FMT_H264, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + [IRIS_FMT_HEVC] = { + .pixfmt = V4L2_PIX_FMT_HEVC, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, +}; + +static const struct iris_fmt * +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) +{ + const struct iris_fmt *fmt = iris_venc_formats; + unsigned int size = ARRAY_SIZE(iris_venc_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_venc_formats; + unsigned int size = ARRAY_SIZE(iris_venc_formats); + + if (index >= size || fmt[index].type != type) + return NULL; + + return &fmt[index]; +} + +int iris_venc_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: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_NV12; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + 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_ENC_CAP_FRAME_INTERVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + const struct iris_fmt *fmt; + struct v4l2_format *f_inst; + + 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_NV12) { + 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; + f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!fmt) { + f_inst = inst->fmt_dst; + f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; + f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; + } + break; + default: + return -EINVAL; + } + + if (pixmp->field == V4L2_FIELD_ANY) + pixmp->field = V4L2_FIELD_NONE; + + pixmp->num_planes = 1; + + return 0; +} + +static int iris_venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt; + + iris_venc_try_fmt(inst, f); + + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + return -EINVAL; + + fmt = inst->fmt_dst; + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); + + if (f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT && + f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_REC709) + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + inst->buffers[BUF_OUTPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + inst->codec = f->fmt.pix_mp.pixelformat; + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return 0; +} + +static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt, *output_fmt; + + iris_venc_try_fmt(inst, f); + + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) + return -EINVAL; + + fmt = inst->fmt_src; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); + fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(f->fmt.pix_mp.width, 128); + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); + + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + output_fmt = inst->fmt_dst; + output_fmt->fmt.pix_mp.width = fmt->fmt.pix_mp.width; + output_fmt->fmt.pix_mp.height = fmt->fmt.pix_mp.height; + output_fmt->fmt.pix_mp.colorspace = fmt->fmt.pix_mp.colorspace; + output_fmt->fmt.pix_mp.xfer_func = fmt->fmt.pix_mp.xfer_func; + output_fmt->fmt.pix_mp.ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc; + output_fmt->fmt.pix_mp.quantization = fmt->fmt.pix_mp.quantization; + + inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); + inst->buffers[BUF_INPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + if (f->fmt.pix_mp.width != inst->crop.width || + f->fmt.pix_mp.height != inst->crop.height) { + inst->crop.top = 0; + inst->crop.left = 0; + inst->crop.width = fmt->fmt.pix_mp.width; + inst->crop.height = fmt->fmt.pix_mp.height; + + iris_venc_s_fmt_output(inst, output_fmt); + } + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return 0; +} + +int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + if (!q) + return -EINVAL; + + if (vb2_is_busy(q)) + return -EBUSY; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return iris_venc_s_fmt_input(inst, f); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return iris_venc_s_fmt_output(inst, f); + default: + return -EINVAL; + } +} + +int iris_venc_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_CAPTURE_MPLANE); + if (!fmt) + return -EINVAL; + } + + return 0; +} + +int iris_venc_subscribe_event(struct iris_inst *inst, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(&inst->fh, sub, 0, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(&inst->fh, sub); + default: + return -EINVAL; + } +} + +int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s) +{ + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + + if (s->r.width > inst->fmt_src->fmt.pix_mp.width || + s->r.height > inst->fmt_src->fmt.pix_mp.height) + return -EINVAL; + + inst->crop.left = s->r.left; + inst->crop.top = s->r.top; + inst->crop.width = s->r.width; + inst->crop.height = s->r.height; + inst->fmt_dst->fmt.pix_mp.width = inst->crop.width; + inst->fmt_dst->fmt.pix_mp.height = inst->crop.height; + return iris_venc_s_fmt_output(inst, inst->fmt_dst); + default: + return -EINVAL; + } +} + +int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; + struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx); + struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + struct v4l2_fract *timeperframe = NULL; + u32 default_rate = DEFAULT_FPS; + bool is_frame_rate = false; + u64 us_per_frame, fps; + u32 max_rate; + + int ret = 0; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe = &s_parm->parm.output.timeperframe; + max_rate = caps->max_operating_rate; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe = &s_parm->parm.capture.timeperframe; + is_frame_rate = true; + max_rate = caps->max_frame_rate; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + if (!timeperframe->denominator || !timeperframe->numerator) { + if (!timeperframe->numerator) + timeperframe->numerator = 1; + if (!timeperframe->denominator) + timeperframe->denominator = default_rate; + } + + us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; + do_div(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) + return -EINVAL; + + fps = (u64)USEC_PER_SEC; + do_div(fps, us_per_frame); + if (fps > max_rate) { + ret = -ENOMEM; + goto reset_rate; + } + + if (is_frame_rate) + inst->frame_rate = (u32)fps; + else + inst->operating_rate = (u32)fps; + + if ((s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && vb2_is_streaming(src_q)) || + (s_parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && vb2_is_streaming(dst_q))) { + ret = iris_check_core_mbpf(inst); + if (ret) + goto reset_rate; + ret = iris_check_core_mbps(inst); + if (ret) + goto reset_rate; + } + + return 0; + +reset_rate: + if (ret) { + if (is_frame_rate) + inst->frame_rate = default_rate; + else + inst->operating_rate = default_rate; + } + + return ret; +} + +int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct v4l2_fract *timeperframe = NULL; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe = &s_parm->parm.output.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = inst->operating_rate; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe = &s_parm->parm.capture.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = inst->frame_rate; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + return 0; +} + +int iris_venc_streamon_input(struct iris_inst *inst) +{ + int ret; + + ret = iris_set_properties(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_ARP); + if (ret) + return ret; + + iris_get_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; + + ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + return iris_process_streamon_input(inst); +} + +int iris_venc_streamon_output(struct iris_inst *inst) +{ + int ret; + + ret = iris_set_properties(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_ARP); + if (ret) + return ret; + + iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_process_streamon_output(inst); + if (ret) + goto error; + + return ret; + +error: + iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + return ret; +} + +int iris_venc_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) +{ + struct iris_buffer *buf = to_iris_buffer(vbuf); + struct vb2_buffer *vb2 = &vbuf->vb2_buf; + struct vb2_queue *q; + int ret; + + ret = iris_vb2_buffer_to_driver(vb2, buf); + if (ret) + return ret; + + if (buf->type == BUF_INPUT) + iris_set_ts_metadata(inst, vbuf); + + q = v4l2_m2m_get_vq(inst->m2m_ctx, vb2->type); + if (!vb2_is_streaming(q)) { + buf->attr |= BUF_ATTR_DEFERRED; + return 0; + } + + iris_scale_power(inst); + + return iris_queue_buffer(inst, buf); +} + +int iris_venc_start_cmd(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + enum iris_inst_sub_state clear_sub_state = 0; + struct vb2_queue *dst_vq; + int ret; + + dst_vq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + + if (inst->sub_state & IRIS_INST_SUB_DRAIN && + inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) { + vb2_clear_last_buffer_dequeued(dst_vq); + clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; + if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + 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_OUTPUT_PAUSE) { + if (hfi_ops->session_resume_drain) { + ret = hfi_ops->session_resume_drain(inst, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + return ret; + } + clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; + } + } else { + dev_err(inst->core->dev, "start called before receiving last_flag\n"); + iris_inst_change_state(inst, IRIS_INST_ERROR); + return -EBUSY; + } + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, clear_sub_state, 0); +} + +int iris_venc_stop_cmd(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + int ret; + + ret = hfi_ops->session_drain(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_DRAIN); + + iris_scale_power(inst); + + return ret; +} diff --git a/drivers/media/platform/qcom/iris/iris_venc.h b/drivers/media/platform/qcom/iris/iris_venc.h new file mode 100644 index 000000000000..c4db7433da53 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_venc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _IRIS_VENC_H_ +#define _IRIS_VENC_H_ + +struct iris_inst; + +int iris_venc_inst_init(struct iris_inst *inst); +void iris_venc_inst_deinit(struct iris_inst *inst); +int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); +int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat); +int iris_venc_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); +int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s); +int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int iris_venc_streamon_input(struct iris_inst *inst); +int iris_venc_streamon_output(struct iris_inst *inst); +int iris_venc_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); +int iris_venc_start_cmd(struct iris_inst *inst); +int iris_venc_stop_cmd(struct iris_inst *inst); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index ca0f4e310f77..d38d0f6961cd 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -12,6 +12,7 @@ #include "iris_vidc.h" #include "iris_instance.h" #include "iris_vdec.h" +#include "iris_venc.h" #include "iris_vb2.h" #include "iris_vpu_buffer.h" #include "iris_platform_common.h" @@ -21,16 +22,19 @@ #define STEP_WIDTH 1 #define STEP_HEIGHT 1 -static void iris_v4l2_fh_init(struct iris_inst *inst) +static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) { - v4l2_fh_init(&inst->fh, inst->core->vdev_dec); + if (inst->domain == ENCODER) + v4l2_fh_init(&inst->fh, inst->core->vdev_enc); + else if (inst->domain == DECODER) + v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, filp); } -static void iris_v4l2_fh_deinit(struct iris_inst *inst) +static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) { - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, filp); inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); } @@ -67,9 +71,9 @@ static void iris_remove_session(struct iris_inst *inst) mutex_unlock(&core->lock); } -static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) +static inline struct iris_inst *iris_get_inst(struct file *filp) { - return container_of(filp->private_data, struct iris_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct iris_inst, fh); } static void iris_m2m_device_run(void *priv) @@ -126,9 +130,19 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ int iris_open(struct file *filp) { struct iris_core *core = video_drvdata(filp); + struct video_device *vdev; struct iris_inst *inst; + u32 session_type; int ret; + vdev = video_devdata(filp); + if (strcmp(vdev->name, "qcom-iris-decoder") == 0) + session_type = DECODER; + else if (strcmp(vdev->name, "qcom-iris-encoder") == 0) + session_type = ENCODER; + else + return -EINVAL; + ret = pm_runtime_resume_and_get(core->dev); if (ret < 0) return ret; @@ -147,6 +161,7 @@ int iris_open(struct file *filp) return -ENOMEM; inst->core = core; + inst->domain = session_type; inst->session_id = hash32_ptr(inst); inst->state = IRIS_INST_DEINIT; @@ -161,10 +176,12 @@ int iris_open(struct file *filp) INIT_LIST_HEAD(&inst->buffers[BUF_DPB].list); INIT_LIST_HEAD(&inst->buffers[BUF_PERSIST].list); INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_1].list); + INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_2].list); + INIT_LIST_HEAD(&inst->buffers[BUF_VPSS].list); init_completion(&inst->completion); init_completion(&inst->flush_completion); - iris_v4l2_fh_init(inst); + iris_v4l2_fh_init(inst, filp); inst->m2m_dev = v4l2_m2m_init(&iris_m2m_ops); if (IS_ERR_OR_NULL(inst->m2m_dev)) { @@ -178,14 +195,16 @@ int iris_open(struct file *filp) goto fail_m2m_release; } - ret = iris_vdec_inst_init(inst); + if (inst->domain == DECODER) + ret = iris_vdec_inst_init(inst); + else if (inst->domain == ENCODER) + ret = iris_venc_inst_init(inst); if (ret) goto fail_m2m_ctx_release; iris_add_session(inst); inst->fh.m2m_ctx = inst->m2m_ctx; - filp->private_data = &inst->fh; return 0; @@ -194,7 +213,7 @@ fail_m2m_ctx_release: fail_m2m_release: v4l2_m2m_release(inst->m2m_dev); fail_v4l2_fh_deinit: - iris_v4l2_fh_deinit(inst); + iris_v4l2_fh_deinit(inst, filp); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); @@ -221,47 +240,98 @@ static void iris_session_close(struct iris_inst *inst) iris_wait_for_session_response(inst, false); } +static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 plane) +{ + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; + struct iris_buffer *buf, *next; + struct iris_buffers *buffers; + const u32 *internal_buf_type; + u32 internal_buffer_count, i; + u32 count = 0; + + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + } + + for (i = 0; i < internal_buffer_count; i++) { + buffers = &inst->buffers[internal_buf_type[i]]; + count = 0; + list_for_each_entry_safe(buf, next, &buffers->list, list) + count++; + if (count) + dev_err(inst->core->dev, "%d buffer of type %d not released", + count, internal_buf_type[i]); + } + + if (inst->domain == DECODER) + buffers = &inst->buffers[BUF_PERSIST]; + else + buffers = &inst->buffers[BUF_ARP]; + + count = 0; + list_for_each_entry_safe(buf, next, &buffers->list, list) + count++; + if (count) + dev_err(inst->core->dev, "%d buffer of type %d not released", + count, inst->domain == DECODER ? BUF_PERSIST : BUF_ARP); +} + int iris_close(struct file *filp) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); v4l2_ctrl_handler_free(&inst->ctrl_handler); v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); mutex_lock(&inst->lock); - iris_vdec_inst_deinit(inst); + if (inst->domain == DECODER) + iris_vdec_inst_deinit(inst); + else if (inst->domain == ENCODER) + iris_venc_inst_deinit(inst); iris_session_close(inst); iris_inst_change_state(inst, IRIS_INST_DEINIT); - iris_v4l2_fh_deinit(inst); - iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + iris_v4l2_fh_deinit(inst, filp); + iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); iris_remove_session(inst); mutex_unlock(&inst->lock); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); - filp->private_data = NULL; return 0; } static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); - if (f->index) + if (inst->domain == DECODER) + return iris_vdec_enum_fmt(inst, f); + else if (inst->domain == ENCODER) + return iris_venc_enum_fmt(inst, f); + else return -EINVAL; - - return iris_vdec_enum_fmt(inst, f); } static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); - int ret; + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; mutex_lock(&inst->lock); - ret = iris_vdec_try_fmt(inst, f); + + if (inst->domain == DECODER) + ret = iris_vdec_try_fmt(inst, f); + else if (inst->domain == ENCODER) + ret = iris_venc_try_fmt(inst, f); + mutex_unlock(&inst->lock); return ret; @@ -269,11 +339,16 @@ static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_form static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); - int ret; + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; mutex_lock(&inst->lock); - ret = iris_vdec_s_fmt(inst, f); + + if (inst->domain == DECODER) + ret = iris_vdec_s_fmt(inst, f); + else if (inst->domain == ENCODER) + ret = iris_venc_s_fmt(inst, f); + mutex_unlock(&inst->lock); return ret; @@ -281,7 +356,7 @@ static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); @@ -300,15 +375,20 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_enum_framesizes(struct file *filp, void *fh, struct v4l2_frmsizeenum *fsize) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); struct platform_inst_caps *caps; + int ret = 0; if (fsize->index) return -EINVAL; - if (fsize->pixel_format != V4L2_PIX_FMT_H264 && - fsize->pixel_format != V4L2_PIX_FMT_NV12) - return -EINVAL; + if (inst->domain == DECODER) + ret = iris_vdec_validate_format(inst, fsize->pixel_format); + else + ret = iris_venc_validate_format(inst, fsize->pixel_format); + + if (ret) + return ret; caps = inst->core->iris_platform_data->inst_caps; @@ -320,55 +400,174 @@ static int iris_enum_framesizes(struct file *filp, void *fh, fsize->stepwise.max_height = caps->max_frame_height; fsize->stepwise.step_height = STEP_HEIGHT; + return ret; +} + +static int iris_enum_frameintervals(struct file *filp, void *fh, + struct v4l2_frmivalenum *fival) + +{ + struct iris_inst *inst = iris_get_inst(filp); + struct iris_core *core = inst->core; + struct platform_inst_caps *caps; + u32 fps, mbpf; + int ret = 0; + + if (inst->domain == DECODER) + return -ENOTTY; + + if (fival->index) + return -EINVAL; + + ret = iris_venc_validate_format(inst, fival->pixel_format); + if (ret) + return ret; + + if (!fival->width || !fival->height) + return -EINVAL; + + caps = inst->core->iris_platform_data->inst_caps; + if (fival->width > caps->max_frame_width || + fival->width < caps->min_frame_width || + fival->height > caps->max_frame_height || + fival->height < caps->min_frame_height) + return -EINVAL; + + mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width); + fps = DIV_ROUND_UP(core->iris_platform_data->max_core_mbps, mbpf); + + fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; + fival->stepwise.min.numerator = 1; + fival->stepwise.min.denominator = + min_t(u32, fps, MAXIMUM_FPS); + fival->stepwise.max.numerator = 1; + fival->stepwise.max.denominator = 1; + fival->stepwise.step.numerator = 1; + fival->stepwise.step.denominator = MAXIMUM_FPS; + return 0; } static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *cap) { + struct iris_inst *inst = iris_get_inst(filp); + strscpy(cap->driver, IRIS_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); + + if (inst->domain == DECODER) + strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); + else + strscpy(cap->card, "Iris Encoder", sizeof(cap->card)); return 0; } static int iris_g_selection(struct file *filp, void *fh, struct v4l2_selection *s) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + inst->domain == DECODER) return -EINVAL; - switch (s->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_PADDED: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + inst->domain == ENCODER) + return -EINVAL; + + if (inst->domain == DECODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left = inst->crop.left; + s->r.top = inst->crop.top; + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + default: + return -EINVAL; + } + } else if (inst->domain == ENCODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.width = inst->fmt_src->fmt.pix_mp.width; + s->r.height = inst->fmt_src->fmt.pix_mp.height; + break; + case V4L2_SEL_TGT_CROP: + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + default: + return -EINVAL; + } s->r.left = inst->crop.left; s->r.top = inst->crop.top; - s->r.width = inst->crop.width; - s->r.height = inst->crop.height; - break; - default: - return -EINVAL; } return 0; } +static int iris_s_selection(struct file *filp, void *fh, struct v4l2_selection *s) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (inst->domain == DECODER) + return -EINVAL; + else if (inst->domain == ENCODER) + return iris_venc_s_selection(inst, s); + + return -EINVAL; +} + static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { struct iris_inst *inst = container_of(fh, struct iris_inst, fh); - return iris_vdec_subscribe_event(inst, sub); + if (inst->domain == DECODER) + return iris_vdec_subscribe_event(inst, sub); + else if (inst->domain == ENCODER) + return iris_venc_subscribe_event(inst, sub); + + return -EINVAL; +} + +static int iris_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (inst->domain == ENCODER) + return iris_venc_s_param(inst, a); + else + return -EINVAL; +} + +static int iris_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (inst->domain == ENCODER) + return iris_venc_g_param(inst, a); + else + return -EINVAL; } static int iris_dec_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); @@ -398,6 +597,39 @@ unlock: return ret; } +static int iris_enc_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; + + mutex_lock(&inst->lock); + + ret = v4l2_m2m_ioctl_encoder_cmd(filp, fh, enc); + if (ret) + goto unlock; + + if (inst->state == IRIS_INST_DEINIT) + goto unlock; + + if (!iris_allow_cmd(inst, enc->cmd)) { + ret = -EBUSY; + goto unlock; + } + + if (enc->cmd == V4L2_ENC_CMD_START) + ret = iris_venc_start_cmd(inst); + else if (enc->cmd == V4L2_ENC_CMD_STOP) + ret = iris_venc_stop_cmd(inst); + else + ret = -EINVAL; + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + static struct v4l2_file_operations iris_v4l2_file_ops = { .owner = THIS_MODULE, .open = iris_open, @@ -417,7 +649,7 @@ static const struct vb2_ops iris_vb2_ops = { .buf_queue = iris_vb2_buf_queue, }; -static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { +static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_dec = { .vidioc_enum_fmt_vid_cap = iris_enum_fmt, .vidioc_enum_fmt_vid_out = iris_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = iris_try_fmt_vid_mplane, @@ -445,9 +677,42 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { .vidioc_decoder_cmd = iris_dec_cmd, }; +static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_enc = { + .vidioc_enum_fmt_vid_cap = iris_enum_fmt, + .vidioc_enum_fmt_vid_out = iris_enum_fmt, + .vidioc_try_fmt_vid_cap_mplane = iris_try_fmt_vid_mplane, + .vidioc_try_fmt_vid_out_mplane = iris_try_fmt_vid_mplane, + .vidioc_s_fmt_vid_cap_mplane = iris_s_fmt_vid_mplane, + .vidioc_s_fmt_vid_out_mplane = iris_s_fmt_vid_mplane, + .vidioc_g_fmt_vid_cap_mplane = iris_g_fmt_vid_mplane, + .vidioc_g_fmt_vid_out_mplane = iris_g_fmt_vid_mplane, + .vidioc_enum_framesizes = iris_enum_framesizes, + .vidioc_enum_frameintervals = iris_enum_frameintervals, + .vidioc_querycap = iris_querycap, + .vidioc_subscribe_event = iris_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_selection = iris_g_selection, + .vidioc_s_selection = iris_s_selection, + .vidioc_s_parm = iris_s_parm, + .vidioc_g_parm = iris_g_parm, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = iris_enc_cmd, +}; + void iris_init_ops(struct iris_core *core) { core->iris_v4l2_file_ops = &iris_v4l2_file_ops; core->iris_vb2_ops = &iris_vb2_ops; - core->iris_v4l2_ioctl_ops = &iris_v4l2_ioctl_ops; + core->iris_v4l2_ioctl_ops_dec = &iris_v4l2_ioctl_ops_dec; + core->iris_v4l2_ioctl_ops_enc = &iris_v4l2_ioctl_ops_enc; } diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c index 7cf1bfc352d3..de7d142316d2 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -34,6 +34,8 @@ static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) const struct vpu_ops iris_vpu2_ops = { .power_off_hw = iris_vpu_power_off_hw, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, .calc_freq = iris_vpu2_calc_freq, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c index 9b7c9a1495ee..339776a0b467 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025 Linaro Ltd */ #include <linux/iopoll.h> @@ -19,8 +20,13 @@ #define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) #define REQ_POWER_DOWN_PREP BIT(0) #define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) +#define NOC_LPI_STATUS_DONE BIT(0) /* Indicates the NOC handshake is complete */ +#define NOC_LPI_STATUS_DENY BIT(1) /* Indicates the NOC handshake is denied */ +#define NOC_LPI_STATUS_ACTIVE BIT(2) /* Indicates the NOC is active */ #define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) #define CORE_CLK_RUN 0x0 +/* VPU v3.5 */ +#define WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0 (WRAPPER_BASE_OFFS + 0x78) #define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) #define CTL_AXI_CLK_HALT BIT(0) @@ -52,6 +58,8 @@ #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) #define NOC_HALT BIT(0) #define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) { @@ -109,7 +117,9 @@ disable_power: static void iris_vpu33_power_off_hardware(struct iris_core *core) { + bool handshake_done = false, handshake_busy = false; u32 reg_val = 0, value, i; + u32 count = 0; int ret; if (iris_vpu3x_hw_power_collapsed(core)) @@ -128,13 +138,36 @@ static void iris_vpu33_power_off_hardware(struct iris_core *core) goto disable_power; } + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + udelay(15); + + value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS); + + handshake_done = value & NOC_LPI_STATUS_DONE; + handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + udelay(15); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, reg_val, reg_val & BIT(0), 200, 2000); if (ret) goto disable_power; - /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ - writel(BIT(0), core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); @@ -225,6 +258,158 @@ disable_power: return 0; } +static int iris_vpu35_power_on_hw(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK); + if (ret) + goto err_disable_axi_clk; + + ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); + if (ret) + goto err_disable_hw_free_clk; + + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); + if (ret) + goto err_disable_hw_clk; + + return 0; + +err_disable_hw_clk: + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +err_disable_hw_free_clk: + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); +err_disable_axi_clk: + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu35_power_off_hw(struct iris_core *core) +{ + iris_vpu33_power_off_hardware(core); + + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +} + +static int iris_vpu35_power_off_controller(struct iris_core *core) +{ + u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + unsigned int count = 0; + u32 val = 0; + bool handshake_done, handshake_busy; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + udelay(15); + + val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); + + handshake_done = val & NOC_LPI_STATUS_DONE; + handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + udelay(15); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 0, 200, 2000); + if (ret) + goto disable_power; + +disable_power: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); + + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + reset_control_bulk_reset(clk_rst_tbl_size, core->resets); + + return 0; +} + +static int iris_vpu35_power_on_controller(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); + if (ret) + goto err_disable_axi1_clk; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (ret) + goto err_disable_ctrl_free_clk; + + return 0; + +err_disable_ctrl_free_clk: + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); +err_disable_axi1_clk: + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu35_program_bootup_registers(struct iris_core *core) +{ + writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); +} + static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_size) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; @@ -264,12 +449,25 @@ static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_si const struct vpu_ops iris_vpu3_ops = { .power_off_hw = iris_vpu3_power_off_hardware, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, .calc_freq = iris_vpu3x_calculate_frequency, }; const struct vpu_ops iris_vpu33_ops = { .power_off_hw = iris_vpu33_power_off_hardware, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu33_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, + .calc_freq = iris_vpu3x_calculate_frequency, +}; + +const struct vpu_ops iris_vpu35_ops = { + .power_off_hw = iris_vpu35_power_off_hw, + .power_on_hw = iris_vpu35_power_on_hw, + .power_off_controller = iris_vpu35_power_off_controller, + .power_on_controller = iris_vpu35_power_on_controller, + .program_bootup_registers = iris_vpu35_program_bootup_registers, .calc_freq = iris_vpu3x_calculate_frequency, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index dce25e410d80..4463be05ce16 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -5,6 +5,14 @@ #include "iris_instance.h" #include "iris_vpu_buffer.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_hfi_gen2_defines.h" + +#define HFI_MAX_COL_FRAME 6 + +#ifndef SYSTEM_LAL_TILE10 +#define SYSTEM_LAL_TILE10 192 +#endif static u32 size_h264d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) { @@ -31,6 +39,42 @@ static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_p return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); } +static u32 size_h265d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + u32 product = frame_width * frame_height; + u32 size_yuv, size_bin_hdr, size_bin_res; + + size_yuv = (product <= BIN_BUFFER_THRESHOLD) ? + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : ((product * 3) >> 1); + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; + size_bin_hdr = ALIGN(size_bin_hdr / num_vpp_pipes, DMA_ALIGNMENT) * num_vpp_pipes; + size_bin_res = ALIGN(size_bin_res / num_vpp_pipes, DMA_ALIGNMENT) * num_vpp_pipes; + + return size_bin_hdr + size_bin_res; +} + +static u32 hfi_buffer_bin_vp9d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + u32 _size_yuv = ALIGN(frame_width, 16) * ALIGN(frame_height, 16) * 3 / 2; + u32 _size = ALIGN(((max_t(u32, _size_yuv, ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * + VPX_DECODER_FRAME_BIN_HDR_BUDGET / VPX_DECODER_FRAME_BIN_DENOMINATOR * + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), DMA_ALIGNMENT) + + ALIGN(((max_t(u32, _size_yuv, ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * + VPX_DECODER_FRAME_BIN_RES_BUDGET / VPX_DECODER_FRAME_BIN_DENOMINATOR * + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), DMA_ALIGNMENT); + + return _size * num_vpp_pipes; +} + +static u32 hfi_buffer_bin_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + u32 n_aligned_w = ALIGN(frame_width, 16); + u32 n_aligned_h = ALIGN(frame_height, 16); + + return size_h265d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); +} + static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) { u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16); @@ -55,6 +99,17 @@ static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bu return (size_colloc * (_comv_bufcount)) + 512; } +static u32 hfi_buffer_comv_h265d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) +{ + u32 frame_height_in_mbs = (frame_height + 15) >> 4; + u32 frame_width_in_mbs = (frame_width + 15) >> 4; + u32 _size; + + _size = ALIGN(((frame_width_in_mbs * frame_height_in_mbs) << 8), 512); + + return (_size * (_comv_bufcount)) + 512; +} + static u32 size_h264d_bse_cmd_buf(u32 frame_height) { u32 height = ALIGN(frame_height, 32); @@ -63,6 +118,44 @@ static u32 size_h264d_bse_cmd_buf(u32 frame_height) SIZE_H264D_BSE_CMD_PER_BUF; } +static u32 size_h265d_bse_cmd_buf(u32 frame_width, u32 frame_height) +{ + u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * + NUM_HW_PIC_BUF, DMA_ALIGNMENT); + _size = min_t(u32, _size, H265D_MAX_SLICE + 1); + _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; + + return _size; +} + +static u32 hfi_buffer_persist_h265d(u32 rpu_enabled) +{ + return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + + H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + + H265_NUM_TILE * sizeof(u32) + + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), + DMA_ALIGNMENT); +} + +static inline +u32 hfi_iris3_vp9d_comv_size(void) +{ + return (((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8); +} + +static u32 hfi_buffer_persist_vp9d(void) +{ + return ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, DMA_ALIGNMENT) + + ALIGN(hfi_iris3_vp9d_comv_size(), DMA_ALIGNMENT) + + ALIGN(MAX_SUPERFRAME_HEADER_LEN, DMA_ALIGNMENT) + + ALIGN(VP9_UDC_HEADER_BUF_SIZE, DMA_ALIGNMENT) + + ALIGN(VP9_NUM_FRAME_INFO_BUF * CCE_TILE_OFFSET_SIZE, DMA_ALIGNMENT) + + ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, DMA_ALIGNMENT) + + HDR10_HIST_EXTRADATA_SIZE; +} + static u32 size_h264d_vpp_cmd_buf(u32 frame_height) { u32 size, height = ALIGN(frame_height, 32); @@ -83,17 +176,45 @@ static u32 hfi_buffer_persist_h264d(void) static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) { - u32 size_bse, size_vpp, size; - - size_bse = size_h264d_bse_cmd_buf(frame_height); - size_vpp = size_h264d_vpp_cmd_buf(frame_height); - size = ALIGN(size_bse, DMA_ALIGNMENT) + + u32 size_bse = size_h264d_bse_cmd_buf(frame_height); + u32 size_vpp = size_h264d_vpp_cmd_buf(frame_height); + u32 size = ALIGN(size_bse, DMA_ALIGNMENT) + ALIGN(size_vpp, DMA_ALIGNMENT) + ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT); return ALIGN(size, DMA_ALIGNMENT); } +static u32 size_h265d_vpp_cmd_buf(u32 frame_width, u32 frame_height) +{ + u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * + NUM_HW_PIC_BUF, DMA_ALIGNMENT); + _size = min_t(u32, _size, H265D_MAX_SLICE + 1); + _size = ALIGN(_size, 4); + _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; + if (_size > VPP_CMD_MAX_SIZE) + _size = VPP_CMD_MAX_SIZE; + + return _size; +} + +static u32 hfi_buffer_non_comv_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + u32 _size_bse = size_h265d_bse_cmd_buf(frame_width, frame_height); + u32 _size_vpp = size_h265d_vpp_cmd_buf(frame_width, frame_height); + u32 _size = ALIGN(_size_bse, DMA_ALIGNMENT) + + ALIGN(_size_vpp, DMA_ALIGNMENT) + + ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, DMA_ALIGNMENT) + + ALIGN(2 * sizeof(u16) * + (ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), DMA_ALIGNMENT) + + ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), DMA_ALIGNMENT) + + HDR10_HIST_EXTRADATA_SIZE; + + return ALIGN(_size, DMA_ALIGNMENT); +} + static u32 size_vpss_lb(u32 frame_width, u32 frame_height) { u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size; @@ -119,6 +240,203 @@ static u32 size_vpss_lb(u32 frame_width, u32 frame_height) opb_lb_wr_llb_y_buffer_size; } +static inline +u32 size_h265d_lb_fe_top_data(u32 frame_width, u32 frame_height) +{ + return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * + (ALIGN(frame_width, 64) + 8) * 2; +} + +static inline +u32 size_h265d_lb_fe_top_ctrl(u32 frame_width, u32 frame_height) +{ + return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * + (ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS); +} + +static inline +u32 size_h265d_lb_fe_left_ctrl(u32 frame_width, u32 frame_height) +{ + return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS); +} + +static inline +u32 size_h265d_lb_se_top_ctrl(u32 frame_width, u32 frame_height) +{ + return (LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4); +} + +static inline +u32 size_h265d_lb_se_left_ctrl(u32 frame_width, u32 frame_height) +{ + return max_t(u32, ((frame_height + 16 - 1) / 8) * + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, + max_t(u32, ((frame_height + 32 - 1) / 8) * + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, + ((frame_height + 64 - 1) / 8) * + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); +} + +static inline +u32 size_h265d_lb_pe_top_data(u32 frame_width, u32 frame_height) +{ + return MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * + (ALIGN(frame_width, LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS); +} + +static inline +u32 size_h265d_lb_vsp_top(u32 frame_width, u32 frame_height) +{ + return ((frame_width + 63) >> 6) * 128; +} + +static inline +u32 size_h265d_lb_vsp_left(u32 frame_width, u32 frame_height) +{ + return ((frame_height + 63) >> 6) * 128; +} + +static inline +u32 size_h265d_lb_recon_dma_metadata_wr(u32 frame_width, u32 frame_height) +{ + return size_h264d_lb_recon_dma_metadata_wr(frame_height); +} + +static inline +u32 size_h265d_qp(u32 frame_width, u32 frame_height) +{ + return size_h264d_qp(frame_width, frame_height); +} + +static inline +u32 hfi_buffer_line_h265d(u32 frame_width, u32 frame_height, bool is_opb, u32 num_vpp_pipes) +{ + u32 vpss_lb_size = 0, _size; + + _size = ALIGN(size_h265d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_h265d_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_h265d_lb_fe_left_ctrl(frame_width, frame_height), + DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(size_h265d_lb_se_left_ctrl(frame_width, frame_height), + DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(size_h265d_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_h265d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_h265d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_h265d_lb_vsp_left(frame_width, frame_height), + DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(size_h265d_lb_recon_dma_metadata_wr(frame_width, frame_height), + DMA_ALIGNMENT) * 4 + + ALIGN(size_h265d_qp(frame_width, frame_height), DMA_ALIGNMENT); + if (is_opb) + vpss_lb_size = size_vpss_lb(frame_width, frame_height); + + return ALIGN((_size + vpss_lb_size), DMA_ALIGNMENT); +} + +static inline +u32 size_vpxd_lb_fe_left_ctrl(u32 frame_width, u32 frame_height) +{ + return max_t(u32, ((frame_height + 15) >> 4) * + MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, + max_t(u32, ((frame_height + 31) >> 5) * + MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, + ((frame_height + 63) >> 6) * + MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); +} + +static inline +u32 size_vpxd_lb_fe_top_ctrl(u32 frame_width, u32 frame_height) +{ + return ((ALIGN(frame_width, 64) + 8) * 10 * 2); +} + +static inline +u32 size_vpxd_lb_se_top_ctrl(u32 frame_width, u32 frame_height) +{ + return ((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE; +} + +static inline +u32 size_vpxd_lb_se_left_ctrl(u32 frame_width, u32 frame_height) +{ + return max_t(u32, ((frame_height + 15) >> 4) * + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, + max_t(u32, ((frame_height + 31) >> 5) * + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, + ((frame_height + 63) >> 6) * + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); +} + +static inline +u32 size_vpxd_lb_recon_dma_metadata_wr(u32 frame_width, u32 frame_height) +{ + return ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, + BUFFER_ALIGNMENT_32_BYTES); +} + +static inline __maybe_unused +u32 size_mp2d_lb_fe_top_data(u32 frame_width, u32 frame_height) +{ + return ((ALIGN(frame_width, 16) + 8) * 10 * 2); +} + +static inline +u32 size_vp9d_lb_fe_top_data(u32 frame_width, u32 frame_height) +{ + return (ALIGN(ALIGN(frame_width, 8), 64) + 8) * 10 * 2; +} + +static inline +u32 size_vp9d_lb_pe_top_data(u32 frame_width, u32 frame_height) +{ + return ((ALIGN(ALIGN(frame_width, 8), 64) >> 6) * 176); +} + +static inline +u32 size_vp9d_lb_vsp_top(u32 frame_width, u32 frame_height) +{ + return (((ALIGN(ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256); +} + +static inline +u32 size_vp9d_qp(u32 frame_width, u32 frame_height) +{ + return size_h264d_qp(frame_width, frame_height); +} + +static inline +u32 hfi_iris3_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) +{ + return ALIGN(size_vpxd_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) * + num_vpp_pipes + + ALIGN(size_vpxd_lb_se_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) * + num_vpp_pipes + + ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_vpxd_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + + 2 * ALIGN(size_vpxd_lb_recon_dma_metadata_wr(frame_width, frame_height), + DMA_ALIGNMENT) + + ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_vp9d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_vp9d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + + ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT); +} + +static inline +u32 hfi_buffer_line_vp9d(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min, bool is_opb, + u32 num_vpp_pipes) +{ + u32 vpss_lb_size = 0; + u32 _lb_size; + + _lb_size = hfi_iris3_vp9d_lb_size(frame_width, frame_height, num_vpp_pipes); + + if (is_opb) + vpss_lb_size = size_vpss_lb(frame_width, frame_height); + + return _lb_size + vpss_lb_size + 4096; +} + static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height, bool is_opb, u32 num_vpp_pipes) { @@ -148,7 +466,14 @@ static u32 iris_vpu_dec_bin_size(struct iris_inst *inst) u32 height = f->fmt.pix_mp.height; u32 width = f->fmt.pix_mp.width; - return hfi_buffer_bin_h264d(width, height, num_vpp_pipes); + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_bin_h264d(width, height, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_bin_h265d(width, height, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_VP9) + return hfi_buffer_bin_vp9d(width, height, num_vpp_pipes); + + return 0; } static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) @@ -158,12 +483,24 @@ static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) u32 height = f->fmt.pix_mp.height; u32 width = f->fmt.pix_mp.width; - return hfi_buffer_comv_h264d(width, height, num_comv); + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_comv_h264d(width, height, num_comv); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_comv_h265d(width, height, num_comv); + + return 0; } static u32 iris_vpu_dec_persist_size(struct iris_inst *inst) { - return hfi_buffer_persist_h264d(); + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_persist_h264d(); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_persist_h265d(0); + else if (inst->codec == V4L2_PIX_FMT_VP9) + return hfi_buffer_persist_vp9d(); + + return 0; } static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst) @@ -181,7 +518,12 @@ static u32 iris_vpu_dec_non_comv_size(struct iris_inst *inst) u32 height = f->fmt.pix_mp.height; u32 width = f->fmt.pix_mp.width; - return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes); + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_non_comv_h265d(width, height, num_vpp_pipes); + + return 0; } static u32 iris_vpu_dec_line_size(struct iris_inst *inst) @@ -191,11 +533,20 @@ static u32 iris_vpu_dec_line_size(struct iris_inst *inst) u32 height = f->fmt.pix_mp.height; u32 width = f->fmt.pix_mp.width; bool is_opb = false; + u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count; if (iris_split_mode_enabled(inst)) is_opb = true; - return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); + if (inst->codec == V4L2_PIX_FMT_H264) + return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_HEVC) + return hfi_buffer_line_h265d(width, height, is_opb, num_vpp_pipes); + else if (inst->codec == V4L2_PIX_FMT_VP9) + return hfi_buffer_line_vp9d(width, height, out_min_count, is_opb, + num_vpp_pipes); + + return 0; } static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) @@ -205,15 +556,885 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) iris_vpu_dec_line_size(inst); } +static inline u32 size_bin_bitstream_enc(u32 width, u32 height, + u32 rc_type) +{ + u32 aligned_height = ALIGN(height, 32); + u32 aligned_width = ALIGN(width, 32); + u32 frame_size = width * height * 3; + u32 mbs_per_frame; + + /* + * Encoder output size calculation: 32 Align width/height + * For resolution < 720p : YUVsize * 4 + * For resolution > 720p & <= 4K : YUVsize / 2 + * For resolution > 4k : YUVsize / 4 + * Initially frame_size = YUVsize * 2; + */ + + mbs_per_frame = (ALIGN(aligned_height, 16) * ALIGN(aligned_width, 16)) / 256; + + if (mbs_per_frame < NUM_MBS_720P) + frame_size = frame_size << 1; + else if (mbs_per_frame <= NUM_MBS_4K) + frame_size = frame_size >> 2; + else + frame_size = frame_size >> 3; + + if (rc_type == HFI_RATE_CONTROL_OFF || rc_type == HFI_RATE_CONTROL_CQ || + rc_type == HFI_RC_OFF || rc_type == HFI_RC_CQ) + frame_size = frame_size << 1; + + /* + * In case of opaque color format bitdepth will be known + * with first ETB, buffers allocated already with 8 bit + * won't be sufficient for 10 bit + * calculate size considering 10-bit by default + * For 10-bit cases size = size * 1.25 + */ + frame_size *= 5; + frame_size /= 4; + + return ALIGN(frame_size, SZ_4K); +} + +static inline u32 hfi_buffer_bin_enc(u32 width, u32 height, + u32 work_mode, u32 lcu_size, + u32 num_vpp_pipes, u32 rc_type) +{ + u32 sao_bin_buffer_size, padded_bin_size, bitstream_size; + u32 total_bitbin_buffers, size_single_pipe, bitbin_size; + u32 aligned_height = ALIGN(height, lcu_size); + u32 aligned_width = ALIGN(width, lcu_size); + + bitstream_size = size_bin_bitstream_enc(width, height, rc_type); + bitstream_size = ALIGN(bitstream_size, 256); + + if (work_mode == STAGE_2) { + total_bitbin_buffers = 3; + bitbin_size = bitstream_size * 17 / 10; + bitbin_size = ALIGN(bitbin_size, 256); + } else { + total_bitbin_buffers = 1; + bitstream_size = aligned_width * aligned_height * 3; + bitbin_size = ALIGN(bitstream_size, 256); + } + + if (num_vpp_pipes > 2) + size_single_pipe = bitbin_size / 2; + else + size_single_pipe = bitbin_size; + + size_single_pipe = ALIGN(size_single_pipe, 256); + sao_bin_buffer_size = (64 * (((width + 32) * (height + 32)) >> 10)) + 384; + padded_bin_size = ALIGN(size_single_pipe, 256); + size_single_pipe = sao_bin_buffer_size + padded_bin_size; + size_single_pipe = ALIGN(size_single_pipe, 256); + bitbin_size = size_single_pipe * num_vpp_pipes; + + return ALIGN(bitbin_size, 256) * total_bitbin_buffers + 512; +} + +static u32 iris_vpu_enc_bin_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + u32 stage = inst->fw_caps[STAGE].value; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size; + + if (inst->codec == V4L2_PIX_FMT_HEVC) + lcu_size = 32; + else + lcu_size = 16; + + return hfi_buffer_bin_enc(width, height, stage, lcu_size, + num_vpp_pipes, inst->hfi_rc_type); +} + +static inline +u32 hfi_buffer_comv_enc(u32 frame_width, u32 frame_height, u32 lcu_size, + u32 num_recon, u32 standard) +{ + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 num_lcu_in_frame = width_in_lcus * height_in_lcus; + u32 mb_height = ((frame_height) + 15) >> 4; + u32 mb_width = ((frame_width) + 15) >> 4; + u32 size_colloc_mv, size_colloc_rc; + + size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? + (16 * ((num_lcu_in_frame << 2) + 32)) : + (3 * 16 * (width_in_lcus * height_in_lcus + 32)); + size_colloc_mv = ALIGN(size_colloc_mv, 256) * num_recon; + size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); + size_colloc_rc = ALIGN(size_colloc_rc, 256) * HFI_MAX_COL_FRAME; + + return size_colloc_mv + size_colloc_rc; +} + +static u32 iris_vpu_enc_comv_size(struct iris_inst *inst) +{ + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 num_recon = 1; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 size_frame_rc_buf_size(u32 standard, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + u32 size = 0; + + size = (standard == HFI_CODEC_ENCODE_HEVC) ? + (256 + 16 * (14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : + (256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); + size *= 11; + + if (num_vpp_pipes_enc > 1) + size = ALIGN(size, 256) * num_vpp_pipes_enc; + + return ALIGN(size, 512) * HFI_MAX_COL_FRAME; +} + +static inline +u32 size_enc_slice_info_buf(u32 num_lcu_in_frame) +{ + return ALIGN((256 + (num_lcu_in_frame << 4)), 256); +} + +static inline u32 enc_bitcnt_buf_size(u32 num_lcu_in_frame) +{ + return ALIGN((256 + (4 * (num_lcu_in_frame))), 256); +} + +static inline u32 enc_bitmap_buf_size(u32 num_lcu_in_frame) +{ + return ALIGN((256 + ((num_lcu_in_frame) >> 3)), 256); +} + +static inline u32 size_override_buf(u32 num_lcumb) +{ + return ALIGN(((16 * (((num_lcumb) + 7) >> 3))), 256) * 2; +} + +static inline u32 size_ir_buf(u32 num_lcu_in_frame) +{ + return ALIGN((((((num_lcu_in_frame) << 1) + 7) & (~7)) * 3), 256); +} + +static inline +u32 size_linebuff_data(bool is_ten_bit, u32 frame_width_coded) +{ + return is_ten_bit ? + (((((10 * (frame_width_coded) + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((10 * (frame_width_coded) + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)) : + (((((8 * (frame_width_coded) + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((8 * (frame_width_coded) + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)); +} + +static inline +u32 size_left_linebuff_ctrl(u32 standard, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + u32 size = 0; + + size = standard == HFI_CODEC_ENCODE_HEVC ? + (((frame_height_coded) + + (32)) / 32 * 4 * 16) : + (((frame_height_coded) + 15) / 16 * 5 * 16); + + if ((num_vpp_pipes_enc) > 1) { + size += 512; + size = ALIGN(size, 512) * + num_vpp_pipes_enc; + } + + return ALIGN(size, 256); +} + +static inline +u32 size_left_linebuff_recon_pix(bool is_ten_bit, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + return (((is_ten_bit + 1) * 2 * (frame_height_coded) + 256) + + (256 << (num_vpp_pipes_enc - 1)) - 1) & + (~((256 << (num_vpp_pipes_enc - 1)) - 1)) * 1; +} + +static inline +u32 size_top_linebuff_ctrl_fe(u32 frame_width_coded, u32 standard) +{ + return standard == HFI_CODEC_ENCODE_HEVC ? + ALIGN((64 * ((frame_width_coded) >> 5)), 256) : + ALIGN((256 + 16 * ((frame_width_coded) >> 4)), 256); +} + +static inline +u32 size_left_linebuff_ctrl_fe(u32 frame_height_coded, u32 num_vpp_pipes_enc) +{ + return (((256 + 64 * ((frame_height_coded) >> 4)) + + (256 << (num_vpp_pipes_enc - 1)) - 1) & + (~((256 << (num_vpp_pipes_enc - 1)) - 1)) * 1) * + num_vpp_pipes_enc; +} + +static inline +u32 size_left_linebuff_metadata_recon_y(u32 frame_height_coded, + bool is_ten_bit, + u32 num_vpp_pipes_enc) +{ + return ALIGN(((256 + 64 * ((frame_height_coded) / + (8 * (is_ten_bit ? 4 : 8))))), 256) * num_vpp_pipes_enc; +} + +static inline +u32 size_left_linebuff_metadata_recon_uv(u32 frame_height_coded, + bool is_ten_bit, + u32 num_vpp_pipes_enc) +{ + return ALIGN(((256 + 64 * ((frame_height_coded) / + (4 * (is_ten_bit ? 4 : 8))))), 256) * num_vpp_pipes_enc; +} + +static inline +u32 size_linebuff_recon_pix(bool is_ten_bit, u32 frame_width_coded) +{ + return ALIGN(((is_ten_bit ? 3 : 2) * (frame_width_coded)), 256); +} + +static inline +u32 size_line_buf_ctrl(u32 frame_width_coded) +{ + return ALIGN(frame_width_coded, 256); +} + +static inline +u32 size_line_buf_ctrl_id2(u32 frame_width_coded) +{ + return ALIGN(frame_width_coded, 256); +} + +static inline u32 size_line_buf_sde(u32 frame_width_coded) +{ + return ALIGN((256 + (16 * ((frame_width_coded) >> 4))), 256); +} + +static inline +u32 size_vpss_line_buf(u32 num_vpp_pipes_enc, u32 frame_height_coded, + u32 frame_width_coded) +{ + return ALIGN(((((((8192) >> 2) << 5) * (num_vpp_pipes_enc)) + 64) + + (((((max_t(u32, (frame_width_coded), + (frame_height_coded)) + 3) >> 2) << 5) + 256) * 16)), 256); +} +static inline +u32 size_vpss_line_buf_vpu33(u32 num_vpp_pipes_enc, u32 frame_height_coded, + u32 frame_width_coded) +{ + u32 vpss_4tap_top, vpss_4tap_left, vpss_div2_top; + u32 vpss_div2_left, vpss_top_lb, vpss_left_lb; + u32 size_left, size_top; + u32 max_width_height; + + max_width_height = max_t(u32, frame_width_coded, frame_height_coded); + vpss_4tap_top = ((((max_width_height * 2) + 3) >> 2) << 4) + 256; + vpss_4tap_left = (((8192 + 3) >> 2) << 5) + 64; + vpss_div2_top = (((max_width_height + 3) >> 2) << 4) + 256; + vpss_div2_left = ((((max_width_height * 2) + 3) >> 2) << 5) + 64; + vpss_top_lb = (frame_width_coded + 1) << 3; + vpss_left_lb = (frame_height_coded << 3) * num_vpp_pipes_enc; + size_left = (vpss_4tap_left + vpss_div2_left) * 2 * num_vpp_pipes_enc; + size_top = (vpss_4tap_top + vpss_div2_top) * 2; + + return ALIGN(size_left + size_top + vpss_top_lb + vpss_left_lb, DMA_ALIGNMENT); +} + +static inline +u32 size_top_line_buf_first_stg_sao(u32 frame_width_coded) +{ + return ALIGN((16 * ((frame_width_coded) >> 5)), 256); +} + +static inline +u32 size_enc_ref_buffer(u32 frame_width, u32 frame_height) +{ + u32 u_chroma_buffer_height = ALIGN(frame_height >> 1, 32); + u32 u_buffer_height = ALIGN(frame_height, 32); + u32 u_buffer_width = ALIGN(frame_width, 32); + + return (u_buffer_height + u_chroma_buffer_height) * u_buffer_width; +} + +static inline +u32 size_enc_ten_bit_ref_buffer(u32 frame_width, u32 frame_height) +{ + u32 ref_luma_stride_in_bytes = ((frame_width + SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * + SYSTEM_LAL_TILE10; + u32 ref_buf_height = (frame_height + (32 - 1)) & (~(32 - 1)); + u32 u_ref_stride, luma_size; + u32 ref_chrm_height_in_bytes; + u32 chroma_size; + + u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); + u_ref_stride = (u_ref_stride + (128 - 1)) & (~(128 - 1)); + luma_size = ref_buf_height * u_ref_stride; + luma_size = (luma_size + (4096 - 1)) & (~(4096 - 1)); + + ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + (32 - 1)) & (~(32 - 1)); + chroma_size = u_ref_stride * ref_chrm_height_in_bytes; + chroma_size = (chroma_size + (4096 - 1)) & (~(4096 - 1)); + + return luma_size + chroma_size; +} + +static inline +u32 hfi_ubwc_calc_metadata_plane_stride(u32 frame_width, + u32 metadata_stride_multiple, + u32 tile_width_in_pels) +{ + return ALIGN(((frame_width + (tile_width_in_pels - 1)) / tile_width_in_pels), + metadata_stride_multiple); +} + +static inline +u32 hfi_ubwc_metadata_plane_bufheight(u32 frame_height, + u32 metadata_height_multiple, + u32 tile_height_in_pels) +{ + return ALIGN(((frame_height + (tile_height_in_pels - 1)) / tile_height_in_pels), + metadata_height_multiple); +} + +static inline +u32 hfi_ubwc_metadata_plane_buffer_size(u32 _metadata_tride, u32 _metadata_buf_height) +{ + return ALIGN(_metadata_tride * _metadata_buf_height, 4096); +} + +static inline +u32 hfi_buffer_non_comv_enc(u32 frame_width, u32 frame_height, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 num_lcu_in_frame = width_in_lcus * height_in_lcus; + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + u32 num_lcumb, frame_rc_buf_size; + + num_lcumb = (frame_height_coded / lcu_size) * + ((frame_width_coded + lcu_size * 8) / lcu_size); + frame_rc_buf_size = size_frame_rc_buf_size(standard, frame_height_coded, + num_vpp_pipes_enc); + return size_enc_slice_info_buf(num_lcu_in_frame) + + SIZE_SLICE_CMD_BUFFER + + SIZE_SPS_PPS_SLICE_HDR + + frame_rc_buf_size + + enc_bitcnt_buf_size(num_lcu_in_frame) + + enc_bitmap_buf_size(num_lcu_in_frame) + + SIZE_BSE_SLICE_CMD_BUF + + SIZE_LAMBDA_LUT + + size_override_buf(num_lcumb) + + size_ir_buf(num_lcu_in_frame); +} + +static u32 iris_vpu_enc_non_comv_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_non_comv_enc(width, height, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC) + + SIZE_ONE_SLICE_BUF; + } + + return hfi_buffer_non_comv_enc(width, height, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 hfi_buffer_line_enc_base(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + u32 line_buff_data_size, left_line_buff_ctrl_size; + u32 left_line_buff_metadata_recon__uv__size; + u32 left_line_buff_metadata_recon__y__size; + u32 left_line_buff_recon_pix_size; + u32 top_line_buff_ctrl_fe_size; + u32 line_buff_recon_pix_size; + + line_buff_data_size = size_linebuff_data(is_ten_bit, frame_width_coded); + left_line_buff_ctrl_size = + size_left_linebuff_ctrl(standard, frame_height_coded, num_vpp_pipes_enc); + left_line_buff_recon_pix_size = + size_left_linebuff_recon_pix(is_ten_bit, frame_height_coded, + num_vpp_pipes_enc); + top_line_buff_ctrl_fe_size = + size_top_linebuff_ctrl_fe(frame_width_coded, standard); + left_line_buff_metadata_recon__y__size = + size_left_linebuff_metadata_recon_y(frame_height_coded, is_ten_bit, + num_vpp_pipes_enc); + left_line_buff_metadata_recon__uv__size = + size_left_linebuff_metadata_recon_uv(frame_height_coded, is_ten_bit, + num_vpp_pipes_enc); + line_buff_recon_pix_size = size_linebuff_recon_pix(is_ten_bit, frame_width_coded); + + return size_line_buf_ctrl(frame_width_coded) + + size_line_buf_ctrl_id2(frame_width_coded) + + line_buff_data_size + + left_line_buff_ctrl_size + + left_line_buff_recon_pix_size + + top_line_buff_ctrl_fe_size + + left_line_buff_metadata_recon__y__size + + left_line_buff_metadata_recon__uv__size + + line_buff_recon_pix_size + + size_left_linebuff_ctrl_fe(frame_height_coded, num_vpp_pipes_enc) + + size_line_buf_sde(frame_width_coded) + + size_top_line_buf_first_stg_sao(frame_width_coded); +} + +static inline +u32 hfi_buffer_line_enc(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + + return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, + num_vpp_pipes_enc, lcu_size, standard) + + size_vpss_line_buf(num_vpp_pipes_enc, frame_height_coded, frame_width_coded); +} + +static inline +u32 hfi_buffer_line_enc_vpu33(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + + return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, + num_vpp_pipes_enc, lcu_size, standard) + + size_vpss_line_buf_vpu33(num_vpp_pipes_enc, frame_height_coded, + frame_width_coded); +} + +static u32 iris_vpu_enc_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_line_enc(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_line_enc(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static u32 iris_vpu33_enc_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 hfi_buffer_dpb_enc(u32 frame_width, u32 frame_height, bool is_ten_bit) +{ + u32 metadata_stride, metadata_buf_height, meta_size_y, meta_size_c; + u32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; + u32 size; + + if (!is_ten_bit) { + ref_buf_size = size_enc_ref_buffer(frame_width, frame_height); + metadata_stride = + hfi_ubwc_calc_metadata_plane_stride(frame_width, 64, + HFI_COL_FMT_NV12C_Y_TILE_WIDTH); + metadata_buf_height = + hfi_ubwc_metadata_plane_bufheight(frame_height, 16, + HFI_COL_FMT_NV12C_Y_TILE_HEIGHT); + meta_size_y = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + meta_size_c = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + size = ref_buf_size + meta_size_y + meta_size_c; + } else { + ten_bit_ref_buf_size = size_enc_ten_bit_ref_buffer(frame_width, frame_height); + metadata_stride = + hfi_ubwc_calc_metadata_plane_stride(frame_width, + IRIS_METADATA_STRIDE_MULTIPLE, + HFI_COL_FMT_TP10C_Y_TILE_WIDTH); + metadata_buf_height = + hfi_ubwc_metadata_plane_bufheight(frame_height, + IRIS_METADATA_HEIGHT_MULTIPLE, + HFI_COL_FMT_TP10C_Y_TILE_HEIGHT); + meta_size_y = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + meta_size_c = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + size = ten_bit_ref_buf_size + meta_size_y + meta_size_c; + } + + return size; +} + +static u32 iris_vpu_enc_arp_size(struct iris_inst *inst) +{ + return HFI_BUFFER_ARP_ENC; +} + +inline bool is_scaling_enabled(struct iris_inst *inst) +{ + return inst->crop.left != inst->compose.left || + inst->crop.top != inst->compose.top || + inst->crop.width != inst->compose.width || + inst->crop.height != inst->compose.height; +} + +static inline +u32 hfi_buffer_vpss_enc(u32 dswidth, u32 dsheight, bool ds_enable, + u32 blur, bool is_ten_bit) +{ + if (ds_enable || blur) + return hfi_buffer_dpb_enc(dswidth, dsheight, is_ten_bit); + + return 0; +} + +static inline u32 hfi_buffer_scratch1_enc(u32 frame_width, u32 frame_height, + u32 lcu_size, u32 num_ref, + bool ten_bit, u32 num_vpp_pipes, + bool is_h265) +{ + u32 line_buf_ctrl_size, line_buf_data_size, leftline_buf_ctrl_size; + u32 line_buf_sde_size, sps_pps_slice_hdr, topline_buf_ctrl_size_FE; + u32 leftline_buf_ctrl_size_FE, line_buf_recon_pix_size; + u32 leftline_buf_recon_pix_size, lambda_lut_size, override_buffer_size; + u32 col_mv_buf_size, vpp_reg_buffer_size, ir_buffer_size; + u32 vpss_line_buf, leftline_buf_meta_recony, h265e_colrcbuf_size; + u32 h265e_framerc_bufsize, h265e_lcubitcnt_bufsize; + u32 h265e_lcubitmap_bufsize, se_stats_bufsize; + u32 bse_reg_buffer_size, bse_slice_cmd_buffer_size, slice_info_bufsize; + u32 line_buf_ctrl_size_buffid2, slice_cmd_buffer_size; + u32 width_lcu_num, height_lcu_num, width_coded, height_coded; + u32 frame_num_lcu, linebuf_meta_recon_uv, topline_bufsize_fe_1stg_sao; + u32 vpss_line_buffer_size_1; + u32 bit_depth, num_lcu_mb; + + width_lcu_num = (frame_width + lcu_size - 1) / lcu_size; + height_lcu_num = (frame_height + lcu_size - 1) / lcu_size; + frame_num_lcu = width_lcu_num * height_lcu_num; + width_coded = width_lcu_num * lcu_size; + height_coded = height_lcu_num * lcu_size; + num_lcu_mb = (height_coded / lcu_size) * + ((width_coded + lcu_size * 8) / lcu_size); + slice_info_bufsize = 256 + (frame_num_lcu << 4); + slice_info_bufsize = ALIGN(slice_info_bufsize, 256); + line_buf_ctrl_size = ALIGN(width_coded, 256); + line_buf_ctrl_size_buffid2 = ALIGN(width_coded, 256); + + bit_depth = ten_bit ? 10 : 8; + line_buf_data_size = + (((((bit_depth * width_coded + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((bit_depth * width_coded + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)); + + leftline_buf_ctrl_size = is_h265 ? ((height_coded + 32) / 32 * 4 * 16) : + ((height_coded + 15) / 16 * 5 * 16); + + if (num_vpp_pipes > 1) { + leftline_buf_ctrl_size += 512; + leftline_buf_ctrl_size = + ALIGN(leftline_buf_ctrl_size, 512) * num_vpp_pipes; + } + + leftline_buf_ctrl_size = ALIGN(leftline_buf_ctrl_size, 256); + leftline_buf_recon_pix_size = + (((ten_bit + 1) * 2 * (height_coded) + 256) + + (256 << (num_vpp_pipes - 1)) - 1) & + (~((256 << (num_vpp_pipes - 1)) - 1)) * 1; + + topline_buf_ctrl_size_FE = is_h265 ? (64 * (width_coded >> 5)) : + (256 + 16 * (width_coded >> 4)); + topline_buf_ctrl_size_FE = ALIGN(topline_buf_ctrl_size_FE, 256); + leftline_buf_ctrl_size_FE = + (((256 + 64 * (height_coded >> 4)) + + (256 << (num_vpp_pipes - 1)) - 1) & + (~((256 << (num_vpp_pipes - 1)) - 1)) * 1) * + num_vpp_pipes; + leftline_buf_meta_recony = + (256 + 64 * ((height_coded) / (8 * (ten_bit ? 4 : 8)))); + leftline_buf_meta_recony = ALIGN(leftline_buf_meta_recony, 256); + leftline_buf_meta_recony = leftline_buf_meta_recony * num_vpp_pipes; + linebuf_meta_recon_uv = + (256 + 64 * ((height_coded) / (4 * (ten_bit ? 4 : 8)))); + linebuf_meta_recon_uv = ALIGN(linebuf_meta_recon_uv, 256); + linebuf_meta_recon_uv = linebuf_meta_recon_uv * num_vpp_pipes; + line_buf_recon_pix_size = ((ten_bit ? 3 : 2) * width_coded); + line_buf_recon_pix_size = ALIGN(line_buf_recon_pix_size, 256); + slice_cmd_buffer_size = ALIGN(20480, 256); + sps_pps_slice_hdr = 2048 + 4096; + col_mv_buf_size = + is_h265 ? (16 * ((frame_num_lcu << 2) + 32)) : + (3 * 16 * (width_lcu_num * height_lcu_num + 32)); + col_mv_buf_size = ALIGN(col_mv_buf_size, 256) * (num_ref + 1); + h265e_colrcbuf_size = + (((width_lcu_num + 7) >> 3) * 16 * 2 * height_lcu_num); + if (num_vpp_pipes > 1) + h265e_colrcbuf_size = + ALIGN(h265e_colrcbuf_size, 256) * num_vpp_pipes; + + h265e_colrcbuf_size = + ALIGN(h265e_colrcbuf_size, 256) * HFI_MAX_COL_FRAME; + h265e_framerc_bufsize = + (is_h265) ? + (256 + 16 * (14 + (((height_coded >> 5) + 7) >> 3))) : + (256 + 16 * (14 + (((height_coded >> 4) + 7) >> 3))); + h265e_framerc_bufsize *= 6; + if (num_vpp_pipes > 1) + h265e_framerc_bufsize = + ALIGN(h265e_framerc_bufsize, 256) * num_vpp_pipes; + + h265e_framerc_bufsize = + ALIGN(h265e_framerc_bufsize, 512) * HFI_MAX_COL_FRAME; + h265e_lcubitcnt_bufsize = 256 + 4 * frame_num_lcu; + h265e_lcubitcnt_bufsize = ALIGN(h265e_lcubitcnt_bufsize, 256); + h265e_lcubitmap_bufsize = 256 + (frame_num_lcu >> 3); + h265e_lcubitmap_bufsize = ALIGN(h265e_lcubitmap_bufsize, 256); + line_buf_sde_size = 256 + 16 * (width_coded >> 4); + line_buf_sde_size = ALIGN(line_buf_sde_size, 256); + if ((width_coded * height_coded) > (4096 * 2160)) + se_stats_bufsize = 0; + else if ((width_coded * height_coded) > (1920 * 1088)) + se_stats_bufsize = (40 * 4 * frame_num_lcu + 256 + 256); + else + se_stats_bufsize = (1024 * frame_num_lcu + 256 + 256); + + se_stats_bufsize = ALIGN(se_stats_bufsize, 256) * 2; + bse_slice_cmd_buffer_size = (((8192 << 2) + 7) & (~7)) * 6; + bse_reg_buffer_size = (((512 << 3) + 7) & (~7)) * 4; + vpp_reg_buffer_size = (((2048 << 3) + 31) & (~31)) * 10; + lambda_lut_size = 256 * 11; + override_buffer_size = 16 * ((num_lcu_mb + 7) >> 3); + override_buffer_size = ALIGN(override_buffer_size, 256) * 2; + ir_buffer_size = (((frame_num_lcu << 1) + 7) & (~7)) * 3; + vpss_line_buffer_size_1 = (((8192 >> 2) << 5) * num_vpp_pipes) + 64; + vpss_line_buf = + (((((max(width_coded, height_coded) + 3) >> 2) << 5) + 256) * + 16) + + vpss_line_buffer_size_1; + topline_bufsize_fe_1stg_sao = 16 * (width_coded >> 5); + topline_bufsize_fe_1stg_sao = ALIGN(topline_bufsize_fe_1stg_sao, 256); + + return line_buf_ctrl_size + line_buf_data_size + + line_buf_ctrl_size_buffid2 + leftline_buf_ctrl_size + + vpss_line_buf + col_mv_buf_size + topline_buf_ctrl_size_FE + + leftline_buf_ctrl_size_FE + line_buf_recon_pix_size + + leftline_buf_recon_pix_size + leftline_buf_meta_recony + + linebuf_meta_recon_uv + h265e_colrcbuf_size + + h265e_framerc_bufsize + h265e_lcubitcnt_bufsize + + h265e_lcubitmap_bufsize + line_buf_sde_size + + topline_bufsize_fe_1stg_sao + override_buffer_size + + bse_reg_buffer_size + vpp_reg_buffer_size + sps_pps_slice_hdr + + slice_cmd_buffer_size + bse_slice_cmd_buffer_size + + ir_buffer_size + slice_info_bufsize + lambda_lut_size + + se_stats_bufsize + 1024; +} + +static u32 iris_vpu_enc_scratch1_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 frame_height = f->fmt.pix_mp.height; + u32 frame_width = f->fmt.pix_mp.width; + u32 num_ref = 1; + u32 lcu_size; + bool is_h265; + + if (inst->codec == V4L2_PIX_FMT_H264) { + lcu_size = 16; + is_h265 = false; + } else if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + is_h265 = true; + } else { + return 0; + } + + return hfi_buffer_scratch1_enc(frame_width, frame_height, lcu_size, + num_ref, false, num_vpp_pipes, is_h265); +} + +static inline u32 ubwc_metadata_plane_stride(u32 width, + u32 metadata_stride_multi, + u32 tile_width_pels) +{ + return ALIGN(((width + (tile_width_pels - 1)) / tile_width_pels), + metadata_stride_multi); +} + +static inline u32 ubwc_metadata_plane_bufheight(u32 height, + u32 metadata_height_multi, + u32 tile_height_pels) +{ + return ALIGN(((height + (tile_height_pels - 1)) / tile_height_pels), + metadata_height_multi); +} + +static inline u32 ubwc_metadata_plane_buffer_size(u32 metadata_stride, + u32 metadata_buf_height) +{ + return ALIGN(metadata_stride * metadata_buf_height, SZ_4K); +} + +static inline u32 hfi_buffer_scratch2_enc(u32 frame_width, u32 frame_height, + u32 num_ref, bool ten_bit) +{ + u32 aligned_width, aligned_height, chroma_height, ref_buf_height; + u32 metadata_stride, meta_buf_height, meta_size_y, meta_size_c; + u32 ref_luma_stride_bytes, ref_chroma_height_bytes; + u32 ref_buf_size, ref_stride; + u32 luma_size, chroma_size; + u32 size; + + if (!ten_bit) { + aligned_height = ALIGN(frame_height, 32); + chroma_height = frame_height >> 1; + chroma_height = ALIGN(chroma_height, 32); + aligned_width = ALIGN(frame_width, 128); + metadata_stride = + ubwc_metadata_plane_stride(frame_width, 64, 32); + meta_buf_height = + ubwc_metadata_plane_bufheight(frame_height, 16, 8); + meta_size_y = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + meta_size_c = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + size = (aligned_height + chroma_height) * aligned_width + + meta_size_y + meta_size_c; + size = (size * (num_ref + 3)) + 4096; + } else { + ref_buf_height = (frame_height + (32 - 1)) & (~(32 - 1)); + ref_luma_stride_bytes = ((frame_width + 192 - 1) / 192) * 192; + ref_stride = 4 * (ref_luma_stride_bytes / 3); + ref_stride = (ref_stride + (128 - 1)) & (~(128 - 1)); + luma_size = ref_buf_height * ref_stride; + ref_chroma_height_bytes = + (((frame_height + 1) >> 1) + (32 - 1)) & (~(32 - 1)); + chroma_size = ref_stride * ref_chroma_height_bytes; + luma_size = (luma_size + (SZ_4K - 1)) & (~(SZ_4K - 1)); + chroma_size = (chroma_size + (SZ_4K - 1)) & (~(SZ_4K - 1)); + ref_buf_size = luma_size + chroma_size; + metadata_stride = + ubwc_metadata_plane_stride(frame_width, 64, 48); + meta_buf_height = + ubwc_metadata_plane_bufheight(frame_height, 16, 4); + meta_size_y = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + meta_size_c = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + size = ref_buf_size + meta_size_y + meta_size_c; + size = (size * (num_ref + 3)) + 4096; + } + + return size; +} + +static u32 iris_vpu_enc_scratch2_size(struct iris_inst *inst) +{ + struct v4l2_format *f = inst->fmt_dst; + u32 frame_width = f->fmt.pix_mp.width; + u32 frame_height = f->fmt.pix_mp.height; + u32 num_ref = 1; + + return hfi_buffer_scratch2_enc(frame_width, frame_height, num_ref, + false); +} + +static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst) +{ + u32 ds_enable = is_scaling_enabled(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + + return hfi_buffer_vpss_enc(width, height, ds_enable, 0, 0); +} + +static int output_min_count(struct iris_inst *inst) +{ + int output_min_count = 4; + + /* fw_min_count > 0 indicates reconfig event has already arrived */ + if (inst->fw_min_count) { + if (iris_split_mode_enabled(inst) && inst->codec == V4L2_PIX_FMT_VP9) + return min_t(u32, 4, inst->fw_min_count); + else + return inst->fw_min_count; + } + + if (inst->codec == V4L2_PIX_FMT_VP9) + output_min_count = 9; + + return output_min_count; +} + struct iris_vpu_buf_type_handle { enum iris_buffer_type type; u32 (*handle)(struct iris_inst *inst); }; -int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - const struct iris_vpu_buf_type_handle *buf_type_handle_arr; - u32 size = 0, buf_type_handle_size, i; + const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL; + u32 size = 0, buf_type_handle_size = 0, i; static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = { {BUF_BIN, iris_vpu_dec_bin_size }, @@ -225,8 +1446,24 @@ int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) {BUF_SCRATCH_1, iris_vpu_dec_scratch1_size }, }; - buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); - buf_type_handle_arr = dec_internal_buf_type_handle; + static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_enc_bin_size }, + {BUF_COMV, iris_vpu_enc_comv_size }, + {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, + {BUF_LINE, iris_vpu_enc_line_size }, + {BUF_ARP, iris_vpu_enc_arp_size }, + {BUF_VPSS, iris_vpu_enc_vpss_size }, + {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, + {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, + }; + + if (inst->domain == DECODER) { + buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); + buf_type_handle_arr = dec_internal_buf_type_handle; + } else if (inst->domain == ENCODER) { + buf_type_handle_size = ARRAY_SIZE(enc_internal_buf_type_handle); + buf_type_handle_arr = enc_internal_buf_type_handle; + } for (i = 0; i < buf_type_handle_size; i++) { if (buf_type_handle_arr[i].type == buffer_type) { @@ -238,6 +1475,47 @@ int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) return size; } +u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +{ + u32 size = 0, i; + + static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_enc_bin_size }, + {BUF_COMV, iris_vpu_enc_comv_size }, + {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, + {BUF_LINE, iris_vpu33_enc_line_size }, + {BUF_ARP, iris_vpu_enc_arp_size }, + {BUF_VPSS, iris_vpu_enc_vpss_size }, + {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, + {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, + }; + + if (inst->domain == DECODER) + return iris_vpu_buf_size(inst, buffer_type); + + for (i = 0; i < ARRAY_SIZE(enc_internal_buf_type_handle); i++) { + if (enc_internal_buf_type_handle[i].type == buffer_type) { + size = enc_internal_buf_type_handle[i].handle(inst); + break; + } + } + + return size; +} + +static u32 internal_buffer_count(struct iris_inst *inst, + enum iris_buffer_type buffer_type) +{ + if (buffer_type == BUF_BIN || buffer_type == BUF_LINE || + buffer_type == BUF_PERSIST) { + return 1; + } else if (buffer_type == BUF_COMV || buffer_type == BUF_NON_COMV) { + if (inst->codec == V4L2_PIX_FMT_H264 || inst->codec == V4L2_PIX_FMT_HEVC) + return 1; + } + return 0; +} + static inline int iris_vpu_dpb_count(struct iris_inst *inst) { if (iris_split_mode_enabled(inst)) { @@ -254,13 +1532,20 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type case BUF_INPUT: return MIN_BUFFERS; case BUF_OUTPUT: - return inst->fw_min_count; + if (inst->domain == ENCODER) + return MIN_BUFFERS; + else + return output_min_count(inst); case BUF_BIN: case BUF_COMV: case BUF_NON_COMV: case BUF_LINE: case BUF_PERSIST: + return internal_buffer_count(inst, buffer_type); case BUF_SCRATCH_1: + case BUF_SCRATCH_2: + case BUF_VPSS: + case BUF_ARP: return 1; /* internal buffer count needed by firmware is 1 */ case BUF_DPB: return iris_vpu_dpb_count(inst); diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h index 62af6ea6ba1f..04f0b7400a1e 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h @@ -13,6 +13,10 @@ struct iris_inst; #define DMA_ALIGNMENT 256 #define NUM_HW_PIC_BUF 32 +#define LCU_MAX_SIZE_PELS 64 +#define LCU_MIN_SIZE_PELS 16 +#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024) + #define SIZE_HW_PIC(size_per_buf) (NUM_HW_PIC_BUF * (size_per_buf)) #define MAX_TILE_COLUMNS 32 @@ -28,11 +32,48 @@ struct iris_inst; #define SIZE_SLIST_BUF_H264 512 #define H264_DISPLAY_BUF_SIZE 3328 #define H264_NUM_FRM_INFO 66 - -#define SIZE_SEI_USERDATA 4096 - +#define H265_NUM_TILE_COL 32 +#define H265_NUM_TILE_ROW 128 +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(u32)) + +#define NUM_SLIST_BUF_H265 (80 + 20) +#define SIZE_SLIST_BUF_H265 (BIT(10)) +#define H265_DISPLAY_BUF_SIZE (3072) +#define H265_NUM_FRM_INFO (48) +#define SIZE_ONE_SLICE_BUF 256 + +#define VP9_NUM_FRAME_INFO_BUF 32 +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) +#define VP9_PROB_TABLE_SIZE (3840) +#define VP9_FRAME_INFO_BUF_SIZE (6144) +#define BUFFER_ALIGNMENT_32_BYTES 32 +#define CCE_TILE_OFFSET_SIZE ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) +#define MAX_SUPERFRAME_HEADER_LEN (34) +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) + +#define SIZE_SEI_USERDATA 4096 +#define SIZE_DOLBY_RPU_METADATA (41 * 1024) #define H264_CABAC_HDR_RATIO_HD_TOT 1 #define H264_CABAC_RES_RATIO_HD_TOT 3 +#define H265D_MAX_SLICE 1200 +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T +#define H265_CABAC_HDR_RATIO_HD_TOT 2 +#define H265_CABAC_RES_RATIO_HD_TOT 2 +#define SIZE_H265D_VPP_CMD_PER_BUF (256) + +#define VPX_DECODER_FRAME_CONCURENCY_LVL (2) +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET 1 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET 3 +#define VPX_DECODER_FRAME_BIN_DENOMINATOR 2 + +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO (3 / 2) + #define SIZE_H264D_HW_PIC_T (BIT(11)) #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 @@ -40,6 +81,26 @@ struct iris_inst; #define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384 #define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define SIZE_SLICE_CMD_BUFFER (ALIGN(20480, 256)) +#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) +#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) +#define SIZE_LAMBDA_LUT (256 * 11) + +#define HFI_COL_FMT_NV12C_Y_TILE_HEIGHT (8) +#define HFI_COL_FMT_NV12C_Y_TILE_WIDTH (32) +#define HFI_COL_FMT_TP10C_Y_TILE_HEIGHT (4) +#define HFI_COL_FMT_TP10C_Y_TILE_WIDTH (48) + +#define IRIS_METADATA_STRIDE_MULTIPLE 64 +#define IRIS_METADATA_HEIGHT_MULTIPLE 16 + +#define HFI_BUFFER_ARP_ENC 204800 + +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 2304 +#define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16)) +#define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) + static inline u32 size_h264d_lb_fe_top_data(u32 frame_width) { return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * ALIGN(frame_width, 16) * 3; @@ -85,7 +146,8 @@ static inline u32 size_h264d_qp(u32 frame_width, u32 frame_height) return DIV_ROUND_UP(frame_width, 64) * DIV_ROUND_UP(frame_height, 64) * 128; } -int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index 268e45acaa7c..bb98950e018f 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -84,6 +84,7 @@ static void iris_vpu_interrupt_init(struct iris_core *core) static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) { u32 queue_size, value; + const struct vpu_ops *vpu_ops = core->iris_platform_data->vpu_ops; /* Iris hardware requires 4K queue alignment */ queue_size = ALIGN(sizeof(struct iris_hfi_queue_table_header) + @@ -105,6 +106,9 @@ static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) value = (u32)core->sfr_daddr + core->iris_platform_data->core_arch; writel(value, core->reg_base + SFR_ADDR); } + + if (vpu_ops->program_bootup_registers) + vpu_ops->program_bootup_registers(core); } int iris_vpu_boot_firmware(struct iris_core *core) @@ -271,7 +275,7 @@ void iris_vpu_power_off(struct iris_core *core) disable_irq_nosync(core->irq); } -static int iris_vpu_power_on_controller(struct iris_core *core) +int iris_vpu_power_on_controller(struct iris_core *core) { u32 rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; int ret; @@ -302,7 +306,7 @@ err_disable_power: return ret; } -static int iris_vpu_power_on_hw(struct iris_core *core) +int iris_vpu_power_on_hw(struct iris_core *core) { int ret; @@ -337,11 +341,11 @@ int iris_vpu_power_on(struct iris_core *core) if (ret) goto err; - ret = iris_vpu_power_on_controller(core); + ret = core->iris_platform_data->vpu_ops->power_on_controller(core); if (ret) goto err_unvote_icc; - ret = iris_vpu_power_on_hw(core); + ret = core->iris_platform_data->vpu_ops->power_on_hw(core); if (ret) goto err_power_off_ctrl; @@ -359,7 +363,7 @@ int iris_vpu_power_on(struct iris_core *core) return 0; err_power_off_ctrl: - iris_vpu_power_off_controller(core); + core->iris_platform_data->vpu_ops->power_off_controller(core); err_unvote_icc: iris_unset_icc_bw(core); err: diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h index 93b7fa27be3b..d636e287457a 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -11,10 +11,14 @@ struct iris_core; extern const struct vpu_ops iris_vpu2_ops; extern const struct vpu_ops iris_vpu3_ops; extern const struct vpu_ops iris_vpu33_ops; +extern const struct vpu_ops iris_vpu35_ops; struct vpu_ops { void (*power_off_hw)(struct iris_core *core); + int (*power_on_hw)(struct iris_core *core); int (*power_off_controller)(struct iris_core *core); + int (*power_on_controller)(struct iris_core *core); + void (*program_bootup_registers)(struct iris_core *core); u64 (*calc_freq)(struct iris_inst *inst, size_t data_size); }; @@ -23,6 +27,8 @@ void iris_vpu_raise_interrupt(struct iris_core *core); void iris_vpu_clear_interrupt(struct iris_core *core); int iris_vpu_watchdog(struct iris_core *core, u32 intr_status); int iris_vpu_prepare_pc(struct iris_core *core); +int iris_vpu_power_on_controller(struct iris_core *core); +int iris_vpu_power_on_hw(struct iris_core *core); int iris_vpu_power_on(struct iris_core *core); int iris_vpu_power_off_controller(struct iris_core *core); void iris_vpu_power_off_hw(struct iris_core *core); |