Implement vb2 ops for buf queue. Below are the different
buffer attributes:
BUF_ATTR_DEFERRED - buffer queued by client but not submitted
to firmware.
BUF_ATTR_PENDING_RELEASE - buffers requested to be released
from firmware.
BUF_ATTR_QUEUED - buffers submitted to firmware.
BUF_ATTR_DEQUEUED - buffers received from firmware.
BUF_ATTR_BUFFER_DONE - buffers sent back to vb2.
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
---
drivers/media/platform/qcom/iris/Kconfig | 1 +
drivers/media/platform/qcom/iris/iris_buffer.c | 118 +++++++++++++
drivers/media/platform/qcom/iris/iris_buffer.h | 2 +
.../platform/qcom/iris/iris_hfi_gen1_command.c | 53 ++++++
.../platform/qcom/iris/iris_hfi_gen1_defines.h | 80 +++++++++
.../platform/qcom/iris/iris_hfi_gen1_response.c | 167 ++++++++++++++++++-
drivers/media/platform/qcom/iris/iris_hfi_gen2.h | 2 +
.../platform/qcom/iris/iris_hfi_gen2_defines.h | 22 +++
.../platform/qcom/iris/iris_hfi_gen2_response.c | 183 ++++++++++++++++++++-
drivers/media/platform/qcom/iris/iris_instance.h | 8 +
drivers/media/platform/qcom/iris/iris_utils.c | 16 ++
drivers/media/platform/qcom/iris/iris_utils.h | 16 ++
drivers/media/platform/qcom/iris/iris_vb2.c | 102 +++++++++++-
drivers/media/platform/qcom/iris/iris_vb2.h | 4 +
drivers/media/platform/qcom/iris/iris_vdec.c | 154 ++++++++++++++++-
drivers/media/platform/qcom/iris/iris_vdec.h | 3 +-
drivers/media/platform/qcom/iris/iris_vidc.c | 15 ++
17 files changed, 926 insertions(+), 20 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig
index f92cc7fe9378..3c803a05305a 100644
--- a/drivers/media/platform/qcom/iris/Kconfig
+++ b/drivers/media/platform/qcom/iris/Kconfig
@@ -5,6 +5,7 @@ config VIDEO_QCOM_IRIS
select V4L2_MEM2MEM_DEV
select QCOM_MDT_LOADER if ARCH_QCOM
select QCOM_SCM
+ select VIDEOBUF2_DMA_CONTIG
help
This is a V4L2 driver for Qualcomm iris video accelerator
hardware. It accelerates decoding operations on various
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c
index 9fa97375d61f..8df003000dc8 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_buffer.c
@@ -3,6 +3,7 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
#include "iris_buffer.h"
@@ -434,6 +435,36 @@ int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst)
return 0;
}
+int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *buffer, *n;
+ struct iris_buffer *buf;
+ int ret;
+
+ if (buf_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))
+ continue;
+ ret = iris_queue_buffer(inst, buf);
+ if (ret)
+ return ret;
+ }
+ } else {
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) {
+ buf = to_iris_buffer(&buffer->vb);
+ if (!(buf->attr & BUF_ATTR_DEFERRED))
+ continue;
+ ret = iris_queue_buffer(inst, buf);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
void iris_vb2_queue_error(struct iris_inst *inst)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
@@ -444,3 +475,90 @@ void iris_vb2_queue_error(struct iris_inst *inst)
q = v4l2_m2m_get_dst_vq(m2m_ctx);
vb2_queue_error(q);
}
+
+static struct vb2_v4l2_buffer *
+iris_helper_find_buf(struct iris_inst *inst, u32 type, u32 idx)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx);
+ else
+ return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx);
+}
+
+static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns,
+ struct vb2_v4l2_buffer *vbuf)
+{
+ u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) {
+ if (inst->tss[i].ts_ns != timestamp_ns)
+ continue;
+
+ vbuf->flags &= ~mask;
+ vbuf->flags |= inst->tss[i].flags;
+ vbuf->timecode = inst->tss[i].tc;
+ return;
+ }
+
+ vbuf->flags &= ~mask;
+ vbuf->flags |= inst->tss[inst->metadata_idx].flags;
+ vbuf->timecode = inst->tss[inst->metadata_idx].tc;
+}
+
+int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct vb2_v4l2_buffer *vbuf;
+ struct vb2_buffer *vb2;
+ u32 type, state;
+
+ switch (buf->type) {
+ case BUF_INPUT:
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ break;
+ case BUF_OUTPUT:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ break;
+ default:
+ return 0; /* Internal DPB Buffers */
+ }
+
+ vbuf = iris_helper_find_buf(inst, type, buf->index);
+ if (!vbuf)
+ return -EINVAL;
+
+ 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 (V4L2_TYPE_IS_CAPTURE(type)) {
+ vb2_set_plane_payload(vb2, 0, buf->data_size);
+ vbuf->sequence = inst->sequence_cap++;
+ iris_get_ts_metadata(inst, buf->timestamp, vbuf);
+ } else {
+ vbuf->sequence = inst->sequence_out++;
+ }
+
+ if (vbuf->flags & V4L2_BUF_FLAG_LAST) {
+ if (!v4l2_m2m_has_stopped(m2m_ctx) &&
+ inst->subscriptions & V4L2_EVENT_EOS) {
+ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
+
+ v4l2_event_queue_fh(&inst->fh, &ev);
+ v4l2_m2m_mark_stopped(m2m_ctx);
+ }
+ }
+ vb2->timestamp = buf->timestamp;
+ vb2->planes[0].bytesused = buf->data_size + vb2->planes[0].data_offset;
+ v4l2_m2m_buf_done(vbuf, state);
+
+ return 0;
+}
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h
index 41e090e9f0b0..bd8b74a9fbc4 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_buffer.h
@@ -109,6 +109,8 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf
int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane);
int iris_alloc_and_queue_persist_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);
+int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf);
void iris_vb2_queue_error(struct iris_inst *inst);
#endif
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 ee7d9beca33b..82f2513576bf 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
@@ -180,6 +180,10 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane)
ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size);
if (!ret)
ret = iris_wait_for_session_response(inst, false);
+ 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;
@@ -201,6 +205,50 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane)
return ret;
}
+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);
+}
+
+static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf)
+{
+ struct hfi_session_fill_buffer_pkt op_pkt;
+
+ op_pkt.shdr.hdr.size = sizeof(struct hfi_session_fill_buffer_pkt);
+ op_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FILL_BUFFER;
+ op_pkt.shdr.session_id = inst->session_id;
+ op_pkt.output_tag = buf->index;
+ op_pkt.packet_buffer = buf->device_addr;
+ op_pkt.extradata_buffer = 0;
+ op_pkt.alloc_len = buf->buffer_size;
+ op_pkt.filled_len = buf->data_size;
+ op_pkt.offset = buf->data_offset;
+ op_pkt.data = 0;
+
+ if (buf->type == BUF_OUTPUT && iris_split_mode_enabled(inst))
+ op_pkt.stream_id = 1;
+ else
+ op_pkt.stream_id = 0;
+
+ return iris_hfi_queue_cmd_write(inst->core, &op_pkt, op_pkt.shdr.hdr.size);
+}
+
static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf)
{
struct hfi_session_set_buffers_pkt *int_pkt;
@@ -240,6 +288,11 @@ static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct ir
static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf)
{
switch (buf->type) {
+ case BUF_INPUT:
+ return iris_hfi_gen1_queue_input_buffer(inst, buf);
+ case BUF_OUTPUT:
+ case BUF_DPB:
+ return iris_hfi_gen1_queue_output_buffer(inst, buf);
case BUF_PERSIST:
case BUF_BIN:
case BUF_SCRATCH_1:
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 5527233b03e5..b7f9e0f47675 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
@@ -29,11 +29,14 @@
#define HFI_CMD_SESSION_LOAD_RESOURCES 0x211001
#define HFI_CMD_SESSION_START 0x211002
#define HFI_CMD_SESSION_STOP 0x211003
+#define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004
+#define HFI_CMD_SESSION_FILL_BUFFER 0x211005
#define HFI_CMD_SESSION_FLUSH 0x211008
#define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b
#define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c
#define HFI_ERR_SESSION_UNSUPPORTED_SETTING 0x1008
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM 0x100d
#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE 0x1010
#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR 0x1012
#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED 0x1013
@@ -41,6 +44,8 @@
#define HFI_EVENT_SYS_ERROR 0x1
#define HFI_EVENT_SESSION_ERROR 0x2
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+
#define HFI_FLUSH_OUTPUT 0x1000002
#define HFI_FLUSH_OUTPUT2 0x1000003
#define HFI_FLUSH_ALL 0x1000004
@@ -84,9 +89,19 @@
#define HFI_MSG_SESSION_START 0x221002
#define HFI_MSG_SESSION_STOP 0x221003
#define HFI_MSG_SESSION_FLUSH 0x221006
+#define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007
+#define HFI_MSG_SESSION_FILL_BUFFER 0x221008
#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_FRAME_NOTCODED 0x7f002000
+#define HFI_FRAME_YUV 0x7f004000
+#define HFI_UNUSED_PICT 0x10000000
+
struct hfi_pkt_hdr {
u32 size;
u32 pkt_type;
@@ -144,6 +159,34 @@ struct hfi_session_set_buffers_pkt {
u32 buffer_info[];
};
+struct hfi_session_empty_buffer_compressed_pkt {
+ struct hfi_session_hdr_pkt shdr;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ 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;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 output_tag;
+ u32 packet_buffer;
+ u32 extradata_buffer;
+ u32 data;
+};
+
struct hfi_session_flush_pkt {
struct hfi_session_hdr_pkt shdr;
u32 flush_type;
@@ -258,6 +301,43 @@ struct hfi_multi_stream {
u32 enable;
};
+struct hfi_msg_session_empty_buffer_done_pkt {
+ struct hfi_msg_session_hdr_pkt shdr;
+ u32 offset;
+ u32 filled_len;
+ u32 input_tag;
+ 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;
+ u32 view_id;
+ u32 error_type;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_x_coord;
+ u32 start_y_coord;
+ u32 input_tag;
+ u32 input_tag2;
+ u32 output_tag;
+ u32 picture_type;
+ u32 packet_buffer;
+ u32 extradata_buffer;
+ u32 data[];
+};
+
struct hfi_msg_session_release_buffers_done_pkt {
struct hfi_msg_session_hdr_pkt shdr;
u32 num_buffers;
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 a84bb00388d9..23a8bf29e381 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
@@ -3,6 +3,8 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <media/v4l2-mem2mem.h>
+
#include "iris_hfi_gen1.h"
#include "iris_hfi_gen1_defines.h"
#include "iris_instance.h"
@@ -130,6 +132,143 @@ static void iris_hfi_gen1_sys_property_info(struct iris_core *core, void *packet
}
}
+static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet)
+{
+ struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *m2m_buffer, *n;
+ struct iris_buffer *buf = NULL;
+ bool found = false;
+
+ 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) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ goto error;
+
+ if (pkt->shdr.error_type == HFI_ERR_SESSION_UNSUPPORTED_STREAM) {
+ buf->flags = V4L2_BUF_FLAG_ERROR;
+ iris_vb2_queue_error(inst);
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ }
+
+ if (!(buf->attr & BUF_ATTR_QUEUED))
+ return;
+
+ buf->attr &= ~BUF_ATTR_QUEUED;
+
+ if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
+ buf->attr |= BUF_ATTR_BUFFER_DONE;
+ iris_vb2_buffer_done(inst, buf);
+ }
+
+ return;
+
+error:
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ dev_err(inst->core->dev, "error in etb done\n");
+}
+
+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 v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *m2m_buffer, *n;
+ u32 timestamp_hi = pkt->time_stamp_hi;
+ u32 timestamp_lo = pkt->time_stamp_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;
+ struct iris_buffer *buf, *iter;
+ struct iris_buffers *buffers;
+ u32 offset = pkt->offset;
+ u64 timestamp_us = 0;
+ bool found = false;
+ u32 flags = 0;
+
+ if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) {
+ buffers = &inst->buffers[BUF_DPB];
+ if (!buffers)
+ goto error;
+
+ found = false;
+ list_for_each_entry(iter, &buffers->list, list) {
+ if (!(iter->attr & BUF_ATTR_QUEUED))
+ continue;
+
+ found = (iter->index == output_tag &&
+ iter->data_offset == offset);
+
+ if (found) {
+ buf = iter;
+ break;
+ }
+ }
+ } else {
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) {
+ buf = to_iris_buffer(&m2m_buffer->vb);
+ if (!(buf->attr & BUF_ATTR_QUEUED))
+ continue;
+
+ found = (buf->index == output_tag &&
+ buf->data_offset == offset);
+
+ if (found)
+ break;
+ }
+ }
+ if (!found)
+ goto error;
+
+ buf->data_offset = offset;
+ buf->data_size = filled_len;
+
+ if (filled_len) {
+ timestamp_us = timestamp_hi;
+ timestamp_us = (timestamp_us << 32) | timestamp_lo;
+ } else {
+ flags |= V4L2_BUF_FLAG_LAST;
+ }
+ buf->timestamp = timestamp_us;
+
+ switch (pic_type) {
+ case HFI_PICTURE_IDR:
+ case HFI_PICTURE_I:
+ flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case HFI_PICTURE_P:
+ flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case HFI_PICTURE_B:
+ flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ case HFI_FRAME_NOTCODED:
+ case HFI_UNUSED_PICT:
+ case HFI_FRAME_YUV:
+ default:
+ break;
+ }
+
+ buf->attr &= ~BUF_ATTR_QUEUED;
+ buf->attr |= BUF_ATTR_DEQUEUED;
+ buf->attr |= BUF_ATTR_BUFFER_DONE;
+
+ buf->flags |= flags;
+
+ iris_vb2_buffer_done(inst, buf);
+
+ return;
+
+error:
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ dev_err(core->dev, "error in ftb done\n");
+}
+
struct iris_hfi_gen1_response_pkt_info {
u32 pkt;
u32 pkt_sz;
@@ -168,6 +307,14 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = {
.pkt = HFI_MSG_SESSION_STOP,
.pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
},
+ {
+ .pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
+ .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
+ },
+ {
+ .pkt = HFI_MSG_SESSION_FILL_BUFFER,
+ .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt),
+ },
{
.pkt = HFI_MSG_SESSION_FLUSH,
.pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
@@ -238,15 +385,21 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response
}
mutex_lock(&inst->lock);
- struct hfi_msg_session_hdr_pkt *shdr;
+ if (hdr->pkt_type == HFI_MSG_SESSION_EMPTY_BUFFER) {
+ iris_hfi_gen1_session_etb_done(inst, hdr);
+ } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
+ iris_hfi_gen1_session_ftb_done(inst, hdr);
+ } else {
+ struct hfi_msg_session_hdr_pkt *shdr;
- shdr = (struct hfi_msg_session_hdr_pkt *)hdr;
- if (shdr->error_type != HFI_ERR_NONE)
- iris_inst_change_state(inst, IRIS_INST_ERROR);
+ shdr = (struct hfi_msg_session_hdr_pkt *)hdr;
+ 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);
+ done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ?
+ &inst->flush_completion : &inst->completion;
+ complete(done);
+ }
mutex_unlock(&inst->lock);
break;
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h
index 5fbbab844025..bf3aa1afb5bb 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h
@@ -20,6 +20,7 @@ struct iris_core;
* @packet: HFI packet
* @ipsc_properties_set: boolean to set ipsc properties to fw
* @opsc_properties_set: boolean to set opsc properties to fw
+ * @hfi_frame_info: structure of frame info
* @src_subcr_params: subscription params to fw on input port
* @dst_subcr_params: subscription params to fw on output port
*/
@@ -28,6 +29,7 @@ struct iris_inst_hfi_gen2 {
struct iris_hfi_header *packet;
bool ipsc_properties_set;
bool opsc_properties_set;
+ struct iris_hfi_frame_info hfi_frame_info;
struct hfi_subscription_params src_subcr_params;
struct hfi_subscription_params dst_subcr_params;
};
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 d9a903ee1e06..69e383a99d84 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
@@ -70,6 +70,12 @@
#define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001
#define HFI_SYSTEM_ERROR_END 0x05FFFFFF
+#define HFI_INFORMATION_BEGIN 0x06000000
+#define HFI_INFO_UNSUPPORTED 0x06000001
+#define HFI_INFO_DATA_CORRUPT 0x06000002
+#define HFI_INFO_BUFFER_OVERFLOW 0x06000004
+#define HFI_INFORMATION_END 0x06FFFFFF
+
enum hfi_property_mode_type {
HFI_MODE_PORT_SETTINGS_CHANGE = 0x00000001,
HFI_MODE_PROPERTY = 0x00000002,
@@ -91,6 +97,15 @@ enum hfi_codec_type {
HFI_CODEC_ENCODE_AVC = 2,
};
+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,
+};
+
enum hfi_buffer_type {
HFI_BUFFER_BITSTREAM = 0x00000001,
HFI_BUFFER_RAW = 0x00000002,
@@ -114,6 +129,13 @@ enum hfi_buffer_host_flags {
HFI_BUF_HOST_FLAGS_CB_NON_SECURE = 0x00000200,
};
+enum hfi_buffer_firmware_flags {
+ HFI_BUF_FW_FLAG_RELEASE_DONE = 0x00000001,
+ HFI_BUF_FW_FLAG_READONLY = 0x00000010,
+ HFI_BUF_FW_FLAG_LAST = 0x10000000,
+ HFI_BUF_FW_FLAG_PSC_LAST = 0x20000000,
+};
+
enum hfi_packet_firmware_flags {
HFI_FW_FLAGS_SUCCESS = 0x00000001,
HFI_FW_FLAGS_INFORMATION = 0x00000002,
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 9639c7eabd6b..77c4f92b76e1 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
@@ -3,6 +3,8 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <media/v4l2-mem2mem.h>
+
#include "iris_hfi_gen2.h"
#include "iris_hfi_gen2_defines.h"
#include "iris_hfi_gen2_packet.h"
@@ -81,6 +83,29 @@ static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type)
return true;
}
+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 driver_flags = 0;
+
+ 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)
+ driver_flags |= V4L2_BUF_FLAG_PFRAME;
+ else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_B)
+ driver_flags |= V4L2_BUF_FLAG_BFRAME;
+
+ if (inst_hfi_gen2->hfi_frame_info.data_corrupt || inst_hfi_gen2->hfi_frame_info.overflow)
+ driver_flags |= V4L2_BUF_FLAG_ERROR;
+
+ if (hfi_flags & HFI_BUF_FW_FLAG_LAST ||
+ hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST)
+ driver_flags |= V4L2_BUF_FLAG_LAST;
+
+ return driver_flags;
+}
+
static bool iris_hfi_gen2_validate_packet_payload(struct iris_hfi_packet *pkt)
{
u32 payload_size = 0;
@@ -154,6 +179,37 @@ static int iris_hfi_gen2_validate_hdr_packet(struct iris_core *core, struct iris
return 0;
}
+static int iris_hfi_gen2_handle_session_info(struct iris_inst *inst,
+ struct iris_hfi_packet *pkt)
+{
+ struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
+ struct iris_core *core = inst->core;
+ int ret = 0;
+ char *info;
+
+ switch (pkt->type) {
+ case HFI_INFO_UNSUPPORTED:
+ info = "unsupported";
+ break;
+ case HFI_INFO_DATA_CORRUPT:
+ info = "data corrupt";
+ inst_hfi_gen2->hfi_frame_info.data_corrupt = 1;
+ break;
+ case HFI_INFO_BUFFER_OVERFLOW:
+ info = "buffer overflow";
+ inst_hfi_gen2->hfi_frame_info.overflow = 1;
+ break;
+ default:
+ info = "unknown";
+ break;
+ }
+
+ dev_dbg(core->dev, "session info received %#x: %s\n",
+ pkt->type, info);
+
+ return ret;
+}
+
static int iris_hfi_gen2_handle_session_error(struct iris_inst *inst,
struct iris_hfi_packet *pkt)
{
@@ -234,19 +290,108 @@ static void iris_hfi_gen2_handle_session_close(struct iris_inst *inst,
complete(&inst->completion);
}
+static int iris_hfi_gen2_handle_input_buffer(struct iris_inst *inst,
+ struct iris_hfi_buffer *buffer)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *m2m_buffer, *n;
+ struct iris_buffer *buf;
+ bool found = false;
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) {
+ buf = to_iris_buffer(&m2m_buffer->vb);
+ if (buf->index == buffer->index) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return -EINVAL;
+
+ if (!(buf->attr & BUF_ATTR_QUEUED))
+ return -EINVAL;
+
+ buf->attr &= ~BUF_ATTR_QUEUED;
+ buf->attr |= BUF_ATTR_DEQUEUED;
+
+ buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, buffer->flags);
+
+ return 0;
+}
+
+static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst,
+ struct iris_hfi_buffer *hfi_buffer)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *m2m_buffer, *n;
+ struct iris_buffer *buf;
+ bool found = false;
+
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) {
+ buf = to_iris_buffer(&m2m_buffer->vb);
+ if (buf->index == hfi_buffer->index &&
+ buf->device_addr == hfi_buffer->base_address &&
+ buf->data_offset == hfi_buffer->data_offset) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return -EINVAL;
+
+ if (!(buf->attr & BUF_ATTR_QUEUED))
+ return -EINVAL;
+
+ buf->data_offset = hfi_buffer->data_offset;
+ buf->data_size = hfi_buffer->data_size;
+ buf->timestamp = hfi_buffer->timestamp;
+
+ buf->attr &= ~BUF_ATTR_QUEUED;
+ buf->attr |= BUF_ATTR_DEQUEUED;
+
+ buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags);
+
+ return 0;
+}
+
+static void iris_hfi_gen2_handle_dequeue_buffers(struct iris_inst *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *buffer, *n;
+ struct iris_buffer *buf = NULL;
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) {
+ buf = to_iris_buffer(&buffer->vb);
+ if (buf->attr & BUF_ATTR_DEQUEUED) {
+ buf->attr &= ~BUF_ATTR_DEQUEUED;
+ if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
+ buf->attr |= BUF_ATTR_BUFFER_DONE;
+ iris_vb2_buffer_done(inst, buf);
+ }
+ }
+ }
+
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) {
+ buf = to_iris_buffer(&buffer->vb);
+ if (buf->attr & BUF_ATTR_DEQUEUED) {
+ buf->attr &= ~BUF_ATTR_DEQUEUED;
+ if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
+ buf->attr |= BUF_ATTR_BUFFER_DONE;
+ iris_vb2_buffer_done(inst, buf);
+ }
+ }
+ }
+}
+
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);
+ struct iris_buffers *buffers = &inst->buffers[buf_type];
struct iris_buffer *buf, *iter;
- struct iris_buffers *buffers;
- u32 buf_type;
+ bool found = false;
int ret = 0;
- bool found;
- buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type);
- buffers = &inst->buffers[buf_type];
-
- found = false;
list_for_each_entry(iter, &buffers->list, list) {
if (iter->device_addr == buffer->base_address) {
found = true;
@@ -258,7 +403,6 @@ 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);
@@ -285,7 +429,12 @@ 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;
- return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer);
+ 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);
}
static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst,
@@ -347,6 +496,12 @@ 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_PICTURE_TYPE:
+ inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0];
+ break;
+ case HFI_PROP_NO_OUTPUT:
+ inst_hfi_gen2->hfi_frame_info.no_output = 1;
+ break;
case HFI_PROP_QUALITY_MODE:
case HFI_PROP_STAGE:
case HFI_PROP_PIPE:
@@ -433,14 +588,18 @@ static int iris_hfi_gen2_handle_system_response(struct iris_core *core,
static int iris_hfi_gen2_handle_session_response(struct iris_core *core,
struct iris_hfi_header *hdr)
{
+ struct iris_inst_hfi_gen2 *inst_hfi_gen2;
struct iris_hfi_packet *packet;
struct iris_inst *inst;
+ bool dequeue = false;
int ret = 0;
u32 i, j;
u8 *pkt;
static const struct iris_hfi_gen2_inst_hfi_range range[] = {
{HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END,
iris_hfi_gen2_handle_session_error},
+ {HFI_INFORMATION_BEGIN, HFI_INFORMATION_END,
+ iris_hfi_gen2_handle_session_info},
{HFI_PROP_BEGIN, HFI_PROP_END,
iris_hfi_gen2_handle_session_property},
{HFI_CMD_BEGIN, HFI_CMD_END,
@@ -452,6 +611,8 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core,
return -EINVAL;
mutex_lock(&inst->lock);
+ inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
+ memset(&inst_hfi_gen2->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info));
pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
for (i = 0; i < ARRAY_SIZE(range); i++) {
@@ -462,6 +623,7 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core,
iris_hfi_gen2_handle_session_error(inst, packet);
if (packet->type > range[i].begin && packet->type < range[i].end) {
+ dequeue |= (packet->type == HFI_CMD_BUFFER);
ret = range[i].handle(inst, packet);
if (ret)
iris_inst_change_state(inst, IRIS_INST_ERROR);
@@ -470,6 +632,9 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core,
}
}
+ if (dequeue)
+ iris_hfi_gen2_handle_dequeue_buffers(inst);
+
mutex_unlock(&inst->lock);
return ret;
diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h
index fdec6a97ac6c..e970c25b6106 100644
--- a/drivers/media/platform/qcom/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/iris/iris_instance.h
@@ -35,6 +35,10 @@
* @m2m_dev: a reference to m2m device structure
* @m2m_ctx: a reference to m2m context structure
* @subscriptions: variable to hold current events subscriptions
+ * @sequence_cap: a sequence counter for capture queue
+ * @sequence_out: a sequence counter for output queue
+ * @tss: timestamp metadata
+ * @metadata_idx: index for metadata buffer
*/
struct iris_inst {
@@ -58,6 +62,10 @@ struct iris_inst {
struct v4l2_m2m_dev *m2m_dev;
struct v4l2_m2m_ctx *m2m_ctx;
unsigned int subscriptions;
+ u32 sequence_cap;
+ u32 sequence_out;
+ struct iris_ts_metadata tss[VIDEO_MAX_FRAME];
+ u32 metadata_idx;
};
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c
index 7e252ee1d165..8487a26d98ed 100644
--- a/drivers/media/platform/qcom/iris/iris_utils.c
+++ b/drivers/media/platform/qcom/iris/iris_utils.c
@@ -4,6 +4,7 @@
*/
#include <linux/pm_runtime.h>
+#include <media/v4l2-mem2mem.h>
#include "iris_instance.h"
#include "iris_utils.h"
@@ -36,6 +37,21 @@ bool iris_split_mode_enabled(struct iris_inst *inst)
return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12;
}
+void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type,
+ enum vb2_buffer_state state)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
+
+ if (V4L2_TYPE_IS_OUTPUT(type)) {
+ while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx)))
+ v4l2_m2m_buf_done(buf, state);
+ } else if (V4L2_TYPE_IS_CAPTURE(type)) {
+ while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx)))
+ v4l2_m2m_buf_done(buf, state);
+ }
+}
+
int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush)
{
struct iris_core *core = inst->core;
diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h
index 0d46f50d3103..745fcc3a22a4 100644
--- a/drivers/media/platform/qcom/iris/iris_utils.h
+++ b/drivers/media/platform/qcom/iris/iris_utils.h
@@ -16,6 +16,20 @@ struct iris_hfi_rect_desc {
u32 height;
};
+struct iris_hfi_frame_info {
+ u32 picture_type;
+ u32 no_output;
+ u32 data_corrupt;
+ u32 overflow;
+};
+
+struct iris_ts_metadata {
+ u64 ts_ns;
+ u64 ts_us;
+ u32 flags;
+ struct v4l2_timecode tc;
+};
+
#define NUM_MBS_PER_FRAME(height, width) \
(DIV_ROUND_UP(height, 16) * DIV_ROUND_UP(width, 16))
@@ -36,6 +50,8 @@ bool iris_res_is_less_than(u32 width, u32 height,
int iris_get_mbpf(struct iris_inst *inst);
bool iris_split_mode_enabled(struct iris_inst *inst);
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);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c
index 75c1364709d1..2e4b30ec963f 100644
--- a/drivers/media/platform/qcom/iris/iris_vb2.c
+++ b/drivers/media/platform/qcom/iris/iris_vb2.c
@@ -3,11 +3,23 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-mem2mem.h>
+
#include "iris_buffer.h"
#include "iris_instance.h"
#include "iris_vb2.h"
#include "iris_vdec.h"
#include "iris_vpu_buffer.h"
+int iris_vb2_buf_init(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct iris_buffer *buf = to_iris_buffer(vbuf);
+
+ buf->device_addr = vb2_dma_contig_plane_dma_addr(vb2, 0);
+
+ return 0;
+}
int iris_vb2_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
@@ -87,6 +99,7 @@ int iris_vb2_queue_setup(struct vb2_queue *q,
int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
{
+ enum iris_buffer_type buf_type;
struct iris_inst *inst;
int ret = 0;
@@ -107,6 +120,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
goto error;
}
+
if (V4L2_TYPE_IS_OUTPUT(q->type))
ret = iris_vdec_streamon_input(inst);
else if (V4L2_TYPE_IS_CAPTURE(q->type))
@@ -114,11 +128,22 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
if (ret)
goto error;
+ buf_type = iris_v4l2_type_to_driver(q->type);
+ if (buf_type == -EINVAL) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = iris_queue_deferred_buffers(inst, buf_type);
+ if (ret)
+ goto error;
+
mutex_unlock(&inst->lock);
return ret;
error:
+ iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED);
iris_inst_change_state(inst, IRIS_INST_ERROR);
mutex_unlock(&inst->lock);
@@ -128,6 +153,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
void iris_vb2_stop_streaming(struct vb2_queue *q)
{
struct iris_inst *inst;
+ int ret = 0;
inst = vb2_get_drv_priv(q);
@@ -140,8 +166,82 @@ void iris_vb2_stop_streaming(struct vb2_queue *q)
!V4L2_TYPE_IS_CAPTURE(q->type))
goto exit;
- iris_vdec_session_streamoff(inst, q->type);
+ ret = iris_vdec_session_streamoff(inst, q->type);
+ if (ret)
+ goto exit;
exit:
+ iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR);
+ if (ret)
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+
+ mutex_unlock(&inst->lock);
+}
+
+int iris_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ struct iris_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+ if (vbuf->field != V4L2_FIELD_NONE)
+ 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;
+
+ return 0;
+}
+
+int iris_vb2_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+
+ v4l2_buf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+void iris_vb2_buf_queue(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct iris_inst *inst;
+ int ret = 0;
+
+ inst = vb2_get_drv_priv(vb2->vb2_queue);
+
+ mutex_lock(&inst->lock);
+ if (inst->state == IRIS_INST_ERROR) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+
+ m2m_ctx = inst->m2m_ctx;
+
+ if (!vb2->planes[0].bytesused && V4L2_TYPE_IS_OUTPUT(vb2->type)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+
+ ret = iris_vdec_qbuf(inst, vbuf);
+
+exit:
+ if (ret) {
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ }
mutex_unlock(&inst->lock);
}
diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h
index bc3bb830c2ba..c0d22c39d197 100644
--- a/drivers/media/platform/qcom/iris/iris_vb2.h
+++ b/drivers/media/platform/qcom/iris/iris_vb2.h
@@ -6,10 +6,14 @@
#ifndef _IRIS_VB2_H_
#define _IRIS_VB2_H_
+int iris_vb2_buf_init(struct vb2_buffer *vb2);
int iris_vb2_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], struct device *alloc_devs[]);
int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count);
void iris_vb2_stop_streaming(struct vb2_queue *q);
+int iris_vb2_buf_prepare(struct vb2_buffer *vb);
+int iris_vb2_buf_out_validate(struct vb2_buffer *vb);
+void iris_vb2_buf_queue(struct vb2_buffer *vb2);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
index 9cd77b551df4..7d5ef23b5c0a 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -242,6 +242,68 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su
return ret;
}
+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;
@@ -253,23 +315,47 @@ static void iris_vdec_kill_session(struct iris_inst *inst)
iris_inst_change_state(inst, IRIS_INST_ERROR);
}
-void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane)
+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;
- return;
+ 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)
@@ -359,3 +445,67 @@ int iris_vdec_streamon_output(struct iris_inst *inst)
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);
+ if (buf->type == -EINVAL)
+ return -EINVAL;
+
+ 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);
+ struct vb2_buffer *vb2 = &vbuf->vb2_buf;
+ struct vb2_queue *q;
+ int ret;
+
+ ret = iris_vdec_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;
+ }
+
+ return iris_queue_buffer(inst, buf);
+}
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h
index b3299164f823..51bf0b96d9f0 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.h
+++ b/drivers/media/platform/qcom/iris/iris_vdec.h
@@ -16,6 +16,7 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f);
int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub);
int iris_vdec_streamon_input(struct iris_inst *inst);
int iris_vdec_streamon_output(struct iris_inst *inst);
-void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane);
+int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf);
+int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index bab9ca52de69..aaf377f2f5f5 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -7,6 +7,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
#include "iris_vidc.h"
#include "iris_instance.h"
@@ -97,6 +98,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->ops = inst->core->iris_vb2_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct iris_buffer);
src_vq->dev = inst->core->dev;
@@ -109,6 +111,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->ops = inst->core->iris_vb2_ops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct iris_buffer);
dst_vq->dev = inst->core->dev;
@@ -438,9 +441,15 @@ static struct v4l2_file_operations iris_v4l2_file_ops = {
};
static const struct vb2_ops iris_vb2_ops = {
+ .buf_init = iris_vb2_buf_init,
.queue_setup = iris_vb2_queue_setup,
.start_streaming = iris_vb2_start_streaming,
.stop_streaming = iris_vb2_stop_streaming,
+ .buf_prepare = iris_vb2_buf_prepare,
+ .buf_out_validate = iris_vb2_buf_out_validate,
+ .buf_queue = iris_vb2_buf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = {
@@ -454,6 +463,12 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = {
.vidioc_g_fmt_vid_out_mplane = iris_g_fmt_vid_mplane,
.vidioc_enum_framesizes = iris_enum_framesizes,
.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_querycap = iris_querycap,
.vidioc_queryctrl = iris_queryctrl,
.vidioc_querymenu = iris_querymenu,
--
2.34.1
On 14/10/2024 11:07, Dikshita Agarwal wrote: > Implement vb2 ops for buf queue. Below are the different > buffer attributes: > BUF_ATTR_DEFERRED - buffer queued by client but not submitted > to firmware. > BUF_ATTR_PENDING_RELEASE - buffers requested to be released > from firmware. > BUF_ATTR_QUEUED - buffers submitted to firmware. > BUF_ATTR_DEQUEUED - buffers received from firmware. > BUF_ATTR_BUFFER_DONE - buffers sent back to vb2. > > Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com> > --- > drivers/media/platform/qcom/iris/Kconfig | 1 + > drivers/media/platform/qcom/iris/iris_buffer.c | 118 +++++++++++++ > drivers/media/platform/qcom/iris/iris_buffer.h | 2 + > .../platform/qcom/iris/iris_hfi_gen1_command.c | 53 ++++++ > .../platform/qcom/iris/iris_hfi_gen1_defines.h | 80 +++++++++ > .../platform/qcom/iris/iris_hfi_gen1_response.c | 167 ++++++++++++++++++- > drivers/media/platform/qcom/iris/iris_hfi_gen2.h | 2 + > .../platform/qcom/iris/iris_hfi_gen2_defines.h | 22 +++ > .../platform/qcom/iris/iris_hfi_gen2_response.c | 183 ++++++++++++++++++++- > drivers/media/platform/qcom/iris/iris_instance.h | 8 + > drivers/media/platform/qcom/iris/iris_utils.c | 16 ++ > drivers/media/platform/qcom/iris/iris_utils.h | 16 ++ > drivers/media/platform/qcom/iris/iris_vb2.c | 102 +++++++++++- > drivers/media/platform/qcom/iris/iris_vb2.h | 4 + > drivers/media/platform/qcom/iris/iris_vdec.c | 154 ++++++++++++++++- > drivers/media/platform/qcom/iris/iris_vdec.h | 3 +- > drivers/media/platform/qcom/iris/iris_vidc.c | 15 ++ > 17 files changed, 926 insertions(+), 20 deletions(-) > > diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig > index f92cc7fe9378..3c803a05305a 100644 > --- a/drivers/media/platform/qcom/iris/Kconfig > +++ b/drivers/media/platform/qcom/iris/Kconfig > @@ -5,6 +5,7 @@ config VIDEO_QCOM_IRIS > select V4L2_MEM2MEM_DEV > select QCOM_MDT_LOADER if ARCH_QCOM > select QCOM_SCM > + select VIDEOBUF2_DMA_CONTIG > help > This is a V4L2 driver for Qualcomm iris video accelerator > hardware. It accelerates decoding operations on various > diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c > index 9fa97375d61f..8df003000dc8 100644 > --- a/drivers/media/platform/qcom/iris/iris_buffer.c > +++ b/drivers/media/platform/qcom/iris/iris_buffer.c > @@ -3,6 +3,7 @@ > * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > +#include <media/v4l2-event.h> > #include <media/v4l2-mem2mem.h> > > #include "iris_buffer.h" > @@ -434,6 +435,36 @@ int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) > return 0; > } > > +int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *buffer, *n; > + struct iris_buffer *buf; > + int ret; > + > + if (buf_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)) > + continue; > + ret = iris_queue_buffer(inst, buf); > + if (ret) > + return ret; > + } > + } else { > + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { > + buf = to_iris_buffer(&buffer->vb); > + if (!(buf->attr & BUF_ATTR_DEFERRED)) > + continue; > + ret = iris_queue_buffer(inst, buf); > + if (ret) > + return ret; > + } > + } > + > + return 0; > +} > + > void iris_vb2_queue_error(struct iris_inst *inst) > { > struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > @@ -444,3 +475,90 @@ void iris_vb2_queue_error(struct iris_inst *inst) > q = v4l2_m2m_get_dst_vq(m2m_ctx); > vb2_queue_error(q); > } > + > +static struct vb2_v4l2_buffer * > +iris_helper_find_buf(struct iris_inst *inst, u32 type, u32 idx) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + > + if (V4L2_TYPE_IS_OUTPUT(type)) > + return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx); > + else > + return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx); > +} > + > +static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns, > + struct vb2_v4l2_buffer *vbuf) > +{ > + u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; > + u32 i; > + > + for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) { > + if (inst->tss[i].ts_ns != timestamp_ns) > + continue; > + > + vbuf->flags &= ~mask; > + vbuf->flags |= inst->tss[i].flags; > + vbuf->timecode = inst->tss[i].tc; > + return; > + } > + > + vbuf->flags &= ~mask; > + vbuf->flags |= inst->tss[inst->metadata_idx].flags; > + vbuf->timecode = inst->tss[inst->metadata_idx].tc; > +} > + > +int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct vb2_v4l2_buffer *vbuf; > + struct vb2_buffer *vb2; > + u32 type, state; > + > + switch (buf->type) { > + case BUF_INPUT: > + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; > + break; > + case BUF_OUTPUT: > + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; > + break; > + default: > + return 0; /* Internal DPB Buffers */ > + } > + > + vbuf = iris_helper_find_buf(inst, type, buf->index); > + if (!vbuf) > + return -EINVAL; > + > + 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 (V4L2_TYPE_IS_CAPTURE(type)) { > + vb2_set_plane_payload(vb2, 0, buf->data_size); > + vbuf->sequence = inst->sequence_cap++; > + iris_get_ts_metadata(inst, buf->timestamp, vbuf); > + } else { > + vbuf->sequence = inst->sequence_out++; > + } > + > + if (vbuf->flags & V4L2_BUF_FLAG_LAST) { > + if (!v4l2_m2m_has_stopped(m2m_ctx) && > + inst->subscriptions & V4L2_EVENT_EOS) { > + const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; > + > + v4l2_event_queue_fh(&inst->fh, &ev); > + v4l2_m2m_mark_stopped(m2m_ctx); > + } > + } > + vb2->timestamp = buf->timestamp; > + vb2->planes[0].bytesused = buf->data_size + vb2->planes[0].data_offset; > + v4l2_m2m_buf_done(vbuf, state); > + > + return 0; > +} > diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h > index 41e090e9f0b0..bd8b74a9fbc4 100644 > --- a/drivers/media/platform/qcom/iris/iris_buffer.h > +++ b/drivers/media/platform/qcom/iris/iris_buffer.h > @@ -109,6 +109,8 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf > int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane); > int iris_alloc_and_queue_persist_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); > +int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf); > void iris_vb2_queue_error(struct iris_inst *inst); > > #endif > 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 ee7d9beca33b..82f2513576bf 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c > @@ -180,6 +180,10 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) > ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); > if (!ret) > ret = iris_wait_for_session_response(inst, false); > + 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; > @@ -201,6 +205,50 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) > return ret; > } > > +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); > +} > + > +static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf) > +{ > + struct hfi_session_fill_buffer_pkt op_pkt; > + > + op_pkt.shdr.hdr.size = sizeof(struct hfi_session_fill_buffer_pkt); > + op_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FILL_BUFFER; > + op_pkt.shdr.session_id = inst->session_id; > + op_pkt.output_tag = buf->index; > + op_pkt.packet_buffer = buf->device_addr; > + op_pkt.extradata_buffer = 0; > + op_pkt.alloc_len = buf->buffer_size; > + op_pkt.filled_len = buf->data_size; > + op_pkt.offset = buf->data_offset; > + op_pkt.data = 0; > + > + if (buf->type == BUF_OUTPUT && iris_split_mode_enabled(inst)) > + op_pkt.stream_id = 1; > + else > + op_pkt.stream_id = 0; > + > + return iris_hfi_queue_cmd_write(inst->core, &op_pkt, op_pkt.shdr.hdr.size); > +} > + > static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf) > { > struct hfi_session_set_buffers_pkt *int_pkt; > @@ -240,6 +288,11 @@ static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct ir > static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf) > { > switch (buf->type) { > + case BUF_INPUT: > + return iris_hfi_gen1_queue_input_buffer(inst, buf); > + case BUF_OUTPUT: > + case BUF_DPB: > + return iris_hfi_gen1_queue_output_buffer(inst, buf); > case BUF_PERSIST: > case BUF_BIN: > case BUF_SCRATCH_1: > 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 5527233b03e5..b7f9e0f47675 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h > @@ -29,11 +29,14 @@ > #define HFI_CMD_SESSION_LOAD_RESOURCES 0x211001 > #define HFI_CMD_SESSION_START 0x211002 > #define HFI_CMD_SESSION_STOP 0x211003 > +#define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004 > +#define HFI_CMD_SESSION_FILL_BUFFER 0x211005 > #define HFI_CMD_SESSION_FLUSH 0x211008 > #define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b > #define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c > > #define HFI_ERR_SESSION_UNSUPPORTED_SETTING 0x1008 > +#define HFI_ERR_SESSION_UNSUPPORTED_STREAM 0x100d > #define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE 0x1010 > #define HFI_ERR_SESSION_INVALID_SCALE_FACTOR 0x1012 > #define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED 0x1013 > @@ -41,6 +44,8 @@ > #define HFI_EVENT_SYS_ERROR 0x1 > #define HFI_EVENT_SESSION_ERROR 0x2 > > +#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 > + > #define HFI_FLUSH_OUTPUT 0x1000002 > #define HFI_FLUSH_OUTPUT2 0x1000003 > #define HFI_FLUSH_ALL 0x1000004 > @@ -84,9 +89,19 @@ > #define HFI_MSG_SESSION_START 0x221002 > #define HFI_MSG_SESSION_STOP 0x221003 > #define HFI_MSG_SESSION_FLUSH 0x221006 > +#define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007 > +#define HFI_MSG_SESSION_FILL_BUFFER 0x221008 > #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_FRAME_NOTCODED 0x7f002000 > +#define HFI_FRAME_YUV 0x7f004000 > +#define HFI_UNUSED_PICT 0x10000000 > + > struct hfi_pkt_hdr { > u32 size; > u32 pkt_type; > @@ -144,6 +159,34 @@ struct hfi_session_set_buffers_pkt { > u32 buffer_info[]; > }; > > +struct hfi_session_empty_buffer_compressed_pkt { > + struct hfi_session_hdr_pkt shdr; > + u32 time_stamp_hi; > + u32 time_stamp_lo; > + u32 flags; > + u32 mark_target; > + u32 mark_data; > + u32 offset; > + u32 alloc_len; > + u32 filled_len; > + 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; > + u32 offset; > + u32 alloc_len; > + u32 filled_len; > + u32 output_tag; > + u32 packet_buffer; > + u32 extradata_buffer; > + u32 data; > +}; > + > struct hfi_session_flush_pkt { > struct hfi_session_hdr_pkt shdr; > u32 flush_type; > @@ -258,6 +301,43 @@ struct hfi_multi_stream { > u32 enable; > }; > > +struct hfi_msg_session_empty_buffer_done_pkt { > + struct hfi_msg_session_hdr_pkt shdr; > + u32 offset; > + u32 filled_len; > + u32 input_tag; > + 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; > + u32 view_id; > + u32 error_type; > + u32 time_stamp_hi; > + u32 time_stamp_lo; > + u32 flags; > + u32 mark_target; > + u32 mark_data; > + u32 stats; > + u32 alloc_len; > + u32 filled_len; > + u32 offset; > + u32 frame_width; > + u32 frame_height; > + u32 start_x_coord; > + u32 start_y_coord; > + u32 input_tag; > + u32 input_tag2; > + u32 output_tag; > + u32 picture_type; > + u32 packet_buffer; > + u32 extradata_buffer; > + u32 data[]; > +}; > + > struct hfi_msg_session_release_buffers_done_pkt { > struct hfi_msg_session_hdr_pkt shdr; > u32 num_buffers; > 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 a84bb00388d9..23a8bf29e381 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c > @@ -3,6 +3,8 @@ > * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > +#include <media/v4l2-mem2mem.h> > + > #include "iris_hfi_gen1.h" > #include "iris_hfi_gen1_defines.h" > #include "iris_instance.h" > @@ -130,6 +132,143 @@ static void iris_hfi_gen1_sys_property_info(struct iris_core *core, void *packet > } > } > > +static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) > +{ > + struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet; > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *m2m_buffer, *n; > + struct iris_buffer *buf = NULL; > + bool found = false; > + > + 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) { > + found = true; > + break; > + } > + } > + if (!found) > + goto error; > + > + if (pkt->shdr.error_type == HFI_ERR_SESSION_UNSUPPORTED_STREAM) { > + buf->flags = V4L2_BUF_FLAG_ERROR; > + iris_vb2_queue_error(inst); > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + } > + > + if (!(buf->attr & BUF_ATTR_QUEUED)) > + return; > + > + buf->attr &= ~BUF_ATTR_QUEUED; > + > + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { > + buf->attr |= BUF_ATTR_BUFFER_DONE; > + iris_vb2_buffer_done(inst, buf); > + } > + > + return; > + > +error: > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + dev_err(inst->core->dev, "error in etb done\n"); > +} > + > +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 v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *m2m_buffer, *n; > + u32 timestamp_hi = pkt->time_stamp_hi; > + u32 timestamp_lo = pkt->time_stamp_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; > + struct iris_buffer *buf, *iter; > + struct iris_buffers *buffers; > + u32 offset = pkt->offset; > + u64 timestamp_us = 0; > + bool found = false; > + u32 flags = 0; > + > + if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) { > + buffers = &inst->buffers[BUF_DPB]; > + if (!buffers) > + goto error; > + > + found = false; > + list_for_each_entry(iter, &buffers->list, list) { > + if (!(iter->attr & BUF_ATTR_QUEUED)) > + continue; > + > + found = (iter->index == output_tag && > + iter->data_offset == offset); > + > + if (found) { > + buf = iter; > + break; > + } > + } > + } else { > + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) { > + buf = to_iris_buffer(&m2m_buffer->vb); > + if (!(buf->attr & BUF_ATTR_QUEUED)) > + continue; > + > + found = (buf->index == output_tag && > + buf->data_offset == offset); > + > + if (found) > + break; > + } > + } > + if (!found) > + goto error; > + > + buf->data_offset = offset; > + buf->data_size = filled_len; > + > + if (filled_len) { > + timestamp_us = timestamp_hi; > + timestamp_us = (timestamp_us << 32) | timestamp_lo; > + } else { > + flags |= V4L2_BUF_FLAG_LAST; > + } > + buf->timestamp = timestamp_us; > + > + switch (pic_type) { > + case HFI_PICTURE_IDR: > + case HFI_PICTURE_I: > + flags |= V4L2_BUF_FLAG_KEYFRAME; > + break; > + case HFI_PICTURE_P: > + flags |= V4L2_BUF_FLAG_PFRAME; > + break; > + case HFI_PICTURE_B: > + flags |= V4L2_BUF_FLAG_BFRAME; > + break; > + case HFI_FRAME_NOTCODED: > + case HFI_UNUSED_PICT: > + case HFI_FRAME_YUV: > + default: > + break; > + } > + > + buf->attr &= ~BUF_ATTR_QUEUED; > + buf->attr |= BUF_ATTR_DEQUEUED; > + buf->attr |= BUF_ATTR_BUFFER_DONE; > + > + buf->flags |= flags; > + > + iris_vb2_buffer_done(inst, buf); > + > + return; > + > +error: > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + dev_err(core->dev, "error in ftb done\n"); > +} > + > struct iris_hfi_gen1_response_pkt_info { > u32 pkt; > u32 pkt_sz; > @@ -168,6 +307,14 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { > .pkt = HFI_MSG_SESSION_STOP, > .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt), > }, > + { > + .pkt = HFI_MSG_SESSION_EMPTY_BUFFER, > + .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt), > + }, > + { > + .pkt = HFI_MSG_SESSION_FILL_BUFFER, > + .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), > + }, > { > .pkt = HFI_MSG_SESSION_FLUSH, > .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt), > @@ -238,15 +385,21 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response > } > > mutex_lock(&inst->lock); > - struct hfi_msg_session_hdr_pkt *shdr; > + if (hdr->pkt_type == HFI_MSG_SESSION_EMPTY_BUFFER) { > + iris_hfi_gen1_session_etb_done(inst, hdr); > + } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) { > + iris_hfi_gen1_session_ftb_done(inst, hdr); > + } else { > + struct hfi_msg_session_hdr_pkt *shdr; > > - shdr = (struct hfi_msg_session_hdr_pkt *)hdr; > - if (shdr->error_type != HFI_ERR_NONE) > - iris_inst_change_state(inst, IRIS_INST_ERROR); > + shdr = (struct hfi_msg_session_hdr_pkt *)hdr; > + 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); > + done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ? > + &inst->flush_completion : &inst->completion; > + complete(done); > + } > mutex_unlock(&inst->lock); > > break; > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > index 5fbbab844025..bf3aa1afb5bb 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > @@ -20,6 +20,7 @@ struct iris_core; > * @packet: HFI packet > * @ipsc_properties_set: boolean to set ipsc properties to fw > * @opsc_properties_set: boolean to set opsc properties to fw > + * @hfi_frame_info: structure of frame info > * @src_subcr_params: subscription params to fw on input port > * @dst_subcr_params: subscription params to fw on output port > */ > @@ -28,6 +29,7 @@ struct iris_inst_hfi_gen2 { > struct iris_hfi_header *packet; > bool ipsc_properties_set; > bool opsc_properties_set; > + struct iris_hfi_frame_info hfi_frame_info; > struct hfi_subscription_params src_subcr_params; > struct hfi_subscription_params dst_subcr_params; > }; > 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 d9a903ee1e06..69e383a99d84 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > @@ -70,6 +70,12 @@ > #define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001 > #define HFI_SYSTEM_ERROR_END 0x05FFFFFF > > +#define HFI_INFORMATION_BEGIN 0x06000000 > +#define HFI_INFO_UNSUPPORTED 0x06000001 > +#define HFI_INFO_DATA_CORRUPT 0x06000002 > +#define HFI_INFO_BUFFER_OVERFLOW 0x06000004 > +#define HFI_INFORMATION_END 0x06FFFFFF > + > enum hfi_property_mode_type { > HFI_MODE_PORT_SETTINGS_CHANGE = 0x00000001, > HFI_MODE_PROPERTY = 0x00000002, > @@ -91,6 +97,15 @@ enum hfi_codec_type { > HFI_CODEC_ENCODE_AVC = 2, > }; > > +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, > +}; > + > enum hfi_buffer_type { > HFI_BUFFER_BITSTREAM = 0x00000001, > HFI_BUFFER_RAW = 0x00000002, > @@ -114,6 +129,13 @@ enum hfi_buffer_host_flags { > HFI_BUF_HOST_FLAGS_CB_NON_SECURE = 0x00000200, > }; > > +enum hfi_buffer_firmware_flags { > + HFI_BUF_FW_FLAG_RELEASE_DONE = 0x00000001, > + HFI_BUF_FW_FLAG_READONLY = 0x00000010, > + HFI_BUF_FW_FLAG_LAST = 0x10000000, > + HFI_BUF_FW_FLAG_PSC_LAST = 0x20000000, > +}; > + > enum hfi_packet_firmware_flags { > HFI_FW_FLAGS_SUCCESS = 0x00000001, > HFI_FW_FLAGS_INFORMATION = 0x00000002, > 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 9639c7eabd6b..77c4f92b76e1 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c > @@ -3,6 +3,8 @@ > * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > +#include <media/v4l2-mem2mem.h> > + > #include "iris_hfi_gen2.h" > #include "iris_hfi_gen2_defines.h" > #include "iris_hfi_gen2_packet.h" > @@ -81,6 +83,29 @@ static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type) > return true; > } > > +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 driver_flags = 0; > + > + 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) > + driver_flags |= V4L2_BUF_FLAG_PFRAME; > + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_B) > + driver_flags |= V4L2_BUF_FLAG_BFRAME; > + > + if (inst_hfi_gen2->hfi_frame_info.data_corrupt || inst_hfi_gen2->hfi_frame_info.overflow) > + driver_flags |= V4L2_BUF_FLAG_ERROR; > + > + if (hfi_flags & HFI_BUF_FW_FLAG_LAST || > + hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST) > + driver_flags |= V4L2_BUF_FLAG_LAST; > + > + return driver_flags; > +} > + > static bool iris_hfi_gen2_validate_packet_payload(struct iris_hfi_packet *pkt) > { > u32 payload_size = 0; > @@ -154,6 +179,37 @@ static int iris_hfi_gen2_validate_hdr_packet(struct iris_core *core, struct iris > return 0; > } > > +static int iris_hfi_gen2_handle_session_info(struct iris_inst *inst, > + struct iris_hfi_packet *pkt) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + struct iris_core *core = inst->core; > + int ret = 0; > + char *info; > + > + switch (pkt->type) { > + case HFI_INFO_UNSUPPORTED: > + info = "unsupported"; > + break; > + case HFI_INFO_DATA_CORRUPT: > + info = "data corrupt"; > + inst_hfi_gen2->hfi_frame_info.data_corrupt = 1; > + break; > + case HFI_INFO_BUFFER_OVERFLOW: > + info = "buffer overflow"; > + inst_hfi_gen2->hfi_frame_info.overflow = 1; > + break; > + default: > + info = "unknown"; > + break; > + } > + > + dev_dbg(core->dev, "session info received %#x: %s\n", > + pkt->type, info); > + > + return ret; > +} > + > static int iris_hfi_gen2_handle_session_error(struct iris_inst *inst, > struct iris_hfi_packet *pkt) > { > @@ -234,19 +290,108 @@ static void iris_hfi_gen2_handle_session_close(struct iris_inst *inst, > complete(&inst->completion); > } > > +static int iris_hfi_gen2_handle_input_buffer(struct iris_inst *inst, > + struct iris_hfi_buffer *buffer) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *m2m_buffer, *n; > + struct iris_buffer *buf; > + bool found = false; > + > + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { > + buf = to_iris_buffer(&m2m_buffer->vb); > + if (buf->index == buffer->index) { > + found = true; > + break; > + } > + } > + if (!found) > + return -EINVAL; > + > + if (!(buf->attr & BUF_ATTR_QUEUED)) > + return -EINVAL; > + > + buf->attr &= ~BUF_ATTR_QUEUED; > + buf->attr |= BUF_ATTR_DEQUEUED; > + > + buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, buffer->flags); > + > + return 0; > +} > + > +static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst, > + struct iris_hfi_buffer *hfi_buffer) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *m2m_buffer, *n; > + struct iris_buffer *buf; > + bool found = false; > + > + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) { > + buf = to_iris_buffer(&m2m_buffer->vb); > + if (buf->index == hfi_buffer->index && > + buf->device_addr == hfi_buffer->base_address && > + buf->data_offset == hfi_buffer->data_offset) { > + found = true; > + break; > + } > + } > + if (!found) > + return -EINVAL; > + > + if (!(buf->attr & BUF_ATTR_QUEUED)) > + return -EINVAL; > + > + buf->data_offset = hfi_buffer->data_offset; > + buf->data_size = hfi_buffer->data_size; > + buf->timestamp = hfi_buffer->timestamp; > + > + buf->attr &= ~BUF_ATTR_QUEUED; > + buf->attr |= BUF_ATTR_DEQUEUED; > + > + buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags); > + > + return 0; > +} > + > +static void iris_hfi_gen2_handle_dequeue_buffers(struct iris_inst *inst) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct v4l2_m2m_buffer *buffer, *n; > + struct iris_buffer *buf = NULL; > + > + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { > + buf = to_iris_buffer(&buffer->vb); > + if (buf->attr & BUF_ATTR_DEQUEUED) { > + buf->attr &= ~BUF_ATTR_DEQUEUED; > + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { > + buf->attr |= BUF_ATTR_BUFFER_DONE; > + iris_vb2_buffer_done(inst, buf); > + } > + } > + } > + > + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { > + buf = to_iris_buffer(&buffer->vb); > + if (buf->attr & BUF_ATTR_DEQUEUED) { > + buf->attr &= ~BUF_ATTR_DEQUEUED; > + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { > + buf->attr |= BUF_ATTR_BUFFER_DONE; > + iris_vb2_buffer_done(inst, buf); > + } > + } > + } > +} > + > 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); > + struct iris_buffers *buffers = &inst->buffers[buf_type]; > struct iris_buffer *buf, *iter; > - struct iris_buffers *buffers; > - u32 buf_type; > + bool found = false; > int ret = 0; > - bool found; > > - buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type); > - buffers = &inst->buffers[buf_type]; > - > - found = false; > list_for_each_entry(iter, &buffers->list, list) { > if (iter->device_addr == buffer->base_address) { > found = true; > @@ -258,7 +403,6 @@ 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); > > @@ -285,7 +429,12 @@ 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; > > - return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); > + 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); > } > > static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst, > @@ -347,6 +496,12 @@ 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_PICTURE_TYPE: > + inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; > + break; > + case HFI_PROP_NO_OUTPUT: > + inst_hfi_gen2->hfi_frame_info.no_output = 1; > + break; > case HFI_PROP_QUALITY_MODE: > case HFI_PROP_STAGE: > case HFI_PROP_PIPE: > @@ -433,14 +588,18 @@ static int iris_hfi_gen2_handle_system_response(struct iris_core *core, > static int iris_hfi_gen2_handle_session_response(struct iris_core *core, > struct iris_hfi_header *hdr) > { > + struct iris_inst_hfi_gen2 *inst_hfi_gen2; > struct iris_hfi_packet *packet; > struct iris_inst *inst; > + bool dequeue = false; > int ret = 0; > u32 i, j; > u8 *pkt; > static const struct iris_hfi_gen2_inst_hfi_range range[] = { > {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, > iris_hfi_gen2_handle_session_error}, > + {HFI_INFORMATION_BEGIN, HFI_INFORMATION_END, > + iris_hfi_gen2_handle_session_info}, > {HFI_PROP_BEGIN, HFI_PROP_END, > iris_hfi_gen2_handle_session_property}, > {HFI_CMD_BEGIN, HFI_CMD_END, > @@ -452,6 +611,8 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, > return -EINVAL; > > mutex_lock(&inst->lock); > + inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + memset(&inst_hfi_gen2->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info)); > > pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); > for (i = 0; i < ARRAY_SIZE(range); i++) { > @@ -462,6 +623,7 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, > iris_hfi_gen2_handle_session_error(inst, packet); > > if (packet->type > range[i].begin && packet->type < range[i].end) { > + dequeue |= (packet->type == HFI_CMD_BUFFER); > ret = range[i].handle(inst, packet); > if (ret) > iris_inst_change_state(inst, IRIS_INST_ERROR); > @@ -470,6 +632,9 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, > } > } > > + if (dequeue) > + iris_hfi_gen2_handle_dequeue_buffers(inst); > + > mutex_unlock(&inst->lock); > > return ret; > diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h > index fdec6a97ac6c..e970c25b6106 100644 > --- a/drivers/media/platform/qcom/iris/iris_instance.h > +++ b/drivers/media/platform/qcom/iris/iris_instance.h > @@ -35,6 +35,10 @@ > * @m2m_dev: a reference to m2m device structure > * @m2m_ctx: a reference to m2m context structure > * @subscriptions: variable to hold current events subscriptions > + * @sequence_cap: a sequence counter for capture queue > + * @sequence_out: a sequence counter for output queue > + * @tss: timestamp metadata > + * @metadata_idx: index for metadata buffer > */ > > struct iris_inst { > @@ -58,6 +62,10 @@ struct iris_inst { > struct v4l2_m2m_dev *m2m_dev; > struct v4l2_m2m_ctx *m2m_ctx; > unsigned int subscriptions; > + u32 sequence_cap; > + u32 sequence_out; > + struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; > + u32 metadata_idx; > }; > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c > index 7e252ee1d165..8487a26d98ed 100644 > --- a/drivers/media/platform/qcom/iris/iris_utils.c > +++ b/drivers/media/platform/qcom/iris/iris_utils.c > @@ -4,6 +4,7 @@ > */ > > #include <linux/pm_runtime.h> > +#include <media/v4l2-mem2mem.h> > > #include "iris_instance.h" > #include "iris_utils.h" > @@ -36,6 +37,21 @@ bool iris_split_mode_enabled(struct iris_inst *inst) > return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12; > } > > +void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, > + enum vb2_buffer_state state) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct vb2_v4l2_buffer *buf; > + > + if (V4L2_TYPE_IS_OUTPUT(type)) { > + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) > + v4l2_m2m_buf_done(buf, state); > + } else if (V4L2_TYPE_IS_CAPTURE(type)) { > + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) > + v4l2_m2m_buf_done(buf, state); > + } > +} > + > int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush) > { > struct iris_core *core = inst->core; > diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h > index 0d46f50d3103..745fcc3a22a4 100644 > --- a/drivers/media/platform/qcom/iris/iris_utils.h > +++ b/drivers/media/platform/qcom/iris/iris_utils.h > @@ -16,6 +16,20 @@ struct iris_hfi_rect_desc { > u32 height; > }; > > +struct iris_hfi_frame_info { > + u32 picture_type; > + u32 no_output; > + u32 data_corrupt; > + u32 overflow; > +}; > + > +struct iris_ts_metadata { > + u64 ts_ns; > + u64 ts_us; > + u32 flags; > + struct v4l2_timecode tc; > +}; > + > #define NUM_MBS_PER_FRAME(height, width) \ > (DIV_ROUND_UP(height, 16) * DIV_ROUND_UP(width, 16)) > > @@ -36,6 +50,8 @@ bool iris_res_is_less_than(u32 width, u32 height, > int iris_get_mbpf(struct iris_inst *inst); > bool iris_split_mode_enabled(struct iris_inst *inst); > 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); > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c > index 75c1364709d1..2e4b30ec963f 100644 > --- a/drivers/media/platform/qcom/iris/iris_vb2.c > +++ b/drivers/media/platform/qcom/iris/iris_vb2.c > @@ -3,11 +3,23 @@ > * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > +#include <media/videobuf2-dma-contig.h> > +#include <media/v4l2-mem2mem.h> > + > #include "iris_buffer.h" > #include "iris_instance.h" > #include "iris_vb2.h" > #include "iris_vdec.h" > #include "iris_vpu_buffer.h" > +int iris_vb2_buf_init(struct vb2_buffer *vb2) > +{ > + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); > + struct iris_buffer *buf = to_iris_buffer(vbuf); > + > + buf->device_addr = vb2_dma_contig_plane_dma_addr(vb2, 0); > + > + return 0; > +} > > int iris_vb2_queue_setup(struct vb2_queue *q, > unsigned int *num_buffers, unsigned int *num_planes, > @@ -87,6 +99,7 @@ int iris_vb2_queue_setup(struct vb2_queue *q, > > int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) > { > + enum iris_buffer_type buf_type; > struct iris_inst *inst; > int ret = 0; > > @@ -107,6 +120,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) > goto error; > } > > + > if (V4L2_TYPE_IS_OUTPUT(q->type)) > ret = iris_vdec_streamon_input(inst); > else if (V4L2_TYPE_IS_CAPTURE(q->type)) > @@ -114,11 +128,22 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) > if (ret) > goto error; > > + buf_type = iris_v4l2_type_to_driver(q->type); > + if (buf_type == -EINVAL) { > + ret = -EINVAL; > + goto error; > + } > + > + ret = iris_queue_deferred_buffers(inst, buf_type); > + if (ret) > + goto error; > + > mutex_unlock(&inst->lock); > > return ret; > > error: > + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); Ah, you added this in this patch. Disregard my earlier comments about not returning buffers in start/stop_streaming. > iris_inst_change_state(inst, IRIS_INST_ERROR); > mutex_unlock(&inst->lock); > > @@ -128,6 +153,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) > void iris_vb2_stop_streaming(struct vb2_queue *q) > { > struct iris_inst *inst; > + int ret = 0; > > inst = vb2_get_drv_priv(q); > > @@ -140,8 +166,82 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) > !V4L2_TYPE_IS_CAPTURE(q->type)) > goto exit; > > - iris_vdec_session_streamoff(inst, q->type); > + ret = iris_vdec_session_streamoff(inst, q->type); > + if (ret) > + goto exit; > > exit: > + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); > + if (ret) > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + > + mutex_unlock(&inst->lock); > +} > + > +int iris_vb2_buf_prepare(struct vb2_buffer *vb) > +{ > + struct iris_inst *inst = vb2_get_drv_priv(vb->vb2_queue); > + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); > + > + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { > + if (vbuf->field == V4L2_FIELD_ANY) > + vbuf->field = V4L2_FIELD_NONE; > + if (vbuf->field != V4L2_FIELD_NONE) > + 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; > + > + return 0; > +} > + > +int iris_vb2_buf_out_validate(struct vb2_buffer *vb) > +{ > + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); > + > + v4l2_buf->field = V4L2_FIELD_NONE; > + > + return 0; > +} > + > +void iris_vb2_buf_queue(struct vb2_buffer *vb2) > +{ > + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); > + struct v4l2_m2m_ctx *m2m_ctx; > + struct iris_inst *inst; > + int ret = 0; > + > + inst = vb2_get_drv_priv(vb2->vb2_queue); > + > + mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; > + goto exit; > + } > + > + if (vbuf->field == V4L2_FIELD_ANY) > + vbuf->field = V4L2_FIELD_NONE; > + > + m2m_ctx = inst->m2m_ctx; > + > + if (!vb2->planes[0].bytesused && V4L2_TYPE_IS_OUTPUT(vb2->type)) { > + ret = -EINVAL; > + goto exit; > + } > + > + v4l2_m2m_buf_queue(m2m_ctx, vbuf); > + > + ret = iris_vdec_qbuf(inst, vbuf); > + > +exit: > + if (ret) { > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); > + } > mutex_unlock(&inst->lock); > } > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h > index bc3bb830c2ba..c0d22c39d197 100644 > --- a/drivers/media/platform/qcom/iris/iris_vb2.h > +++ b/drivers/media/platform/qcom/iris/iris_vb2.h > @@ -6,10 +6,14 @@ > #ifndef _IRIS_VB2_H_ > #define _IRIS_VB2_H_ > > +int iris_vb2_buf_init(struct vb2_buffer *vb2); > int iris_vb2_queue_setup(struct vb2_queue *q, > unsigned int *num_buffers, unsigned int *num_planes, > unsigned int sizes[], struct device *alloc_devs[]); > int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count); > void iris_vb2_stop_streaming(struct vb2_queue *q); > +int iris_vb2_buf_prepare(struct vb2_buffer *vb); > +int iris_vb2_buf_out_validate(struct vb2_buffer *vb); > +void iris_vb2_buf_queue(struct vb2_buffer *vb2); > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c > index 9cd77b551df4..7d5ef23b5c0a 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.c > +++ b/drivers/media/platform/qcom/iris/iris_vdec.c > @@ -242,6 +242,68 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su > return ret; > } > > +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; > @@ -253,23 +315,47 @@ static void iris_vdec_kill_session(struct iris_inst *inst) > iris_inst_change_state(inst, IRIS_INST_ERROR); > } > > -void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) > +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; > > - return; > + 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) > @@ -359,3 +445,67 @@ int iris_vdec_streamon_output(struct iris_inst *inst) > > 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); > + if (buf->type == -EINVAL) > + return -EINVAL; > + > + 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); > + struct vb2_buffer *vb2 = &vbuf->vb2_buf; > + struct vb2_queue *q; > + int ret; > + > + ret = iris_vdec_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; > + } > + > + return iris_queue_buffer(inst, buf); > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h > index b3299164f823..51bf0b96d9f0 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.h > +++ b/drivers/media/platform/qcom/iris/iris_vdec.h > @@ -16,6 +16,7 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); > int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); > int iris_vdec_streamon_input(struct iris_inst *inst); > int iris_vdec_streamon_output(struct iris_inst *inst); > -void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); > +int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); > +int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c > index bab9ca52de69..aaf377f2f5f5 100644 > --- a/drivers/media/platform/qcom/iris/iris_vidc.c > +++ b/drivers/media/platform/qcom/iris/iris_vidc.c > @@ -7,6 +7,7 @@ > #include <media/v4l2-event.h> > #include <media/v4l2-ioctl.h> > #include <media/v4l2-mem2mem.h> > +#include <media/videobuf2-dma-contig.h> > > #include "iris_vidc.h" > #include "iris_instance.h" > @@ -97,6 +98,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ > src_vq->io_modes = VB2_MMAP | VB2_DMABUF; > src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > src_vq->ops = inst->core->iris_vb2_ops; > + src_vq->mem_ops = &vb2_dma_contig_memops; > src_vq->drv_priv = inst; > src_vq->buf_struct_size = sizeof(struct iris_buffer); > src_vq->dev = inst->core->dev; > @@ -109,6 +111,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ > dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; > dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > dst_vq->ops = inst->core->iris_vb2_ops; > + dst_vq->mem_ops = &vb2_dma_contig_memops; > dst_vq->drv_priv = inst; > dst_vq->buf_struct_size = sizeof(struct iris_buffer); > dst_vq->dev = inst->core->dev; > @@ -438,9 +441,15 @@ static struct v4l2_file_operations iris_v4l2_file_ops = { > }; > > static const struct vb2_ops iris_vb2_ops = { > + .buf_init = iris_vb2_buf_init, > .queue_setup = iris_vb2_queue_setup, > .start_streaming = iris_vb2_start_streaming, > .stop_streaming = iris_vb2_stop_streaming, > + .buf_prepare = iris_vb2_buf_prepare, > + .buf_out_validate = iris_vb2_buf_out_validate, > + .buf_queue = iris_vb2_buf_queue, > + .wait_prepare = vb2_ops_wait_prepare, > + .wait_finish = vb2_ops_wait_finish, These two ops are no longer needed after commit 88785982a19d ("media: vb2: use lock if wait_prepare/finish are NULL"). Please drop these. > }; > > static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { > @@ -454,6 +463,12 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { > .vidioc_g_fmt_vid_out_mplane = iris_g_fmt_vid_mplane, > .vidioc_enum_framesizes = iris_enum_framesizes, > .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_querycap = iris_querycap, > .vidioc_queryctrl = iris_queryctrl, > .vidioc_querymenu = iris_querymenu, > Regards, Hans
On 10/23/2024 4:49 PM, Hans Verkuil wrote: > On 14/10/2024 11:07, Dikshita Agarwal wrote: >> Implement vb2 ops for buf queue. Below are the different >> buffer attributes: >> BUF_ATTR_DEFERRED - buffer queued by client but not submitted >> to firmware. >> BUF_ATTR_PENDING_RELEASE - buffers requested to be released >> from firmware. >> BUF_ATTR_QUEUED - buffers submitted to firmware. >> BUF_ATTR_DEQUEUED - buffers received from firmware. >> BUF_ATTR_BUFFER_DONE - buffers sent back to vb2. >> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com> >> --- >> drivers/media/platform/qcom/iris/Kconfig | 1 + >> drivers/media/platform/qcom/iris/iris_buffer.c | 118 +++++++++++++ >> drivers/media/platform/qcom/iris/iris_buffer.h | 2 + >> .../platform/qcom/iris/iris_hfi_gen1_command.c | 53 ++++++ >> .../platform/qcom/iris/iris_hfi_gen1_defines.h | 80 +++++++++ >> .../platform/qcom/iris/iris_hfi_gen1_response.c | 167 ++++++++++++++++++- >> drivers/media/platform/qcom/iris/iris_hfi_gen2.h | 2 + >> .../platform/qcom/iris/iris_hfi_gen2_defines.h | 22 +++ >> .../platform/qcom/iris/iris_hfi_gen2_response.c | 183 ++++++++++++++++++++- >> drivers/media/platform/qcom/iris/iris_instance.h | 8 + >> drivers/media/platform/qcom/iris/iris_utils.c | 16 ++ >> drivers/media/platform/qcom/iris/iris_utils.h | 16 ++ >> drivers/media/platform/qcom/iris/iris_vb2.c | 102 +++++++++++- >> drivers/media/platform/qcom/iris/iris_vb2.h | 4 + >> drivers/media/platform/qcom/iris/iris_vdec.c | 154 ++++++++++++++++- >> drivers/media/platform/qcom/iris/iris_vdec.h | 3 +- >> drivers/media/platform/qcom/iris/iris_vidc.c | 15 ++ >> 17 files changed, 926 insertions(+), 20 deletions(-) >> >> diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig >> index f92cc7fe9378..3c803a05305a 100644 >> --- a/drivers/media/platform/qcom/iris/Kconfig >> +++ b/drivers/media/platform/qcom/iris/Kconfig >> @@ -5,6 +5,7 @@ config VIDEO_QCOM_IRIS >> select V4L2_MEM2MEM_DEV >> select QCOM_MDT_LOADER if ARCH_QCOM >> select QCOM_SCM >> + select VIDEOBUF2_DMA_CONTIG >> help >> This is a V4L2 driver for Qualcomm iris video accelerator >> hardware. It accelerates decoding operations on various >> diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c >> index 9fa97375d61f..8df003000dc8 100644 >> --- a/drivers/media/platform/qcom/iris/iris_buffer.c >> +++ b/drivers/media/platform/qcom/iris/iris_buffer.c >> @@ -3,6 +3,7 @@ >> * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> */ >> >> +#include <media/v4l2-event.h> >> #include <media/v4l2-mem2mem.h> >> >> #include "iris_buffer.h" >> @@ -434,6 +435,36 @@ int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) >> return 0; >> } >> >> +int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *buffer, *n; >> + struct iris_buffer *buf; >> + int ret; >> + >> + if (buf_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)) >> + continue; >> + ret = iris_queue_buffer(inst, buf); >> + if (ret) >> + return ret; >> + } >> + } else { >> + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { >> + buf = to_iris_buffer(&buffer->vb); >> + if (!(buf->attr & BUF_ATTR_DEFERRED)) >> + continue; >> + ret = iris_queue_buffer(inst, buf); >> + if (ret) >> + return ret; >> + } >> + } >> + >> + return 0; >> +} >> + >> void iris_vb2_queue_error(struct iris_inst *inst) >> { >> struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> @@ -444,3 +475,90 @@ void iris_vb2_queue_error(struct iris_inst *inst) >> q = v4l2_m2m_get_dst_vq(m2m_ctx); >> vb2_queue_error(q); >> } >> + >> +static struct vb2_v4l2_buffer * >> +iris_helper_find_buf(struct iris_inst *inst, u32 type, u32 idx) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + >> + if (V4L2_TYPE_IS_OUTPUT(type)) >> + return v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx); >> + else >> + return v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, idx); >> +} >> + >> +static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns, >> + struct vb2_v4l2_buffer *vbuf) >> +{ >> + u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; >> + u32 i; >> + >> + for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) { >> + if (inst->tss[i].ts_ns != timestamp_ns) >> + continue; >> + >> + vbuf->flags &= ~mask; >> + vbuf->flags |= inst->tss[i].flags; >> + vbuf->timecode = inst->tss[i].tc; >> + return; >> + } >> + >> + vbuf->flags &= ~mask; >> + vbuf->flags |= inst->tss[inst->metadata_idx].flags; >> + vbuf->timecode = inst->tss[inst->metadata_idx].tc; >> +} >> + >> +int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct vb2_v4l2_buffer *vbuf; >> + struct vb2_buffer *vb2; >> + u32 type, state; >> + >> + switch (buf->type) { >> + case BUF_INPUT: >> + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; >> + break; >> + case BUF_OUTPUT: >> + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; >> + break; >> + default: >> + return 0; /* Internal DPB Buffers */ >> + } >> + >> + vbuf = iris_helper_find_buf(inst, type, buf->index); >> + if (!vbuf) >> + return -EINVAL; >> + >> + 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 (V4L2_TYPE_IS_CAPTURE(type)) { >> + vb2_set_plane_payload(vb2, 0, buf->data_size); >> + vbuf->sequence = inst->sequence_cap++; >> + iris_get_ts_metadata(inst, buf->timestamp, vbuf); >> + } else { >> + vbuf->sequence = inst->sequence_out++; >> + } >> + >> + if (vbuf->flags & V4L2_BUF_FLAG_LAST) { >> + if (!v4l2_m2m_has_stopped(m2m_ctx) && >> + inst->subscriptions & V4L2_EVENT_EOS) { >> + const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; >> + >> + v4l2_event_queue_fh(&inst->fh, &ev); >> + v4l2_m2m_mark_stopped(m2m_ctx); >> + } >> + } >> + vb2->timestamp = buf->timestamp; >> + vb2->planes[0].bytesused = buf->data_size + vb2->planes[0].data_offset; >> + v4l2_m2m_buf_done(vbuf, state); >> + >> + return 0; >> +} >> diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h >> index 41e090e9f0b0..bd8b74a9fbc4 100644 >> --- a/drivers/media/platform/qcom/iris/iris_buffer.h >> +++ b/drivers/media/platform/qcom/iris/iris_buffer.h >> @@ -109,6 +109,8 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf >> int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane); >> int iris_alloc_and_queue_persist_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); >> +int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf); >> void iris_vb2_queue_error(struct iris_inst *inst); >> >> #endif >> 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 ee7d9beca33b..82f2513576bf 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c >> @@ -180,6 +180,10 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) >> ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); >> if (!ret) >> ret = iris_wait_for_session_response(inst, false); >> + 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; >> @@ -201,6 +205,50 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) >> return ret; >> } >> >> +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); >> +} >> + >> +static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf) >> +{ >> + struct hfi_session_fill_buffer_pkt op_pkt; >> + >> + op_pkt.shdr.hdr.size = sizeof(struct hfi_session_fill_buffer_pkt); >> + op_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FILL_BUFFER; >> + op_pkt.shdr.session_id = inst->session_id; >> + op_pkt.output_tag = buf->index; >> + op_pkt.packet_buffer = buf->device_addr; >> + op_pkt.extradata_buffer = 0; >> + op_pkt.alloc_len = buf->buffer_size; >> + op_pkt.filled_len = buf->data_size; >> + op_pkt.offset = buf->data_offset; >> + op_pkt.data = 0; >> + >> + if (buf->type == BUF_OUTPUT && iris_split_mode_enabled(inst)) >> + op_pkt.stream_id = 1; >> + else >> + op_pkt.stream_id = 0; >> + >> + return iris_hfi_queue_cmd_write(inst->core, &op_pkt, op_pkt.shdr.hdr.size); >> +} >> + >> static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf) >> { >> struct hfi_session_set_buffers_pkt *int_pkt; >> @@ -240,6 +288,11 @@ static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct ir >> static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf) >> { >> switch (buf->type) { >> + case BUF_INPUT: >> + return iris_hfi_gen1_queue_input_buffer(inst, buf); >> + case BUF_OUTPUT: >> + case BUF_DPB: >> + return iris_hfi_gen1_queue_output_buffer(inst, buf); >> case BUF_PERSIST: >> case BUF_BIN: >> case BUF_SCRATCH_1: >> 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 5527233b03e5..b7f9e0f47675 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h >> @@ -29,11 +29,14 @@ >> #define HFI_CMD_SESSION_LOAD_RESOURCES 0x211001 >> #define HFI_CMD_SESSION_START 0x211002 >> #define HFI_CMD_SESSION_STOP 0x211003 >> +#define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004 >> +#define HFI_CMD_SESSION_FILL_BUFFER 0x211005 >> #define HFI_CMD_SESSION_FLUSH 0x211008 >> #define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b >> #define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c >> >> #define HFI_ERR_SESSION_UNSUPPORTED_SETTING 0x1008 >> +#define HFI_ERR_SESSION_UNSUPPORTED_STREAM 0x100d >> #define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE 0x1010 >> #define HFI_ERR_SESSION_INVALID_SCALE_FACTOR 0x1012 >> #define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED 0x1013 >> @@ -41,6 +44,8 @@ >> #define HFI_EVENT_SYS_ERROR 0x1 >> #define HFI_EVENT_SESSION_ERROR 0x2 >> >> +#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 >> + >> #define HFI_FLUSH_OUTPUT 0x1000002 >> #define HFI_FLUSH_OUTPUT2 0x1000003 >> #define HFI_FLUSH_ALL 0x1000004 >> @@ -84,9 +89,19 @@ >> #define HFI_MSG_SESSION_START 0x221002 >> #define HFI_MSG_SESSION_STOP 0x221003 >> #define HFI_MSG_SESSION_FLUSH 0x221006 >> +#define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007 >> +#define HFI_MSG_SESSION_FILL_BUFFER 0x221008 >> #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_FRAME_NOTCODED 0x7f002000 >> +#define HFI_FRAME_YUV 0x7f004000 >> +#define HFI_UNUSED_PICT 0x10000000 >> + >> struct hfi_pkt_hdr { >> u32 size; >> u32 pkt_type; >> @@ -144,6 +159,34 @@ struct hfi_session_set_buffers_pkt { >> u32 buffer_info[]; >> }; >> >> +struct hfi_session_empty_buffer_compressed_pkt { >> + struct hfi_session_hdr_pkt shdr; >> + u32 time_stamp_hi; >> + u32 time_stamp_lo; >> + u32 flags; >> + u32 mark_target; >> + u32 mark_data; >> + u32 offset; >> + u32 alloc_len; >> + u32 filled_len; >> + 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; >> + u32 offset; >> + u32 alloc_len; >> + u32 filled_len; >> + u32 output_tag; >> + u32 packet_buffer; >> + u32 extradata_buffer; >> + u32 data; >> +}; >> + >> struct hfi_session_flush_pkt { >> struct hfi_session_hdr_pkt shdr; >> u32 flush_type; >> @@ -258,6 +301,43 @@ struct hfi_multi_stream { >> u32 enable; >> }; >> >> +struct hfi_msg_session_empty_buffer_done_pkt { >> + struct hfi_msg_session_hdr_pkt shdr; >> + u32 offset; >> + u32 filled_len; >> + u32 input_tag; >> + 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; >> + u32 view_id; >> + u32 error_type; >> + u32 time_stamp_hi; >> + u32 time_stamp_lo; >> + u32 flags; >> + u32 mark_target; >> + u32 mark_data; >> + u32 stats; >> + u32 alloc_len; >> + u32 filled_len; >> + u32 offset; >> + u32 frame_width; >> + u32 frame_height; >> + u32 start_x_coord; >> + u32 start_y_coord; >> + u32 input_tag; >> + u32 input_tag2; >> + u32 output_tag; >> + u32 picture_type; >> + u32 packet_buffer; >> + u32 extradata_buffer; >> + u32 data[]; >> +}; >> + >> struct hfi_msg_session_release_buffers_done_pkt { >> struct hfi_msg_session_hdr_pkt shdr; >> u32 num_buffers; >> 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 a84bb00388d9..23a8bf29e381 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c >> @@ -3,6 +3,8 @@ >> * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> */ >> >> +#include <media/v4l2-mem2mem.h> >> + >> #include "iris_hfi_gen1.h" >> #include "iris_hfi_gen1_defines.h" >> #include "iris_instance.h" >> @@ -130,6 +132,143 @@ static void iris_hfi_gen1_sys_property_info(struct iris_core *core, void *packet >> } >> } >> >> +static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) >> +{ >> + struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet; >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *m2m_buffer, *n; >> + struct iris_buffer *buf = NULL; >> + bool found = false; >> + >> + 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) { >> + found = true; >> + break; >> + } >> + } >> + if (!found) >> + goto error; >> + >> + if (pkt->shdr.error_type == HFI_ERR_SESSION_UNSUPPORTED_STREAM) { >> + buf->flags = V4L2_BUF_FLAG_ERROR; >> + iris_vb2_queue_error(inst); >> + iris_inst_change_state(inst, IRIS_INST_ERROR); >> + } >> + >> + if (!(buf->attr & BUF_ATTR_QUEUED)) >> + return; >> + >> + buf->attr &= ~BUF_ATTR_QUEUED; >> + >> + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { >> + buf->attr |= BUF_ATTR_BUFFER_DONE; >> + iris_vb2_buffer_done(inst, buf); >> + } >> + >> + return; >> + >> +error: >> + iris_inst_change_state(inst, IRIS_INST_ERROR); >> + dev_err(inst->core->dev, "error in etb done\n"); >> +} >> + >> +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 v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *m2m_buffer, *n; >> + u32 timestamp_hi = pkt->time_stamp_hi; >> + u32 timestamp_lo = pkt->time_stamp_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; >> + struct iris_buffer *buf, *iter; >> + struct iris_buffers *buffers; >> + u32 offset = pkt->offset; >> + u64 timestamp_us = 0; >> + bool found = false; >> + u32 flags = 0; >> + >> + if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) { >> + buffers = &inst->buffers[BUF_DPB]; >> + if (!buffers) >> + goto error; >> + >> + found = false; >> + list_for_each_entry(iter, &buffers->list, list) { >> + if (!(iter->attr & BUF_ATTR_QUEUED)) >> + continue; >> + >> + found = (iter->index == output_tag && >> + iter->data_offset == offset); >> + >> + if (found) { >> + buf = iter; >> + break; >> + } >> + } >> + } else { >> + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) { >> + buf = to_iris_buffer(&m2m_buffer->vb); >> + if (!(buf->attr & BUF_ATTR_QUEUED)) >> + continue; >> + >> + found = (buf->index == output_tag && >> + buf->data_offset == offset); >> + >> + if (found) >> + break; >> + } >> + } >> + if (!found) >> + goto error; >> + >> + buf->data_offset = offset; >> + buf->data_size = filled_len; >> + >> + if (filled_len) { >> + timestamp_us = timestamp_hi; >> + timestamp_us = (timestamp_us << 32) | timestamp_lo; >> + } else { >> + flags |= V4L2_BUF_FLAG_LAST; >> + } >> + buf->timestamp = timestamp_us; >> + >> + switch (pic_type) { >> + case HFI_PICTURE_IDR: >> + case HFI_PICTURE_I: >> + flags |= V4L2_BUF_FLAG_KEYFRAME; >> + break; >> + case HFI_PICTURE_P: >> + flags |= V4L2_BUF_FLAG_PFRAME; >> + break; >> + case HFI_PICTURE_B: >> + flags |= V4L2_BUF_FLAG_BFRAME; >> + break; >> + case HFI_FRAME_NOTCODED: >> + case HFI_UNUSED_PICT: >> + case HFI_FRAME_YUV: >> + default: >> + break; >> + } >> + >> + buf->attr &= ~BUF_ATTR_QUEUED; >> + buf->attr |= BUF_ATTR_DEQUEUED; >> + buf->attr |= BUF_ATTR_BUFFER_DONE; >> + >> + buf->flags |= flags; >> + >> + iris_vb2_buffer_done(inst, buf); >> + >> + return; >> + >> +error: >> + iris_inst_change_state(inst, IRIS_INST_ERROR); >> + dev_err(core->dev, "error in ftb done\n"); >> +} >> + >> struct iris_hfi_gen1_response_pkt_info { >> u32 pkt; >> u32 pkt_sz; >> @@ -168,6 +307,14 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { >> .pkt = HFI_MSG_SESSION_STOP, >> .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt), >> }, >> + { >> + .pkt = HFI_MSG_SESSION_EMPTY_BUFFER, >> + .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt), >> + }, >> + { >> + .pkt = HFI_MSG_SESSION_FILL_BUFFER, >> + .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), >> + }, >> { >> .pkt = HFI_MSG_SESSION_FLUSH, >> .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt), >> @@ -238,15 +385,21 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response >> } >> >> mutex_lock(&inst->lock); >> - struct hfi_msg_session_hdr_pkt *shdr; >> + if (hdr->pkt_type == HFI_MSG_SESSION_EMPTY_BUFFER) { >> + iris_hfi_gen1_session_etb_done(inst, hdr); >> + } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) { >> + iris_hfi_gen1_session_ftb_done(inst, hdr); >> + } else { >> + struct hfi_msg_session_hdr_pkt *shdr; >> >> - shdr = (struct hfi_msg_session_hdr_pkt *)hdr; >> - if (shdr->error_type != HFI_ERR_NONE) >> - iris_inst_change_state(inst, IRIS_INST_ERROR); >> + shdr = (struct hfi_msg_session_hdr_pkt *)hdr; >> + 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); >> + done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ? >> + &inst->flush_completion : &inst->completion; >> + complete(done); >> + } >> mutex_unlock(&inst->lock); >> >> break; >> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h >> index 5fbbab844025..bf3aa1afb5bb 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h >> @@ -20,6 +20,7 @@ struct iris_core; >> * @packet: HFI packet >> * @ipsc_properties_set: boolean to set ipsc properties to fw >> * @opsc_properties_set: boolean to set opsc properties to fw >> + * @hfi_frame_info: structure of frame info >> * @src_subcr_params: subscription params to fw on input port >> * @dst_subcr_params: subscription params to fw on output port >> */ >> @@ -28,6 +29,7 @@ struct iris_inst_hfi_gen2 { >> struct iris_hfi_header *packet; >> bool ipsc_properties_set; >> bool opsc_properties_set; >> + struct iris_hfi_frame_info hfi_frame_info; >> struct hfi_subscription_params src_subcr_params; >> struct hfi_subscription_params dst_subcr_params; >> }; >> 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 d9a903ee1e06..69e383a99d84 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h >> @@ -70,6 +70,12 @@ >> #define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001 >> #define HFI_SYSTEM_ERROR_END 0x05FFFFFF >> >> +#define HFI_INFORMATION_BEGIN 0x06000000 >> +#define HFI_INFO_UNSUPPORTED 0x06000001 >> +#define HFI_INFO_DATA_CORRUPT 0x06000002 >> +#define HFI_INFO_BUFFER_OVERFLOW 0x06000004 >> +#define HFI_INFORMATION_END 0x06FFFFFF >> + >> enum hfi_property_mode_type { >> HFI_MODE_PORT_SETTINGS_CHANGE = 0x00000001, >> HFI_MODE_PROPERTY = 0x00000002, >> @@ -91,6 +97,15 @@ enum hfi_codec_type { >> HFI_CODEC_ENCODE_AVC = 2, >> }; >> >> +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, >> +}; >> + >> enum hfi_buffer_type { >> HFI_BUFFER_BITSTREAM = 0x00000001, >> HFI_BUFFER_RAW = 0x00000002, >> @@ -114,6 +129,13 @@ enum hfi_buffer_host_flags { >> HFI_BUF_HOST_FLAGS_CB_NON_SECURE = 0x00000200, >> }; >> >> +enum hfi_buffer_firmware_flags { >> + HFI_BUF_FW_FLAG_RELEASE_DONE = 0x00000001, >> + HFI_BUF_FW_FLAG_READONLY = 0x00000010, >> + HFI_BUF_FW_FLAG_LAST = 0x10000000, >> + HFI_BUF_FW_FLAG_PSC_LAST = 0x20000000, >> +}; >> + >> enum hfi_packet_firmware_flags { >> HFI_FW_FLAGS_SUCCESS = 0x00000001, >> HFI_FW_FLAGS_INFORMATION = 0x00000002, >> 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 9639c7eabd6b..77c4f92b76e1 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c >> @@ -3,6 +3,8 @@ >> * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> */ >> >> +#include <media/v4l2-mem2mem.h> >> + >> #include "iris_hfi_gen2.h" >> #include "iris_hfi_gen2_defines.h" >> #include "iris_hfi_gen2_packet.h" >> @@ -81,6 +83,29 @@ static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type) >> return true; >> } >> >> +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 driver_flags = 0; >> + >> + 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) >> + driver_flags |= V4L2_BUF_FLAG_PFRAME; >> + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_B) >> + driver_flags |= V4L2_BUF_FLAG_BFRAME; >> + >> + if (inst_hfi_gen2->hfi_frame_info.data_corrupt || inst_hfi_gen2->hfi_frame_info.overflow) >> + driver_flags |= V4L2_BUF_FLAG_ERROR; >> + >> + if (hfi_flags & HFI_BUF_FW_FLAG_LAST || >> + hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST) >> + driver_flags |= V4L2_BUF_FLAG_LAST; >> + >> + return driver_flags; >> +} >> + >> static bool iris_hfi_gen2_validate_packet_payload(struct iris_hfi_packet *pkt) >> { >> u32 payload_size = 0; >> @@ -154,6 +179,37 @@ static int iris_hfi_gen2_validate_hdr_packet(struct iris_core *core, struct iris >> return 0; >> } >> >> +static int iris_hfi_gen2_handle_session_info(struct iris_inst *inst, >> + struct iris_hfi_packet *pkt) >> +{ >> + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); >> + struct iris_core *core = inst->core; >> + int ret = 0; >> + char *info; >> + >> + switch (pkt->type) { >> + case HFI_INFO_UNSUPPORTED: >> + info = "unsupported"; >> + break; >> + case HFI_INFO_DATA_CORRUPT: >> + info = "data corrupt"; >> + inst_hfi_gen2->hfi_frame_info.data_corrupt = 1; >> + break; >> + case HFI_INFO_BUFFER_OVERFLOW: >> + info = "buffer overflow"; >> + inst_hfi_gen2->hfi_frame_info.overflow = 1; >> + break; >> + default: >> + info = "unknown"; >> + break; >> + } >> + >> + dev_dbg(core->dev, "session info received %#x: %s\n", >> + pkt->type, info); >> + >> + return ret; >> +} >> + >> static int iris_hfi_gen2_handle_session_error(struct iris_inst *inst, >> struct iris_hfi_packet *pkt) >> { >> @@ -234,19 +290,108 @@ static void iris_hfi_gen2_handle_session_close(struct iris_inst *inst, >> complete(&inst->completion); >> } >> >> +static int iris_hfi_gen2_handle_input_buffer(struct iris_inst *inst, >> + struct iris_hfi_buffer *buffer) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *m2m_buffer, *n; >> + struct iris_buffer *buf; >> + bool found = false; >> + >> + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { >> + buf = to_iris_buffer(&m2m_buffer->vb); >> + if (buf->index == buffer->index) { >> + found = true; >> + break; >> + } >> + } >> + if (!found) >> + return -EINVAL; >> + >> + if (!(buf->attr & BUF_ATTR_QUEUED)) >> + return -EINVAL; >> + >> + buf->attr &= ~BUF_ATTR_QUEUED; >> + buf->attr |= BUF_ATTR_DEQUEUED; >> + >> + buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, buffer->flags); >> + >> + return 0; >> +} >> + >> +static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst, >> + struct iris_hfi_buffer *hfi_buffer) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *m2m_buffer, *n; >> + struct iris_buffer *buf; >> + bool found = false; >> + >> + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) { >> + buf = to_iris_buffer(&m2m_buffer->vb); >> + if (buf->index == hfi_buffer->index && >> + buf->device_addr == hfi_buffer->base_address && >> + buf->data_offset == hfi_buffer->data_offset) { >> + found = true; >> + break; >> + } >> + } >> + if (!found) >> + return -EINVAL; >> + >> + if (!(buf->attr & BUF_ATTR_QUEUED)) >> + return -EINVAL; >> + >> + buf->data_offset = hfi_buffer->data_offset; >> + buf->data_size = hfi_buffer->data_size; >> + buf->timestamp = hfi_buffer->timestamp; >> + >> + buf->attr &= ~BUF_ATTR_QUEUED; >> + buf->attr |= BUF_ATTR_DEQUEUED; >> + >> + buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags); >> + >> + return 0; >> +} >> + >> +static void iris_hfi_gen2_handle_dequeue_buffers(struct iris_inst *inst) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct v4l2_m2m_buffer *buffer, *n; >> + struct iris_buffer *buf = NULL; >> + >> + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { >> + buf = to_iris_buffer(&buffer->vb); >> + if (buf->attr & BUF_ATTR_DEQUEUED) { >> + buf->attr &= ~BUF_ATTR_DEQUEUED; >> + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { >> + buf->attr |= BUF_ATTR_BUFFER_DONE; >> + iris_vb2_buffer_done(inst, buf); >> + } >> + } >> + } >> + >> + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { >> + buf = to_iris_buffer(&buffer->vb); >> + if (buf->attr & BUF_ATTR_DEQUEUED) { >> + buf->attr &= ~BUF_ATTR_DEQUEUED; >> + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { >> + buf->attr |= BUF_ATTR_BUFFER_DONE; >> + iris_vb2_buffer_done(inst, buf); >> + } >> + } >> + } >> +} >> + >> 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); >> + struct iris_buffers *buffers = &inst->buffers[buf_type]; >> struct iris_buffer *buf, *iter; >> - struct iris_buffers *buffers; >> - u32 buf_type; >> + bool found = false; >> int ret = 0; >> - bool found; >> >> - buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type); >> - buffers = &inst->buffers[buf_type]; >> - >> - found = false; >> list_for_each_entry(iter, &buffers->list, list) { >> if (iter->device_addr == buffer->base_address) { >> found = true; >> @@ -258,7 +403,6 @@ 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); >> >> @@ -285,7 +429,12 @@ 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; >> >> - return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); >> + 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); >> } >> >> static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst, >> @@ -347,6 +496,12 @@ 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_PICTURE_TYPE: >> + inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; >> + break; >> + case HFI_PROP_NO_OUTPUT: >> + inst_hfi_gen2->hfi_frame_info.no_output = 1; >> + break; >> case HFI_PROP_QUALITY_MODE: >> case HFI_PROP_STAGE: >> case HFI_PROP_PIPE: >> @@ -433,14 +588,18 @@ static int iris_hfi_gen2_handle_system_response(struct iris_core *core, >> static int iris_hfi_gen2_handle_session_response(struct iris_core *core, >> struct iris_hfi_header *hdr) >> { >> + struct iris_inst_hfi_gen2 *inst_hfi_gen2; >> struct iris_hfi_packet *packet; >> struct iris_inst *inst; >> + bool dequeue = false; >> int ret = 0; >> u32 i, j; >> u8 *pkt; >> static const struct iris_hfi_gen2_inst_hfi_range range[] = { >> {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, >> iris_hfi_gen2_handle_session_error}, >> + {HFI_INFORMATION_BEGIN, HFI_INFORMATION_END, >> + iris_hfi_gen2_handle_session_info}, >> {HFI_PROP_BEGIN, HFI_PROP_END, >> iris_hfi_gen2_handle_session_property}, >> {HFI_CMD_BEGIN, HFI_CMD_END, >> @@ -452,6 +611,8 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, >> return -EINVAL; >> >> mutex_lock(&inst->lock); >> + inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); >> + memset(&inst_hfi_gen2->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info)); >> >> pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); >> for (i = 0; i < ARRAY_SIZE(range); i++) { >> @@ -462,6 +623,7 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, >> iris_hfi_gen2_handle_session_error(inst, packet); >> >> if (packet->type > range[i].begin && packet->type < range[i].end) { >> + dequeue |= (packet->type == HFI_CMD_BUFFER); >> ret = range[i].handle(inst, packet); >> if (ret) >> iris_inst_change_state(inst, IRIS_INST_ERROR); >> @@ -470,6 +632,9 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, >> } >> } >> >> + if (dequeue) >> + iris_hfi_gen2_handle_dequeue_buffers(inst); >> + >> mutex_unlock(&inst->lock); >> >> return ret; >> diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h >> index fdec6a97ac6c..e970c25b6106 100644 >> --- a/drivers/media/platform/qcom/iris/iris_instance.h >> +++ b/drivers/media/platform/qcom/iris/iris_instance.h >> @@ -35,6 +35,10 @@ >> * @m2m_dev: a reference to m2m device structure >> * @m2m_ctx: a reference to m2m context structure >> * @subscriptions: variable to hold current events subscriptions >> + * @sequence_cap: a sequence counter for capture queue >> + * @sequence_out: a sequence counter for output queue >> + * @tss: timestamp metadata >> + * @metadata_idx: index for metadata buffer >> */ >> >> struct iris_inst { >> @@ -58,6 +62,10 @@ struct iris_inst { >> struct v4l2_m2m_dev *m2m_dev; >> struct v4l2_m2m_ctx *m2m_ctx; >> unsigned int subscriptions; >> + u32 sequence_cap; >> + u32 sequence_out; >> + struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; >> + u32 metadata_idx; >> }; >> >> #endif >> diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c >> index 7e252ee1d165..8487a26d98ed 100644 >> --- a/drivers/media/platform/qcom/iris/iris_utils.c >> +++ b/drivers/media/platform/qcom/iris/iris_utils.c >> @@ -4,6 +4,7 @@ >> */ >> >> #include <linux/pm_runtime.h> >> +#include <media/v4l2-mem2mem.h> >> >> #include "iris_instance.h" >> #include "iris_utils.h" >> @@ -36,6 +37,21 @@ bool iris_split_mode_enabled(struct iris_inst *inst) >> return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12; >> } >> >> +void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, >> + enum vb2_buffer_state state) >> +{ >> + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; >> + struct vb2_v4l2_buffer *buf; >> + >> + if (V4L2_TYPE_IS_OUTPUT(type)) { >> + while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) >> + v4l2_m2m_buf_done(buf, state); >> + } else if (V4L2_TYPE_IS_CAPTURE(type)) { >> + while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) >> + v4l2_m2m_buf_done(buf, state); >> + } >> +} >> + >> int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush) >> { >> struct iris_core *core = inst->core; >> diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h >> index 0d46f50d3103..745fcc3a22a4 100644 >> --- a/drivers/media/platform/qcom/iris/iris_utils.h >> +++ b/drivers/media/platform/qcom/iris/iris_utils.h >> @@ -16,6 +16,20 @@ struct iris_hfi_rect_desc { >> u32 height; >> }; >> >> +struct iris_hfi_frame_info { >> + u32 picture_type; >> + u32 no_output; >> + u32 data_corrupt; >> + u32 overflow; >> +}; >> + >> +struct iris_ts_metadata { >> + u64 ts_ns; >> + u64 ts_us; >> + u32 flags; >> + struct v4l2_timecode tc; >> +}; >> + >> #define NUM_MBS_PER_FRAME(height, width) \ >> (DIV_ROUND_UP(height, 16) * DIV_ROUND_UP(width, 16)) >> >> @@ -36,6 +50,8 @@ bool iris_res_is_less_than(u32 width, u32 height, >> int iris_get_mbpf(struct iris_inst *inst); >> bool iris_split_mode_enabled(struct iris_inst *inst); >> 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); >> >> #endif >> diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c >> index 75c1364709d1..2e4b30ec963f 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vb2.c >> +++ b/drivers/media/platform/qcom/iris/iris_vb2.c >> @@ -3,11 +3,23 @@ >> * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> */ >> >> +#include <media/videobuf2-dma-contig.h> >> +#include <media/v4l2-mem2mem.h> >> + >> #include "iris_buffer.h" >> #include "iris_instance.h" >> #include "iris_vb2.h" >> #include "iris_vdec.h" >> #include "iris_vpu_buffer.h" >> +int iris_vb2_buf_init(struct vb2_buffer *vb2) >> +{ >> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); >> + struct iris_buffer *buf = to_iris_buffer(vbuf); >> + >> + buf->device_addr = vb2_dma_contig_plane_dma_addr(vb2, 0); >> + >> + return 0; >> +} >> >> int iris_vb2_queue_setup(struct vb2_queue *q, >> unsigned int *num_buffers, unsigned int *num_planes, >> @@ -87,6 +99,7 @@ int iris_vb2_queue_setup(struct vb2_queue *q, >> >> int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) >> { >> + enum iris_buffer_type buf_type; >> struct iris_inst *inst; >> int ret = 0; >> >> @@ -107,6 +120,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) >> goto error; >> } >> >> + >> if (V4L2_TYPE_IS_OUTPUT(q->type)) >> ret = iris_vdec_streamon_input(inst); >> else if (V4L2_TYPE_IS_CAPTURE(q->type)) >> @@ -114,11 +128,22 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) >> if (ret) >> goto error; >> >> + buf_type = iris_v4l2_type_to_driver(q->type); >> + if (buf_type == -EINVAL) { >> + ret = -EINVAL; >> + goto error; >> + } >> + >> + ret = iris_queue_deferred_buffers(inst, buf_type); >> + if (ret) >> + goto error; >> + >> mutex_unlock(&inst->lock); >> >> return ret; >> >> error: >> + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); > > Ah, you added this in this patch. Disregard my earlier comments about not > returning buffers in start/stop_streaming. > Sure. >> iris_inst_change_state(inst, IRIS_INST_ERROR); >> mutex_unlock(&inst->lock); >> >> @@ -128,6 +153,7 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) >> void iris_vb2_stop_streaming(struct vb2_queue *q) >> { >> struct iris_inst *inst; >> + int ret = 0; >> >> inst = vb2_get_drv_priv(q); >> >> @@ -140,8 +166,82 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) >> !V4L2_TYPE_IS_CAPTURE(q->type)) >> goto exit; >> >> - iris_vdec_session_streamoff(inst, q->type); >> + ret = iris_vdec_session_streamoff(inst, q->type); >> + if (ret) >> + goto exit; >> >> exit: >> + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); >> + if (ret) >> + iris_inst_change_state(inst, IRIS_INST_ERROR); >> + >> + mutex_unlock(&inst->lock); >> +} >> + >> +int iris_vb2_buf_prepare(struct vb2_buffer *vb) >> +{ >> + struct iris_inst *inst = vb2_get_drv_priv(vb->vb2_queue); >> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); >> + >> + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { >> + if (vbuf->field == V4L2_FIELD_ANY) >> + vbuf->field = V4L2_FIELD_NONE; >> + if (vbuf->field != V4L2_FIELD_NONE) >> + 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; >> + >> + return 0; >> +} >> + >> +int iris_vb2_buf_out_validate(struct vb2_buffer *vb) >> +{ >> + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); >> + >> + v4l2_buf->field = V4L2_FIELD_NONE; >> + >> + return 0; >> +} >> + >> +void iris_vb2_buf_queue(struct vb2_buffer *vb2) >> +{ >> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); >> + struct v4l2_m2m_ctx *m2m_ctx; >> + struct iris_inst *inst; >> + int ret = 0; >> + >> + inst = vb2_get_drv_priv(vb2->vb2_queue); >> + >> + mutex_lock(&inst->lock); >> + if (inst->state == IRIS_INST_ERROR) { >> + ret = -EBUSY; >> + goto exit; >> + } >> + >> + if (vbuf->field == V4L2_FIELD_ANY) >> + vbuf->field = V4L2_FIELD_NONE; >> + >> + m2m_ctx = inst->m2m_ctx; >> + >> + if (!vb2->planes[0].bytesused && V4L2_TYPE_IS_OUTPUT(vb2->type)) { >> + ret = -EINVAL; >> + goto exit; >> + } >> + >> + v4l2_m2m_buf_queue(m2m_ctx, vbuf); >> + >> + ret = iris_vdec_qbuf(inst, vbuf); >> + >> +exit: >> + if (ret) { >> + iris_inst_change_state(inst, IRIS_INST_ERROR); >> + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); >> + } >> mutex_unlock(&inst->lock); >> } >> diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h >> index bc3bb830c2ba..c0d22c39d197 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vb2.h >> +++ b/drivers/media/platform/qcom/iris/iris_vb2.h >> @@ -6,10 +6,14 @@ >> #ifndef _IRIS_VB2_H_ >> #define _IRIS_VB2_H_ >> >> +int iris_vb2_buf_init(struct vb2_buffer *vb2); >> int iris_vb2_queue_setup(struct vb2_queue *q, >> unsigned int *num_buffers, unsigned int *num_planes, >> unsigned int sizes[], struct device *alloc_devs[]); >> int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count); >> void iris_vb2_stop_streaming(struct vb2_queue *q); >> +int iris_vb2_buf_prepare(struct vb2_buffer *vb); >> +int iris_vb2_buf_out_validate(struct vb2_buffer *vb); >> +void iris_vb2_buf_queue(struct vb2_buffer *vb2); >> >> #endif >> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c >> index 9cd77b551df4..7d5ef23b5c0a 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vdec.c >> +++ b/drivers/media/platform/qcom/iris/iris_vdec.c >> @@ -242,6 +242,68 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su >> return ret; >> } >> >> +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; >> @@ -253,23 +315,47 @@ static void iris_vdec_kill_session(struct iris_inst *inst) >> iris_inst_change_state(inst, IRIS_INST_ERROR); >> } >> >> -void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) >> +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; >> >> - return; >> + 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) >> @@ -359,3 +445,67 @@ int iris_vdec_streamon_output(struct iris_inst *inst) >> >> 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); >> + if (buf->type == -EINVAL) >> + return -EINVAL; >> + >> + 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); >> + struct vb2_buffer *vb2 = &vbuf->vb2_buf; >> + struct vb2_queue *q; >> + int ret; >> + >> + ret = iris_vdec_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; >> + } >> + >> + return iris_queue_buffer(inst, buf); >> +} >> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h >> index b3299164f823..51bf0b96d9f0 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vdec.h >> +++ b/drivers/media/platform/qcom/iris/iris_vdec.h >> @@ -16,6 +16,7 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); >> int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); >> int iris_vdec_streamon_input(struct iris_inst *inst); >> int iris_vdec_streamon_output(struct iris_inst *inst); >> -void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); >> +int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); >> +int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); >> >> #endif >> diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c >> index bab9ca52de69..aaf377f2f5f5 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vidc.c >> +++ b/drivers/media/platform/qcom/iris/iris_vidc.c >> @@ -7,6 +7,7 @@ >> #include <media/v4l2-event.h> >> #include <media/v4l2-ioctl.h> >> #include <media/v4l2-mem2mem.h> >> +#include <media/videobuf2-dma-contig.h> >> >> #include "iris_vidc.h" >> #include "iris_instance.h" >> @@ -97,6 +98,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ >> src_vq->io_modes = VB2_MMAP | VB2_DMABUF; >> src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; >> src_vq->ops = inst->core->iris_vb2_ops; >> + src_vq->mem_ops = &vb2_dma_contig_memops; >> src_vq->drv_priv = inst; >> src_vq->buf_struct_size = sizeof(struct iris_buffer); >> src_vq->dev = inst->core->dev; >> @@ -109,6 +111,7 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ >> dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; >> dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; >> dst_vq->ops = inst->core->iris_vb2_ops; >> + dst_vq->mem_ops = &vb2_dma_contig_memops; >> dst_vq->drv_priv = inst; >> dst_vq->buf_struct_size = sizeof(struct iris_buffer); >> dst_vq->dev = inst->core->dev; >> @@ -438,9 +441,15 @@ static struct v4l2_file_operations iris_v4l2_file_ops = { >> }; >> >> static const struct vb2_ops iris_vb2_ops = { >> + .buf_init = iris_vb2_buf_init, >> .queue_setup = iris_vb2_queue_setup, >> .start_streaming = iris_vb2_start_streaming, >> .stop_streaming = iris_vb2_stop_streaming, >> + .buf_prepare = iris_vb2_buf_prepare, >> + .buf_out_validate = iris_vb2_buf_out_validate, >> + .buf_queue = iris_vb2_buf_queue, >> + .wait_prepare = vb2_ops_wait_prepare, >> + .wait_finish = vb2_ops_wait_finish, > > These two ops are no longer needed after commit 88785982a19d ("media: vb2: use > lock if wait_prepare/finish are NULL"). > > Please drop these. > Sure, Noted. >> }; >> >> static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { >> @@ -454,6 +463,12 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { >> .vidioc_g_fmt_vid_out_mplane = iris_g_fmt_vid_mplane, >> .vidioc_enum_framesizes = iris_enum_framesizes, >> .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_querycap = iris_querycap, >> .vidioc_queryctrl = iris_queryctrl, >> .vidioc_querymenu = iris_querymenu, >> > > Regards, > > Hans
© 2016 - 2024 Red Hat, Inc.