blob: 5fc30d54af4dc34616cfd08813940aa0b7044a20 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "iris_hfi_gen1.h"
#include "iris_hfi_gen1_defines.h"
#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;
sys_init_pkt.hdr.size = sizeof(sys_init_pkt);
sys_init_pkt.hdr.pkt_type = HFI_CMD_SYS_INIT;
sys_init_pkt.arch_type = HFI_VIDEO_ARCH_OX;
return iris_hfi_queue_cmd_write_locked(core, &sys_init_pkt, sys_init_pkt.hdr.size);
}
static int iris_hfi_gen1_sys_image_version(struct iris_core *core)
{
struct hfi_sys_get_property_pkt packet;
packet.hdr.size = sizeof(packet);
packet.hdr.pkt_type = HFI_CMD_SYS_GET_PROPERTY;
packet.num_properties = 1;
packet.data = HFI_PROPERTY_SYS_IMAGE_VERSION;
return iris_hfi_queue_cmd_write_locked(core, &packet, packet.hdr.size);
}
static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core)
{
struct hfi_sys_set_property_pkt *pkt;
struct hfi_enable *hfi;
u32 packet_size;
int ret;
packet_size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt = kzalloc(packet_size, GFP_KERNEL);
if (!pkt)
return -ENOMEM;
hfi = (struct hfi_enable *)&pkt->data[1];
pkt->hdr.size = packet_size;
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
hfi->enable = true;
ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt->hdr.size);
kfree(pkt);
return ret;
}
static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core)
{
struct hfi_sys_pc_prep_pkt pkt;
pkt.hdr.size = sizeof(struct hfi_sys_pc_prep_pkt);
pkt.hdr.pkt_type = HFI_CMD_SYS_PC_PREP;
return iris_hfi_queue_cmd_write_locked(core, &pkt, pkt.hdr.size);
}
static int iris_hfi_gen1_session_open(struct iris_inst *inst)
{
struct hfi_session_open_pkt packet;
u32 codec = 0;
int ret;
if (inst->state != IRIS_INST_DEINIT)
return -EALREADY;
switch (inst->codec) {
case V4L2_PIX_FMT_H264:
codec = HFI_VIDEO_CODEC_H264;
break;
case V4L2_PIX_FMT_HEVC:
codec = HFI_VIDEO_CODEC_HEVC;
break;
case V4L2_PIX_FMT_VP9:
codec = HFI_VIDEO_CODEC_VP9;
break;
}
packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt);
packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT;
packet.shdr.session_id = inst->session_id;
packet.session_domain = HFI_SESSION_TYPE_DEC;
packet.session_codec = codec;
reinit_completion(&inst->completion);
ret = iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size);
if (ret)
return ret;
return iris_wait_for_session_response(inst, false);
}
static void iris_hfi_gen1_packet_session_cmd(struct iris_inst *inst,
struct hfi_session_pkt *packet,
u32 ptype)
{
packet->shdr.hdr.size = sizeof(*packet);
packet->shdr.hdr.pkt_type = ptype;
packet->shdr.session_id = inst->session_id;
}
static int iris_hfi_gen1_session_close(struct iris_inst *inst)
{
struct hfi_session_pkt packet;
iris_hfi_gen1_packet_session_cmd(inst, &packet, HFI_CMD_SYS_SESSION_END);
return iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size);
}
static int iris_hfi_gen1_session_start(struct iris_inst *inst, u32 plane)
{
struct iris_core *core = inst->core;
struct hfi_session_pkt packet;
int ret;
if (!V4L2_TYPE_IS_OUTPUT(plane))
return 0;
if (inst->sub_state & IRIS_INST_SUB_LOAD_RESOURCES)
return 0;
reinit_completion(&inst->completion);
iris_hfi_gen1_packet_session_cmd(inst, &packet, HFI_CMD_SESSION_LOAD_RESOURCES);
ret = iris_hfi_queue_cmd_write(core, &packet, packet.shdr.hdr.size);
if (ret)
return ret;
ret = iris_wait_for_session_response(inst, false);
if (ret)
return ret;
reinit_completion(&inst->completion);
iris_hfi_gen1_packet_session_cmd(inst, &packet, HFI_CMD_SESSION_START);
ret = iris_hfi_queue_cmd_write(core, &packet, packet.shdr.hdr.size);
if (ret)
return ret;
ret = iris_wait_for_session_response(inst, false);
if (ret)
return ret;
return iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_LOAD_RESOURCES);
}
static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane)
{
struct hfi_session_flush_pkt flush_pkt;
struct iris_core *core = inst->core;
struct hfi_session_pkt pkt;
u32 flush_type = 0;
int ret = 0;
if ((V4L2_TYPE_IS_OUTPUT(plane) &&
inst->state == IRIS_INST_INPUT_STREAMING) ||
(V4L2_TYPE_IS_CAPTURE(plane) &&
inst->state == IRIS_INST_OUTPUT_STREAMING) ||
inst->state == IRIS_INST_ERROR) {
reinit_completion(&inst->completion);
iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP);
ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size);
if (!ret)
ret = iris_wait_for_session_response(inst, false);
reinit_completion(&inst->completion);
iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_RELEASE_RESOURCES);
ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size);
if (!ret)
ret = iris_wait_for_session_response(inst, false);
iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0);
iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
VB2_BUF_STATE_ERROR);
iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
VB2_BUF_STATE_ERROR);
} else if (inst->state == IRIS_INST_STREAMING) {
if (V4L2_TYPE_IS_OUTPUT(plane))
flush_type = HFI_FLUSH_ALL;
else if (V4L2_TYPE_IS_CAPTURE(plane))
flush_type = HFI_FLUSH_OUTPUT;
reinit_completion(&inst->flush_completion);
flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt);
flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH;
flush_pkt.shdr.session_id = inst->session_id;
flush_pkt.flush_type = flush_type;
ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size);
if (!ret) {
inst->flush_responses_pending++;
ret = iris_wait_for_session_response(inst, true);
}
}
return ret;
}
static int iris_hfi_gen1_session_continue(struct iris_inst *inst, u32 plane)
{
struct hfi_session_pkt packet;
iris_hfi_gen1_packet_session_cmd(inst, &packet, HFI_CMD_SESSION_CONTINUE);
return iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size);
}
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;
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_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:
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_session_drain(struct iris_inst *inst, u32 plane)
{
struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0};
ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt);
ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER;
ip_pkt.shdr.session_id = inst->session_id;
ip_pkt.flags = HFI_BUFFERFLAG_EOS;
if (inst->codec == V4L2_PIX_FMT_VP9)
ip_pkt.packet_buffer = 0xdeadb000;
return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size);
}
static int
iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *packet,
struct iris_inst *inst, u32 ptype, void *pdata)
{
void *prop_data = &packet->data[1];
packet->shdr.hdr.size = sizeof(*packet);
packet->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_PROPERTY;
packet->shdr.session_id = inst->session_id;
packet->num_properties = 1;
packet->data[0] = ptype;
switch (ptype) {
case HFI_PROPERTY_PARAM_FRAME_SIZE: {
struct hfi_framesize *in = pdata, *fsize = prop_data;
fsize->buffer_type = in->buffer_type;
fsize->height = in->height;
fsize->width = in->width;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*fsize);
break;
}
case HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE: {
struct hfi_videocores_usage_type *in = pdata, *cu = prop_data;
cu->video_core_enable_mask = in->video_core_enable_mask;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*cu);
break;
}
case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT: {
struct hfi_uncompressed_format_select *in = pdata;
struct hfi_uncompressed_format_select *hfi = prop_data;
hfi->buffer_type = in->buffer_type;
hfi->format = in->format;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*hfi);
break;
}
case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO: {
struct hfi_uncompressed_plane_actual_constraints_info *info = prop_data;
info->buffer_type = HFI_BUFFER_OUTPUT2;
info->num_planes = 2;
info->plane_format[0].stride_multiples = 128;
info->plane_format[0].max_stride = 8192;
info->plane_format[0].min_plane_buffer_height_multiple = 32;
info->plane_format[0].buffer_alignment = 256;
if (info->num_planes > 1) {
info->plane_format[1].stride_multiples = 128;
info->plane_format[1].max_stride = 8192;
info->plane_format[1].min_plane_buffer_height_multiple = 16;
info->plane_format[1].buffer_alignment = 256;
}
packet->shdr.hdr.size += sizeof(u32) + sizeof(*info);
break;
}
case HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL: {
struct hfi_buffer_count_actual *in = pdata;
struct hfi_buffer_count_actual *count = prop_data;
count->type = in->type;
count->count_actual = in->count_actual;
count->count_min_host = in->count_min_host;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*count);
break;
}
case HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM: {
struct hfi_multi_stream *in = pdata;
struct hfi_multi_stream *multi = prop_data;
multi->buffer_type = in->buffer_type;
multi->enable = in->enable;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*multi);
break;
}
case HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL: {
struct hfi_buffer_size_actual *in = pdata, *sz = prop_data;
sz->size = in->size;
sz->type = in->type;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*sz);
break;
}
case HFI_PROPERTY_PARAM_WORK_ROUTE: {
struct hfi_video_work_route *wr = prop_data;
u32 *in = pdata;
wr->video_work_route = *in;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*wr);
break;
}
case HFI_PROPERTY_PARAM_WORK_MODE: {
struct hfi_video_work_mode *wm = prop_data;
u32 *in = pdata;
wm->video_work_mode = *in;
packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm);
break;
}
default:
return -EINVAL;
}
return 0;
}
static int hfi_gen1_set_property(struct iris_inst *inst, u32 packet_type,
void *payload, u32 payload_size)
{
struct hfi_session_set_property_pkt *pkt;
u32 packet_size;
int ret;
packet_size = sizeof(*pkt) + sizeof(u32) + payload_size;
pkt = kzalloc(packet_size, GFP_KERNEL);
if (!pkt)
return -ENOMEM;
ret = iris_hfi_gen1_packet_session_set_property(pkt, inst, packet_type, payload);
if (ret == -EOPNOTSUPP) {
ret = 0;
goto exit;
}
if (ret)
goto exit;
ret = iris_hfi_queue_cmd_write(inst->core, pkt, pkt->shdr.hdr.size);
exit:
kfree(pkt);
return ret;
}
static int iris_hfi_gen1_session_set_property(struct iris_inst *inst, u32 packet_type,
u32 flag, u32 plane, u32 payload_type,
void *payload, u32 payload_size)
{
return hfi_gen1_set_property(inst, packet_type, payload, payload_size);
}
static int iris_hfi_gen1_set_resolution(struct iris_inst *inst)
{
u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE;
struct hfi_framesize fs;
int ret;
if (!iris_drc_pending(inst)) {
fs.buffer_type = HFI_BUFFER_INPUT;
fs.width = inst->fmt_src->fmt.pix_mp.width;
fs.height = inst->fmt_src->fmt.pix_mp.height;
ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs));
if (ret)
return ret;
}
fs.buffer_type = HFI_BUFFER_OUTPUT2;
fs.width = inst->fmt_dst->fmt.pix_mp.width;
fs.height = inst->fmt_dst->fmt.pix_mp.height;
return hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs));
}
static int iris_hfi_gen1_decide_core(struct iris_inst *inst)
{
const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
struct hfi_videocores_usage_type cu;
cu.video_core_enable_mask = HFI_CORE_ID_1;
return hfi_gen1_set_property(inst, ptype, &cu, sizeof(cu));
}
static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst)
{
const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat;
struct hfi_uncompressed_format_select fmt;
int ret;
if (iris_split_mode_enabled(inst)) {
fmt.buffer_type = HFI_BUFFER_OUTPUT;
fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12_UBWC : 0;
ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt));
if (ret)
return ret;
fmt.buffer_type = HFI_BUFFER_OUTPUT2;
fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0;
ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt));
} else {
fmt.buffer_type = HFI_BUFFER_OUTPUT;
fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0;
ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt));
}
return ret;
}
static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst)
{
const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO;
struct hfi_uncompressed_plane_actual_constraints_info pconstraint;
pconstraint.buffer_type = HFI_BUFFER_OUTPUT2;
pconstraint.num_planes = 2;
pconstraint.plane_format[0].stride_multiples = 128;
pconstraint.plane_format[0].max_stride = 8192;
pconstraint.plane_format[0].min_plane_buffer_height_multiple = 32;
pconstraint.plane_format[0].buffer_alignment = 256;
pconstraint.plane_format[1].stride_multiples = 128;
pconstraint.plane_format[1].max_stride = 8192;
pconstraint.plane_format[1].min_plane_buffer_height_multiple = 16;
pconstraint.plane_format[1].buffer_alignment = 256;
return hfi_gen1_set_property(inst, ptype, &pconstraint, sizeof(pconstraint));
}
static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst)
{
u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
struct hfi_buffer_count_actual buf_count;
int ret;
buf_count.type = HFI_BUFFER_INPUT;
buf_count.count_actual = VIDEO_MAX_FRAME;
buf_count.count_min_host = VIDEO_MAX_FRAME;
ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count));
if (ret)
return ret;
if (iris_split_mode_enabled(inst)) {
buf_count.type = HFI_BUFFER_OUTPUT;
buf_count.count_actual = VIDEO_MAX_FRAME;
buf_count.count_min_host = VIDEO_MAX_FRAME;
ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count));
if (ret)
return ret;
buf_count.type = HFI_BUFFER_OUTPUT2;
buf_count.count_actual = iris_vpu_buf_count(inst, BUF_DPB);
buf_count.count_min_host = iris_vpu_buf_count(inst, BUF_DPB);
ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count));
} else {
buf_count.type = HFI_BUFFER_OUTPUT;
buf_count.count_actual = VIDEO_MAX_FRAME;
buf_count.count_min_host = VIDEO_MAX_FRAME;
ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count));
}
return ret;
}
static int iris_hfi_gen1_set_multistream(struct iris_inst *inst)
{
u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
struct hfi_multi_stream multi = {0};
int ret;
if (iris_split_mode_enabled(inst)) {
multi.buffer_type = HFI_BUFFER_OUTPUT;
multi.enable = 0;
ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi));
if (ret)
return ret;
multi.buffer_type = HFI_BUFFER_OUTPUT2;
multi.enable = 1;
ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi));
} else {
multi.buffer_type = HFI_BUFFER_OUTPUT;
multi.enable = 1;
ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi));
if (ret)
return ret;
multi.buffer_type = HFI_BUFFER_OUTPUT2;
multi.enable = 0;
ret = hfi_gen1_set_property(inst, ptype, &multi, sizeof(multi));
}
return ret;
}
static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst)
{
const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL;
struct hfi_buffer_size_actual bufsz;
int ret;
if (iris_split_mode_enabled(inst)) {
bufsz.type = HFI_BUFFER_OUTPUT;
bufsz.size = iris_vpu_buf_size(inst, BUF_DPB);
ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
if (ret)
return ret;
bufsz.type = HFI_BUFFER_OUTPUT2;
bufsz.size = inst->buffers[BUF_OUTPUT].size;
ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
} else {
bufsz.type = HFI_BUFFER_OUTPUT;
bufsz.size = inst->buffers[BUF_OUTPUT].size;
ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
if (ret)
return ret;
bufsz.type = HFI_BUFFER_OUTPUT2;
bufsz.size = 0;
ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
}
return ret;
}
static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 plane)
{
struct iris_core *core = inst->core;
u32 config_params_size, i, j;
const u32 *config_params;
int ret;
static const struct iris_hfi_prop_type_handle prop_type_handle_inp_arr[] = {
{HFI_PROPERTY_PARAM_FRAME_SIZE,
iris_hfi_gen1_set_resolution},
{HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE,
iris_hfi_gen1_decide_core},
{HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT,
iris_hfi_gen1_set_raw_format},
{HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
iris_hfi_gen1_set_format_constraints},
{HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
iris_hfi_gen1_set_num_bufs},
{HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM,
iris_hfi_gen1_set_multistream},
{HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL,
iris_hfi_gen1_set_bufsize},
};
static const struct iris_hfi_prop_type_handle prop_type_handle_out_arr[] = {
{HFI_PROPERTY_PARAM_FRAME_SIZE,
iris_hfi_gen1_set_resolution},
{HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT,
iris_hfi_gen1_set_raw_format},
{HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
iris_hfi_gen1_set_format_constraints},
{HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
iris_hfi_gen1_set_num_bufs},
{HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM,
iris_hfi_gen1_set_multistream},
{HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL,
iris_hfi_gen1_set_bufsize},
};
config_params = core->iris_platform_data->input_config_params_default;
config_params_size = core->iris_platform_data->input_config_params_default_size;
if (V4L2_TYPE_IS_OUTPUT(plane)) {
for (i = 0; i < config_params_size; i++) {
for (j = 0; j < ARRAY_SIZE(prop_type_handle_inp_arr); j++) {
if (prop_type_handle_inp_arr[j].type == config_params[i]) {
ret = prop_type_handle_inp_arr[j].handle(inst);
if (ret)
return ret;
break;
}
}
}
} else if (V4L2_TYPE_IS_CAPTURE(plane)) {
for (i = 0; i < config_params_size; i++) {
for (j = 0; j < ARRAY_SIZE(prop_type_handle_out_arr); j++) {
if (prop_type_handle_out_arr[j].type == config_params[i]) {
ret = prop_type_handle_out_arr[j].handle(inst);
if (ret)
return ret;
break;
}
}
}
}
return 0;
}
static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops = {
.sys_init = iris_hfi_gen1_sys_init,
.sys_image_version = iris_hfi_gen1_sys_image_version,
.sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse,
.sys_pc_prep = iris_hfi_gen1_sys_pc_prep,
.session_open = iris_hfi_gen1_session_open,
.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_resume_drc = iris_hfi_gen1_session_continue,
.session_stop = iris_hfi_gen1_session_stop,
.session_drain = iris_hfi_gen1_session_drain,
.session_close = iris_hfi_gen1_session_close,
};
void iris_hfi_gen1_command_ops_init(struct iris_core *core)
{
core->hfi_ops = &iris_hfi_gen1_command_ops;
}
struct iris_inst *iris_hfi_gen1_get_instance(void)
{
return kzalloc(sizeof(struct iris_inst), GFP_KERNEL);
}