Commit 73702f45 authored by Dikshita Agarwal's avatar Dikshita Agarwal Committed by Hans Verkuil
Browse files

media: iris: allocate, initialize and queue internal buffers



Implement the functions for creating, queueing, releasing and destroying
the buffers for internal usage.

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 025398e9
Loading
Loading
Loading
Loading
+206 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@

#include "iris_buffer.h"
#include "iris_instance.h"
#include "iris_vpu_buffer.h"

#define PIXELS_4K 4096
#define MAX_WIDTH 4096
@@ -228,6 +229,211 @@ int iris_get_buffer_size(struct iris_inst *inst,
	}
}

static void iris_fill_internal_buf_info(struct iris_inst *inst,
					enum iris_buffer_type buffer_type)
{
	struct iris_buffers *buffers = &inst->buffers[buffer_type];

	buffers->size = iris_vpu_buf_size(inst, buffer_type);
	buffers->min_count = iris_vpu_buf_count(inst, buffer_type);
}

void iris_get_internal_buffers(struct iris_inst *inst, u32 plane)
{
	const struct iris_platform_data *platform_data = inst->core->iris_platform_data;
	const u32 *internal_buf_type;
	u32 internal_buffer_count, i;

	if (V4L2_TYPE_IS_OUTPUT(plane)) {
		internal_buf_type = platform_data->dec_ip_int_buf_tbl;
		internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
		for (i = 0; i < internal_buffer_count; i++)
			iris_fill_internal_buf_info(inst, internal_buf_type[i]);
	} else {
		internal_buf_type = platform_data->dec_op_int_buf_tbl;
		internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
		for (i = 0; i < internal_buffer_count; i++)
			iris_fill_internal_buf_info(inst, internal_buf_type[i]);
	}
}

static int iris_create_internal_buffer(struct iris_inst *inst,
				       enum iris_buffer_type buffer_type, u32 index)
{
	struct iris_buffers *buffers = &inst->buffers[buffer_type];
	struct iris_core *core = inst->core;
	struct iris_buffer *buffer;

	if (!buffers->size)
		return 0;

	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;

	INIT_LIST_HEAD(&buffer->list);
	buffer->type = buffer_type;
	buffer->index = index;
	buffer->buffer_size = buffers->size;
	buffer->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;
	list_add_tail(&buffer->list, &buffers->list);

	buffer->kvaddr = dma_alloc_attrs(core->dev, buffer->buffer_size,
					 &buffer->device_addr, GFP_KERNEL, buffer->dma_attrs);
	if (!buffer->kvaddr)
		return -ENOMEM;

	return 0;
}

int iris_create_internal_buffers(struct iris_inst *inst, u32 plane)
{
	const struct iris_platform_data *platform_data = inst->core->iris_platform_data;
	u32 internal_buffer_count, i, j;
	struct iris_buffers *buffers;
	const u32 *internal_buf_type;
	int ret;

	if (V4L2_TYPE_IS_OUTPUT(plane)) {
		internal_buf_type = platform_data->dec_ip_int_buf_tbl;
		internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
	} else {
		internal_buf_type = platform_data->dec_op_int_buf_tbl;
		internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
	}

	for (i = 0; i < internal_buffer_count; i++) {
		buffers = &inst->buffers[internal_buf_type[i]];
		for (j = 0; j < buffers->min_count; j++) {
			ret = iris_create_internal_buffer(inst, internal_buf_type[i], j);
			if (ret)
				return ret;
		}
	}

	return 0;
}

int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf)
{
	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
	int ret;

	ret = hfi_ops->session_queue_buf(inst, buf);
	if (ret)
		return ret;

	buf->attr &= ~BUF_ATTR_DEFERRED;
	buf->attr |= BUF_ATTR_QUEUED;

	return 0;
}

