Commit 17f2a485 authored by Dikshita Agarwal's avatar Dikshita Agarwal Committed by Hans Verkuil
Browse files

media: iris: implement vb2 ops for buf_queue and firmware response



Implement the vb2 ops for the buf queue. These are the different buffer
attributes:
BUF_ATTR_DEFERRED - buffer queued by the client but not submitted to
                    firmware.
BUF_ATTR_PENDING_RELEASE - buffers requested to be released from
                           the firmware.
BUF_ATTR_QUEUED - buffers submitted to the firmware.
BUF_ATTR_DEQUEUED - buffers received from the firmware.
BUF_ATTR_BUFFER_DONE - buffers sent back to vb2.

Reviewed-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Tested-by: Stefan Schmidt <stefan.schmidt@linaro.org> # x1e80100 (Dell XPS 13 9345)
Reviewed-by: default avatarStefan Schmidt <stefan.schmidt@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Signed-off-by: default avatarDikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
parent 73702f45
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+116 −0
Original line number Diff line number Diff line
@@ -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,88 @@ 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)) {
			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;
	v4l2_m2m_buf_done(vbuf, state);

	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -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
+53 −0
Original line number Diff line number Diff line
@@ -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:
+80 −0
Original line number Diff line number Diff line
@@ -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;
Loading