blob: 7ca5ae13d62b95fdcf71ef70cb6abf446b2c6e5a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/bitfield.h>
#include "iris_hfi_gen2.h"
#include "iris_hfi_gen2_packet.h"
#define UNSPECIFIED_COLOR_FORMAT 5
#define NUM_SYS_INIT_PACKETS 8
#define SYS_INIT_PKT_SIZE (sizeof(struct iris_hfi_header) + \
NUM_SYS_INIT_PACKETS * (sizeof(struct iris_hfi_packet) + sizeof(u32)))
#define SYS_IFPC_PKT_SIZE (sizeof(struct iris_hfi_header) + \
sizeof(struct iris_hfi_packet) + sizeof(u32))
#define SYS_NO_PAYLOAD_PKT_SIZE (sizeof(struct iris_hfi_header) + \
sizeof(struct iris_hfi_packet))
static int iris_hfi_gen2_sys_init(struct iris_core *core)
{
struct iris_hfi_header *hdr;
int ret;
hdr = kzalloc(SYS_INIT_PKT_SIZE, GFP_KERNEL);
if (!hdr)
return -ENOMEM;
iris_hfi_gen2_packet_sys_init(core, hdr);
ret = iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size);
kfree(hdr);
return ret;
}
static int iris_hfi_gen2_sys_image_version(struct iris_core *core)
{
struct iris_hfi_header *hdr;
int ret;
hdr = kzalloc(SYS_NO_PAYLOAD_PKT_SIZE, GFP_KERNEL);
if (!hdr)
return -ENOMEM;
iris_hfi_gen2_packet_image_version(core, hdr);
ret = iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size);
kfree(hdr);
return ret;
}
static int iris_hfi_gen2_sys_interframe_powercollapse(struct iris_core *core)
{
struct iris_hfi_header *hdr;
int ret;
hdr = kzalloc(SYS_IFPC_PKT_SIZE, GFP_KERNEL);
if (!hdr)
return -ENOMEM;
iris_hfi_gen2_packet_sys_interframe_powercollapse(core, hdr);
ret = iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size);
kfree(hdr);
return ret;
}
static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core)
{
struct iris_hfi_header *hdr;
int ret;
hdr = kzalloc(SYS_NO_PAYLOAD_PKT_SIZE, GFP_KERNEL);
if (!hdr)
return -ENOMEM;
iris_hfi_gen2_packet_sys_pc_prep(core, hdr);
ret = iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size);
kfree(hdr);
return ret;
}
static u32 iris_hfi_gen2_get_port(u32 plane)
{
switch (plane) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return HFI_PORT_BITSTREAM;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return HFI_PORT_RAW;
default:
return HFI_PORT_NONE;
}
}
static u32 iris_hfi_gen2_get_port_from_buf_type(enum iris_buffer_type buffer_type)
{
switch (buffer_type) {
case BUF_INPUT:
case BUF_BIN:
case BUF_COMV:
case BUF_NON_COMV:
case BUF_LINE:
return HFI_PORT_BITSTREAM;
case BUF_OUTPUT:
case BUF_DPB:
return HFI_PORT_RAW;
case BUF_PERSIST:
default:
return HFI_PORT_NONE;
}
}
static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 packet_type, u32 flag,
u32 plane, u32 payload_type, void *payload,
u32 payload_size)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
iris_hfi_gen2_packet_session_property(inst,
packet_type,
flag,
plane,
payload_type,
payload,
payload_size);
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 resolution = inst->fmt_src->fmt.pix_mp.width << 16 |
inst->fmt_src->fmt.pix_mp.height;
inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_BITSTREAM_RESOLUTION,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&resolution,
sizeof(u32));
}
static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst)
{
u32 bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height);
u32 right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width);
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 left_offset = inst->crop.left;
u32 top_offset = inst->crop.top;
u32 payload[2];
payload[0] = FIELD_PREP(GENMASK(31, 16), left_offset) | top_offset;
payload[1] = FIELD_PREP(GENMASK(31, 16), right_offset) | bottom_offset;
inst_hfi_gen2->src_subcr_params.crop_offsets[0] = payload[0];
inst_hfi_gen2->src_subcr_params.crop_offsets[1] = payload[1];
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_CROP_OFFSETS,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_64_PACKED,
&payload,
sizeof(u64));
}
static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 bitdepth = BIT_DEPTH_8;
inst_hfi_gen2->src_subcr_params.bit_depth = bitdepth;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&bitdepth,
sizeof(u32));
}
static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 coded_frames = 0;
if (inst->fw_caps[CODED_FRAMES].value == CODED_FRAMES_PROGRESSIVE)
coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
inst_hfi_gen2->src_subcr_params.coded_frames = coded_frames;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_CODED_FRAMES,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&coded_frames,
sizeof(u32));
}
static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 min_output = inst->buffers[BUF_OUTPUT].min_count;
inst_hfi_gen2->src_subcr_params.fw_min_count = min_output;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&min_output,
sizeof(u32));
}
static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 poc = 0;
inst_hfi_gen2->src_subcr_params.pic_order_cnt = poc;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_PIC_ORDER_CNT_TYPE,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&poc,
sizeof(u32));
}
static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
struct v4l2_pix_format_mplane *pixmp = &inst->fmt_src->fmt.pix_mp;
u32 video_signal_type_present_flag = 0, color_info;
u32 matrix_coeff = HFI_MATRIX_COEFF_RESERVED;
u32 video_format = UNSPECIFIED_COLOR_FORMAT;
u32 full_range = V4L2_QUANTIZATION_DEFAULT;
u32 transfer_char = HFI_TRANSFER_RESERVED;
u32 colour_description_present_flag = 0;
u32 primaries = HFI_PRIMARIES_RESERVED;
if (pixmp->colorspace != V4L2_COLORSPACE_DEFAULT ||
pixmp->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT ||
pixmp->xfer_func != V4L2_XFER_FUNC_DEFAULT) {
colour_description_present_flag = 1;
video_signal_type_present_flag = 1;
primaries = iris_hfi_gen2_get_color_primaries(pixmp->colorspace);
matrix_coeff = iris_hfi_gen2_get_matrix_coefficients(pixmp->ycbcr_enc);
transfer_char = iris_hfi_gen2_get_transfer_char(pixmp->xfer_func);
}
if (pixmp->quantization != V4L2_QUANTIZATION_DEFAULT) {
video_signal_type_present_flag = 1;
full_range = pixmp->quantization == V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
}
color_info = iris_hfi_gen2_get_color_info(matrix_coeff, transfer_char, primaries,
colour_description_present_flag, full_range,
video_format, video_signal_type_present_flag);
inst_hfi_gen2->src_subcr_params.color_info = color_info;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_SIGNAL_COLOR_INFO,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_32_PACKED,
&color_info,
sizeof(u32));
}
static int iris_hfi_gen2_set_profile(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 profile = 0;
switch (inst->codec) {
case V4L2_PIX_FMT_HEVC:
profile = inst->fw_caps[PROFILE_HEVC].value;
break;
case V4L2_PIX_FMT_VP9:
profile = inst->fw_caps[PROFILE_VP9].value;
break;
case V4L2_PIX_FMT_H264:
profile = inst->fw_caps[PROFILE_H264].value;
break;
}
inst_hfi_gen2->src_subcr_params.profile = profile;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_PROFILE,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32_ENUM,
&profile,
sizeof(u32));
}
static int iris_hfi_gen2_set_level(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 level = 0;
switch (inst->codec) {
case V4L2_PIX_FMT_HEVC:
level = inst->fw_caps[LEVEL_HEVC].value;
break;
case V4L2_PIX_FMT_VP9:
level = inst->fw_caps[LEVEL_VP9].value;
break;
case V4L2_PIX_FMT_H264:
level = inst->fw_caps[LEVEL_H264].value;
break;
}
inst_hfi_gen2->src_subcr_params.level = level;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_LEVEL,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32_ENUM,
&level,
sizeof(u32));
}
static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst)
{
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
u32 hfi_colorformat, pixelformat;
pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat;
hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_COLOR_FORMAT,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32,
&hfi_colorformat,
sizeof(u32));
}
static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst)
{
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat;
u32 scanline_y = inst->fmt_dst->fmt.pix_mp.height;
u32 stride_y = inst->fmt_dst->fmt.pix_mp.width;
u32 scanline_uv = scanline_y / 2;
u32 stride_uv = stride_y;
u32 payload[2];
if (pixelformat != V4L2_PIX_FMT_NV12)
return 0;
payload[0] = stride_y << 16 | scanline_y;
payload[1] = stride_uv << 16 | scanline_uv;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_LINEAR_STRIDE_SCANLINE,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U64,
&payload,
sizeof(u64));
}
static int iris_hfi_gen2_set_tier(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
u32 tier = inst->fw_caps[TIER].value;
inst_hfi_gen2->src_subcr_params.tier = tier;
return iris_hfi_gen2_session_set_property(inst,
HFI_PROP_TIER,
HFI_HOST_FLAGS_NONE,
port,
HFI_PAYLOAD_U32_ENUM,
&tier,
sizeof(u32));
}
static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane)
{
struct iris_core *core = inst->core;
u32 config_params_size = 0, i, j;
const u32 *config_params = NULL;
int ret;
static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = {
{HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution },
{HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets },
{HFI_PROP_CODED_FRAMES, iris_hfi_gen2_set_coded_frames },
{HFI_PROP_LUMA_CHROMA_BIT_DEPTH, iris_hfi_gen2_set_bit_depth },
{HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, iris_hfi_gen2_set_min_output_count },
{HFI_PROP_PIC_ORDER_CNT_TYPE, iris_hfi_gen2_set_picture_order_count },
{HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace },
{HFI_PROP_PROFILE, iris_hfi_gen2_set_profile },
{HFI_PROP_LEVEL, iris_hfi_gen2_set_level },
{HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat },
{HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline },
{HFI_PROP_TIER, iris_hfi_gen2_set_tier },
};
if (V4L2_TYPE_IS_OUTPUT(plane)) {
switch (inst->codec) {
case V4L2_PIX_FMT_H264:
config_params = core->iris_platform_data->input_config_params_default;
config_params_size =
core->iris_platform_data->input_config_params_default_size;
break;
case V4L2_PIX_FMT_HEVC:
config_params = core->iris_platform_data->input_config_params_hevc;
config_params_size =
core->iris_platform_data->input_config_params_hevc_size;
break;
case V4L2_PIX_FMT_VP9:
config_params = core->iris_platform_data->input_config_params_vp9;
config_params_size =
core->iris_platform_data->input_config_params_vp9_size;
break;
}
} else {
config_params = core->iris_platform_data->output_config_params;
config_params_size = core->iris_platform_data->output_config_params_size;
}
if (!config_params || !config_params_size)
return -EINVAL;
for (i = 0; i < config_params_size; i++) {
for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
if (prop_type_handle_arr[j].type == config_params[i]) {
ret = prop_type_handle_arr[j].handle(inst);
if (ret)
return ret;
break;
}
}
}
return 0;
}
static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 codec = 0;
switch (inst->codec) {
case V4L2_PIX_FMT_H264:
codec = HFI_CODEC_DECODE_AVC;
break;
case V4L2_PIX_FMT_HEVC:
codec = HFI_CODEC_DECODE_HEVC;
break;
case V4L2_PIX_FMT_VP9:
codec = HFI_CODEC_DECODE_VP9;
break;
}
iris_hfi_gen2_packet_session_property(inst,
HFI_PROP_CODEC,
HFI_HOST_FLAGS_NONE,
HFI_PORT_NONE,
HFI_PAYLOAD_U32_ENUM,
&codec,
sizeof(u32));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_set_default_header(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 default_header = false;
iris_hfi_gen2_packet_session_property(inst,
HFI_PROP_DEC_DEFAULT_HEADER,
HFI_HOST_FLAGS_NONE,
HFI_PORT_BITSTREAM,
HFI_PAYLOAD_U32,
&default_header,
sizeof(u32));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_open(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
int ret;
if (inst->state != IRIS_INST_DEINIT)
return -EALREADY;
inst_hfi_gen2->ipsc_properties_set = false;
inst_hfi_gen2->opsc_properties_set = false;
inst_hfi_gen2->packet = kzalloc(4096, GFP_KERNEL);
if (!inst_hfi_gen2->packet)
return -ENOMEM;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_OPEN,
HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED,
HFI_PORT_NONE,
0,
HFI_PAYLOAD_U32,
&inst->session_id,
sizeof(u32));
ret = iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
if (ret)
goto fail_free_packet;
ret = iris_hfi_gen2_session_set_codec(inst);
if (ret)
goto fail_free_packet;
ret = iris_hfi_gen2_session_set_default_header(inst);
if (ret)
goto fail_free_packet;
return 0;
fail_free_packet:
kfree(inst_hfi_gen2->packet);
inst_hfi_gen2->packet = NULL;
return ret;
}
static int iris_hfi_gen2_session_close(struct iris_inst *inst)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
int ret;
if (!inst_hfi_gen2->packet)
return -EINVAL;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_CLOSE,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED |
HFI_HOST_FLAGS_NON_DISCARDABLE),
HFI_PORT_NONE,
inst->session_id,
HFI_PAYLOAD_NONE,
NULL,
0);
ret = iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
kfree(inst_hfi_gen2->packet);
inst_hfi_gen2->packet = NULL;
return ret;
}
static int iris_hfi_gen2_session_subscribe_mode(struct iris_inst *inst,
u32 cmd, u32 plane, u32 payload_type,
void *payload, u32 payload_size)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
iris_hfi_gen2_packet_session_command(inst,
cmd,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
iris_hfi_gen2_get_port(plane),
inst->session_id,
payload_type,
payload,
payload_size);
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
struct hfi_subscription_params subsc_params;
u32 prop_type, payload_size, payload_type;
struct iris_core *core = inst->core;
const u32 *change_param = NULL;
u32 change_param_size = 0;
u32 payload[32] = {0};
u32 hfi_port = 0, i;
int ret;
if ((V4L2_TYPE_IS_OUTPUT(plane) && inst_hfi_gen2->ipsc_properties_set) ||
(V4L2_TYPE_IS_CAPTURE(plane) && inst_hfi_gen2->opsc_properties_set)) {
dev_err(core->dev, "invalid plane\n");
return 0;
}
switch (inst->codec) {
case V4L2_PIX_FMT_H264:
change_param = core->iris_platform_data->input_config_params_default;
change_param_size =
core->iris_platform_data->input_config_params_default_size;
break;
case V4L2_PIX_FMT_HEVC:
change_param = core->iris_platform_data->input_config_params_hevc;
change_param_size =
core->iris_platform_data->input_config_params_hevc_size;
break;
case V4L2_PIX_FMT_VP9:
change_param = core->iris_platform_data->input_config_params_vp9;
change_param_size =
core->iris_platform_data->input_config_params_vp9_size;
break;
}
payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
for (i = 0; i < change_param_size; i++)
payload[i + 1] = change_param[i];
ret = iris_hfi_gen2_session_subscribe_mode(inst,
HFI_CMD_SUBSCRIBE_MODE,
plane,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
((change_param_size + 1) * sizeof(u32)));
if (ret)
return ret;
if (V4L2_TYPE_IS_OUTPUT(plane)) {
inst_hfi_gen2->ipsc_properties_set = true;
} else {
hfi_port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
memcpy(&inst_hfi_gen2->dst_subcr_params,
&inst_hfi_gen2->src_subcr_params,
sizeof(inst_hfi_gen2->src_subcr_params));
subsc_params = inst_hfi_gen2->dst_subcr_params;
for (i = 0; i < change_param_size; i++) {
payload[0] = 0;
payload[1] = 0;
payload_size = 0;
payload_type = 0;
prop_type = change_param[i];
switch (prop_type) {
case HFI_PROP_BITSTREAM_RESOLUTION:
payload[0] = subsc_params.bitstream_resolution;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_CROP_OFFSETS:
payload[0] = subsc_params.crop_offsets[0];
payload[1] = subsc_params.crop_offsets[1];
payload_size = sizeof(u64);
payload_type = HFI_PAYLOAD_64_PACKED;
break;
case HFI_PROP_CODED_FRAMES:
payload[0] = subsc_params.coded_frames;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
payload[0] = subsc_params.bit_depth;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
payload[0] = subsc_params.fw_min_count;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_PIC_ORDER_CNT_TYPE:
payload[0] = subsc_params.pic_order_cnt;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_SIGNAL_COLOR_INFO:
payload[0] = subsc_params.color_info;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_PROFILE:
payload[0] = subsc_params.profile;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_LEVEL:
payload[0] = subsc_params.level;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
case HFI_PROP_TIER:
payload[0] = subsc_params.tier;
payload_size = sizeof(u32);
payload_type = HFI_PAYLOAD_U32;
break;
default:
prop_type = 0;
ret = -EINVAL;
break;
}
if (prop_type) {
ret = iris_hfi_gen2_session_set_property(inst,
prop_type,
HFI_HOST_FLAGS_NONE,
hfi_port,
payload_type,
&payload,
payload_size);
if (ret)
return ret;
}
}
inst_hfi_gen2->opsc_properties_set = true;
}
return 0;
}
static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane)
{
struct iris_core *core = inst->core;
u32 subscribe_prop_size = 0, i;
const u32 *subcribe_prop = NULL;
u32 payload[32] = {0};
payload[0] = HFI_MODE_PROPERTY;
if (V4L2_TYPE_IS_OUTPUT(plane)) {
subscribe_prop_size = core->iris_platform_data->dec_input_prop_size;
subcribe_prop = core->iris_platform_data->dec_input_prop;
} else {
switch (inst->codec) {
case V4L2_PIX_FMT_H264:
subcribe_prop = core->iris_platform_data->dec_output_prop_avc;
subscribe_prop_size =
core->iris_platform_data->dec_output_prop_avc_size;
break;
case V4L2_PIX_FMT_HEVC:
subcribe_prop = core->iris_platform_data->dec_output_prop_hevc;
subscribe_prop_size =
core->iris_platform_data->dec_output_prop_hevc_size;
break;
case V4L2_PIX_FMT_VP9:
subcribe_prop = core->iris_platform_data->dec_output_prop_vp9;
subscribe_prop_size =
core->iris_platform_data->dec_output_prop_vp9_size;
break;
}
}
for (i = 0; i < subscribe_prop_size; i++)
payload[i + 1] = subcribe_prop[i];
return iris_hfi_gen2_session_subscribe_mode(inst,
HFI_CMD_SUBSCRIBE_MODE,
plane,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
(subscribe_prop_size + 1) * sizeof(u32));
}
static int iris_hfi_gen2_session_start(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
int ret = 0;
ret = iris_hfi_gen2_subscribe_change_param(inst, plane);
if (ret)
return ret;
ret = iris_hfi_gen2_subscribe_property(inst, plane);
if (ret)
return ret;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_START,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_NONE,
NULL,
0);
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_stop(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
int ret = 0;
reinit_completion(&inst->completion);
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_STOP,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED |
HFI_HOST_FLAGS_NON_DISCARDABLE),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_NONE,
NULL,
0);
ret = iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
if (ret)
return ret;
return iris_wait_for_session_response(inst, false);
}
static int iris_hfi_gen2_session_pause(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_PAUSE,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_NONE,
NULL,
0);
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_resume_drc(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 payload = HFI_CMD_SETTINGS_CHANGE;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_RESUME,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_U32,
&payload,
sizeof(u32));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_resume_drain(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
u32 payload = HFI_CMD_DRAIN;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_RESUME,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_U32,
&payload,
sizeof(u32));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
if (!V4L2_TYPE_IS_OUTPUT(plane))
return 0;
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_DRAIN,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED |
HFI_HOST_FLAGS_NON_DISCARDABLE),
iris_hfi_gen2_get_port(plane),
inst->session_id,
HFI_PAYLOAD_NONE,
NULL,
0);
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type)
{
switch (buffer_type) {
case BUF_INPUT:
return HFI_BUFFER_BITSTREAM;
case BUF_OUTPUT:
return HFI_BUFFER_RAW;
case BUF_BIN:
return HFI_BUFFER_BIN;
case BUF_COMV:
return HFI_BUFFER_COMV;
case BUF_NON_COMV:
return HFI_BUFFER_NON_COMV;
case BUF_LINE:
return HFI_BUFFER_LINE;
case BUF_DPB:
return HFI_BUFFER_DPB;
case BUF_PERSIST:
return HFI_BUFFER_PERSIST;
default:
return 0;
}
}
static int iris_set_num_comv(struct iris_inst *inst)
{
struct platform_inst_caps *caps;
struct iris_core *core = inst->core;
u32 num_comv;
caps = core->iris_platform_data->inst_caps;
num_comv = caps->num_comv;
return core->hfi_ops->session_set_property(inst,
HFI_PROP_COMV_BUFFER_COUNT,
HFI_HOST_FLAGS_NONE,
HFI_PORT_BITSTREAM,
HFI_PAYLOAD_U32,
&num_comv, sizeof(u32));
}
static void iris_hfi_gen2_get_buffer(struct iris_buffer *buffer, struct iris_hfi_buffer *buf)
{
memset(buf, 0, sizeof(*buf));
buf->type = iris_hfi_gen2_buf_type_from_driver(buffer->type);
buf->index = buffer->index;
buf->base_address = buffer->device_addr;
buf->addr_offset = 0;
buf->buffer_size = buffer->buffer_size;
if (buffer->type == BUF_INPUT)
buf->buffer_size = ALIGN(buffer->buffer_size, 256);
buf->data_offset = buffer->data_offset;
buf->data_size = buffer->data_size;
if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
buf->flags |= HFI_BUF_HOST_FLAG_RELEASE;
buf->flags |= HFI_BUF_HOST_FLAGS_CB_NON_SECURE;
buf->timestamp = buffer->timestamp;
}
static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct iris_buffer *buffer)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
struct iris_hfi_buffer hfi_buffer;
u32 port;
int ret;
iris_hfi_gen2_get_buffer(buffer, &hfi_buffer);
if (buffer->type == BUF_COMV) {
ret = iris_set_num_comv(inst);
if (ret)
return ret;
}
port = iris_hfi_gen2_get_port_from_buf_type(buffer->type);
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_BUFFER,
HFI_HOST_FLAGS_INTR_REQUIRED,
port,
inst->session_id,
HFI_PAYLOAD_STRUCTURE,
&hfi_buffer,
sizeof(hfi_buffer));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct iris_buffer *buffer)
{
struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
struct iris_hfi_buffer hfi_buffer;
u32 port;
iris_hfi_gen2_get_buffer(buffer, &hfi_buffer);
hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE;
port = iris_hfi_gen2_get_port_from_buf_type(buffer->type);
iris_hfi_gen2_packet_session_command(inst,
HFI_CMD_BUFFER,
(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
HFI_HOST_FLAGS_INTR_REQUIRED),
port,
inst->session_id,
HFI_PAYLOAD_STRUCTURE,
&hfi_buffer,
sizeof(hfi_buffer));
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = {
.sys_init = iris_hfi_gen2_sys_init,
.sys_image_version = iris_hfi_gen2_sys_image_version,
.sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse,
.sys_pc_prep = iris_hfi_gen2_sys_pc_prep,
.session_open = iris_hfi_gen2_session_open,
.session_set_config_params = iris_hfi_gen2_session_set_config_params,
.session_set_property = iris_hfi_gen2_session_set_property,
.session_start = iris_hfi_gen2_session_start,
.session_queue_buf = iris_hfi_gen2_session_queue_buffer,
.session_release_buf = iris_hfi_gen2_session_release_buffer,
.session_pause = iris_hfi_gen2_session_pause,
.session_resume_drc = iris_hfi_gen2_session_resume_drc,
.session_stop = iris_hfi_gen2_session_stop,
.session_drain = iris_hfi_gen2_session_drain,
.session_resume_drain = iris_hfi_gen2_session_resume_drain,
.session_close = iris_hfi_gen2_session_close,
};
void iris_hfi_gen2_command_ops_init(struct iris_core *core)
{
core->hfi_ops = &iris_hfi_gen2_command_ops;
}
struct iris_inst *iris_hfi_gen2_get_instance(void)
{
return kzalloc(sizeof(struct iris_inst_hfi_gen2), GFP_KERNEL);
}