int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane)
{
	const struct iris_platform_data *platform_data = inst->core->iris_platform_data;
	struct iris_buffer *buffer, *next;
	struct iris_buffers *buffers;
	const u32 *internal_buf_type;
	u32 internal_buffer_count, i;
	int ret;

	if (V4L2_TYPE_IS_OUTPUT(plane)) {
		internal_buf_type = platform_data->dec_ip_int_buf_tbl;
		internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
	} else {
		internal_buf_type = platform_data->dec_op_int_buf_tbl;
		internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
	}

	for (i = 0; i < internal_buffer_count; i++) {
		buffers = &inst->buffers[internal_buf_type[i]];
		list_for_each_entry_safe(buffer, next, &buffers->list, list) {
			if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
				continue;
			if (buffer->attr & BUF_ATTR_QUEUED)
				continue;
			ret = iris_queue_buffer(inst, buffer);
			if (ret)
				return ret;
		}
	}

	return 0;
}

int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer)
{
	struct iris_core *core = inst->core;

	list_del(&buffer->list);
	dma_free_attrs(core->dev, buffer->buffer_size, buffer->kvaddr,
		       buffer->device_addr, buffer->dma_attrs);
	kfree(buffer);

	return 0;
}

int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane)
{
	const struct iris_platform_data *platform_data = inst->core->iris_platform_data;
	struct iris_buffer *buf, *next;
	struct iris_buffers *buffers;
	const u32 *internal_buf_type;
	u32 i, len;
	int ret;

	if (V4L2_TYPE_IS_OUTPUT(plane)) {
		internal_buf_type = platform_data->dec_ip_int_buf_tbl;
		len = platform_data->dec_ip_int_buf_tbl_size;
	} else {
		internal_buf_type = platform_data->dec_op_int_buf_tbl;
		len = platform_data->dec_op_int_buf_tbl_size;
	}

	for (i = 0; i < len; i++) {
		buffers = &inst->buffers[internal_buf_type[i]];
		list_for_each_entry_safe(buf, next, &buffers->list, list) {
			ret = iris_destroy_internal_buffer(inst, buf);
			if (ret)
				return ret;
		}
	}

	return 0;
}

int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst)
{
	struct iris_buffers *buffers = &inst->buffers[BUF_PERSIST];
	struct iris_buffer *buffer, *next;
	int ret;
	u32 i;

	if (!list_empty(&buffers->list))
		return 0;

	iris_fill_internal_buf_info(inst, BUF_PERSIST);

	for (i = 0; i < buffers->min_count; i++) {
		ret = iris_create_internal_buffer(inst, BUF_PERSIST, i);
		if (ret)
			return ret;
	}

	list_for_each_entry_safe(buffer, next, &buffers->list, list) {
		if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
			continue;
		if (buffer->attr & BUF_ATTR_QUEUED)
			continue;
		ret = iris_queue_buffer(inst, buffer);
		if (ret)
			return ret;
	}

	return 0;
}

void iris_vb2_queue_error(struct iris_inst *inst)
{
	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+7 −0
Original line number Diff line number Diff line
@@ -102,6 +102,13 @@ struct iris_buffers {
};

int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
void iris_get_internal_buffers(struct iris_inst *inst, u32 plane);
int iris_create_internal_buffers(struct iris_inst *inst, u32 plane);
int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane);
int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer);
int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane);
int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst);
int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf);
void iris_vb2_queue_error(struct iris_inst *inst);

#endif
+4 −0
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@
#include <linux/types.h>
#include <media/v4l2-device.h>

#include "iris_buffer.h"

struct iris_inst;
struct iris_core;

@@ -114,6 +116,8 @@ struct iris_hfi_command_ops {
				    void *payload, u32 payload_size);
	int (*session_open)(struct iris_inst *inst);
	int (*session_start)(struct iris_inst *inst, u32 plane);
	int (*session_queue_buf)(struct iris_inst *inst, struct iris_buffer *buffer);
	int (*session_release_buf)(struct iris_inst *inst, struct iris_buffer *buffer);
	int (*session_stop)(struct iris_inst *inst, u32 plane);
	int (*session_close)(struct iris_inst *inst);
};
+126 −1
Original line number Diff line number Diff line
@@ -8,6 +8,24 @@
#include "iris_instance.h"
#include "iris_vpu_buffer.h"

