| // 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); |
| } |