static u32 iris_hfi_gen1_buf_type_from_driver(enum iris_buffer_type buffer_type)
{
	switch (buffer_type) {
	case BUF_INPUT:
		return HFI_BUFFER_INPUT;
	case BUF_OUTPUT:
		return HFI_BUFFER_OUTPUT;
	case BUF_PERSIST:
		return HFI_BUFFER_INTERNAL_PERSIST_1;
	case BUF_BIN:
		return HFI_BUFFER_INTERNAL_SCRATCH;
	case BUF_SCRATCH_1:
		return HFI_BUFFER_INTERNAL_SCRATCH_1;
	default:
		return -EINVAL;
	}
}

static int iris_hfi_gen1_sys_init(struct iris_core *core)
{
	struct hfi_sys_init_pkt sys_init_pkt;
@@ -183,6 +201,111 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane)
	return ret;
}

static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf)
{
	struct hfi_session_set_buffers_pkt *int_pkt;
	u32 buffer_type, i;
	u32 packet_size;
	int ret;

	packet_size = struct_size(int_pkt, buffer_info, 1);
	int_pkt = kzalloc(packet_size, GFP_KERNEL);
	if (!int_pkt)
		return -ENOMEM;

	int_pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_BUFFERS;
	int_pkt->shdr.session_id = inst->session_id;
	int_pkt->buffer_size = buf->buffer_size;
	int_pkt->min_buffer_size = buf->buffer_size;
	int_pkt->num_buffers = 1;
	int_pkt->extradata_size = 0;
	int_pkt->shdr.hdr.size = packet_size;
	for (i = 0; i < int_pkt->num_buffers; i++)
		int_pkt->buffer_info[i] = buf->device_addr;
	buffer_type = iris_hfi_gen1_buf_type_from_driver(buf->type);
	if (buffer_type == -EINVAL) {
		ret = -EINVAL;
		goto exit;
	}

	int_pkt->buffer_type = buffer_type;
	ret = iris_hfi_queue_cmd_write(inst->core, int_pkt, int_pkt->shdr.hdr.size);

exit:
	kfree(int_pkt);

	return ret;
}

static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf)
{
	switch (buf->type) {
	case BUF_PERSIST:
	case BUF_BIN:
	case BUF_SCRATCH_1:
		return iris_hfi_gen1_queue_internal_buffer(inst, buf);
	default:
		return -EINVAL;
	}
}

static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct iris_buffer *buf)
{
	struct hfi_session_release_buffer_pkt *pkt;
	u32 packet_size, buffer_type, i;
	int ret;

	buffer_type = iris_hfi_gen1_buf_type_from_driver(buf->type);
	if (buffer_type == -EINVAL)
		return -EINVAL;

	if (buffer_type == HFI_BUFFER_INPUT)
		return 0;

	packet_size = sizeof(*pkt) + sizeof(struct hfi_buffer_info);
	pkt = kzalloc(packet_size, GFP_KERNEL);
	if (!pkt)
		return -ENOMEM;

	pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
	pkt->shdr.session_id = inst->session_id;
	pkt->buffer_size = buf->buffer_size;
	pkt->num_buffers = 1;

	if (buffer_type == HFI_BUFFER_OUTPUT ||
	    buffer_type == HFI_BUFFER_OUTPUT2) {
		struct hfi_buffer_info *bi;

		bi = (struct hfi_buffer_info *)pkt->buffer_info;
		for (i = 0; i < pkt->num_buffers; i++) {
			bi->buffer_addr = buf->device_addr;
			bi->extradata_addr = 0;
		}
		pkt->shdr.hdr.size = packet_size;
	} else {
		for (i = 0; i < pkt->num_buffers; i++)
			pkt->buffer_info[i] = buf->device_addr;
		pkt->extradata_size = 0;
		pkt->shdr.hdr.size =
				sizeof(struct hfi_session_set_buffers_pkt) +
				((pkt->num_buffers) * sizeof(u32));
	}

	pkt->response_req = true;
	pkt->buffer_type = buffer_type;

	ret = iris_hfi_queue_cmd_write(inst->core, pkt, pkt->shdr.hdr.size);
	if (ret)
		goto exit;

	ret = iris_wait_for_session_response(inst, false);

exit:
	kfree(pkt);

	return ret;
}

static int
iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *packet,
					  struct iris_inst *inst, u32 ptype, void *pdata)
@@ -495,7 +618,7 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst)

	if (iris_split_mode_enabled(inst)) {
		bufsz.type = HFI_BUFFER_OUTPUT;
		bufsz.size = iris_vpu_dec_dpb_size(inst);
		bufsz.size = iris_vpu_buf_size(inst, BUF_DPB);

		ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
		if (ret)
@@ -600,6 +723,8 @@ static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops = {
	.session_set_config_params = iris_hfi_gen1_session_set_config_params,
	.session_set_property = iris_hfi_gen1_session_set_property,
	.session_start = iris_hfi_gen1_session_start,
	.session_queue_buf = iris_hfi_gen1_session_queue_buffer,
	.session_release_buf = iris_hfi_gen1_session_unset_buffers,
	.session_stop = iris_hfi_gen1_session_stop,
	.session_close = iris_hfi_gen1_session_close,
};
+37 −0
Original line number Diff line number Diff line
@@ -24,11 +24,13 @@
#define HFI_CMD_SYS_SESSION_END				0x10008

#define HFI_CMD_SESSION_SET_PROPERTY			0x11001
#define HFI_CMD_SESSION_SET_BUFFERS			0x11002

#define HFI_CMD_SESSION_LOAD_RESOURCES			0x211001
#define HFI_CMD_SESSION_START				0x211002
#define HFI_CMD_SESSION_STOP				0x211003
#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
@@ -53,6 +55,9 @@
#define HFI_BUFFER_INPUT				0x1
#define HFI_BUFFER_OUTPUT				0x2
#define HFI_BUFFER_OUTPUT2				0x3
#define HFI_BUFFER_INTERNAL_PERSIST_1			0x5
#define HFI_BUFFER_INTERNAL_SCRATCH			0x6
#define HFI_BUFFER_INTERNAL_SCRATCH_1			0x7

#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL		0x5
#define HFI_PROPERTY_SYS_IMAGE_VERSION			0x6
@@ -80,6 +85,7 @@
#define HFI_MSG_SESSION_STOP				0x221003
#define HFI_MSG_SESSION_FLUSH				0x221006
#define HFI_MSG_SESSION_RELEASE_RESOURCES		0x22100a
#define HFI_MSG_SESSION_RELEASE_BUFFERS			0x22100c

struct hfi_pkt_hdr {
	u32 size;
@@ -128,11 +134,36 @@ struct hfi_sys_pc_prep_pkt {
	struct hfi_pkt_hdr hdr;
};

struct hfi_session_set_buffers_pkt {
	struct hfi_session_hdr_pkt shdr;
	u32 buffer_type;
	u32 buffer_size;
	u32 extradata_size;
	u32 min_buffer_size;
	u32 num_buffers;
	u32 buffer_info[];
};

struct hfi_session_flush_pkt {
	struct hfi_session_hdr_pkt shdr;
	u32 flush_type;
};

struct hfi_session_release_buffer_pkt {
	struct hfi_session_hdr_pkt shdr;
	u32 buffer_type;
	u32 buffer_size;
	u32 extradata_size;
	u32 response_req;
	u32 num_buffers;
	u32 buffer_info[];
};

struct hfi_buffer_info {
	u32 buffer_addr;
	u32 extradata_addr;
};

struct hfi_msg_event_notify_pkt {
	struct hfi_session_hdr_pkt shdr;
	u32 event_id;
@@ -227,6 +258,12 @@ struct hfi_multi_stream {
	u32 enable;
};

struct hfi_msg_session_release_buffers_done_pkt {
	struct hfi_msg_session_hdr_pkt shdr;
	u32 num_buffers;
	u32 buffer_info[];
};

struct hfi_msg_sys_debug_pkt {
	struct hfi_pkt_hdr hdr;
	u32 msg_type;
Loading