Handle the response sent by the firmware, when a source change is detected. Read the subscribed parameter to get the changed values. Raise the source change event to the client and update the instance sub-state. Mark the last buffer from before the source change with the V4L2_BUF_FLAG_LAST flag and return to the client. Reviewed-by: Hans Verkuil <hverkuil@xxxxxxxxx> Tested-by: Stefan Schmidt <stefan.schmidt@xxxxxxxxxx> # x1e80100 (Dell XPS 13 9345) Reviewed-by: Stefan Schmidt <stefan.schmidt@xxxxxxxxxx> Tested-by: Neil Armstrong <neil.armstrong@xxxxxxxxxx> # on SM8550-QRD Tested-by: Neil Armstrong <neil.armstrong@xxxxxxxxxx> # on SM8550-HDK Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx> --- drivers/media/platform/qcom/iris/iris_hfi_common.c | 64 +++++++ drivers/media/platform/qcom/iris/iris_hfi_common.h | 3 + .../platform/qcom/iris/iris_hfi_gen1_defines.h | 82 ++++++++ .../platform/qcom/iris/iris_hfi_gen1_response.c | 208 +++++++++++++++++++++ .../platform/qcom/iris/iris_hfi_gen2_defines.h | 4 + .../platform/qcom/iris/iris_hfi_gen2_response.c | 183 +++++++++++++++++- drivers/media/platform/qcom/iris/iris_instance.h | 2 + drivers/media/platform/qcom/iris/iris_state.c | 64 +++++++ drivers/media/platform/qcom/iris/iris_state.h | 33 ++++ drivers/media/platform/qcom/iris/iris_vb2.c | 18 ++ drivers/media/platform/qcom/iris/iris_vdec.c | 15 ++ drivers/media/platform/qcom/iris/iris_vdec.h | 1 + 12 files changed, 676 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/media/platform/qcom/iris/iris_hfi_common.c index 29f56c2bf74c..92112eb16c11 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.c @@ -10,6 +10,70 @@ #include "iris_hfi_common.h" #include "iris_vpu_common.h" +u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries) +{ + switch (hfi_primaries) { + case HFI_PRIMARIES_RESERVED: + return V4L2_COLORSPACE_DEFAULT; + case HFI_PRIMARIES_BT709: + return V4L2_COLORSPACE_REC709; + case HFI_PRIMARIES_BT470_SYSTEM_M: + return V4L2_COLORSPACE_470_SYSTEM_M; + case HFI_PRIMARIES_BT470_SYSTEM_BG: + return V4L2_COLORSPACE_470_SYSTEM_BG; + case HFI_PRIMARIES_BT601_525: + return V4L2_COLORSPACE_SMPTE170M; + case HFI_PRIMARIES_SMPTE_ST240M: + return V4L2_COLORSPACE_SMPTE240M; + case HFI_PRIMARIES_BT2020: + return V4L2_COLORSPACE_BT2020; + case V4L2_COLORSPACE_DCI_P3: + return HFI_PRIMARIES_SMPTE_RP431_2; + default: + return V4L2_COLORSPACE_DEFAULT; + } +} + +u32 iris_hfi_get_v4l2_transfer_char(u32 hfi_characterstics) +{ + switch (hfi_characterstics) { + case HFI_TRANSFER_RESERVED: + return V4L2_XFER_FUNC_DEFAULT; + case HFI_TRANSFER_BT709: + return V4L2_XFER_FUNC_709; + case HFI_TRANSFER_SMPTE_ST240M: + return V4L2_XFER_FUNC_SMPTE240M; + case HFI_TRANSFER_SRGB_SYCC: + return V4L2_XFER_FUNC_SRGB; + case HFI_TRANSFER_SMPTE_ST2084_PQ: + return V4L2_XFER_FUNC_SMPTE2084; + default: + return V4L2_XFER_FUNC_DEFAULT; + } +} + +u32 iris_hfi_get_v4l2_matrix_coefficients(u32 hfi_coefficients) +{ + switch (hfi_coefficients) { + case HFI_MATRIX_COEFF_RESERVED: + return V4L2_YCBCR_ENC_DEFAULT; + case HFI_MATRIX_COEFF_BT709: + return V4L2_YCBCR_ENC_709; + case HFI_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625: + return V4L2_YCBCR_ENC_XV601; + case HFI_MATRIX_COEFF_BT601_525_BT1358_525_OR_625: + return V4L2_YCBCR_ENC_601; + case HFI_MATRIX_COEFF_SMPTE_ST240: + return V4L2_YCBCR_ENC_SMPTE240M; + case HFI_MATRIX_COEFF_BT2020_NON_CONSTANT: + return V4L2_YCBCR_ENC_BT2020; + case HFI_MATRIX_COEFF_BT2020_CONSTANT: + return V4L2_YCBCR_ENC_BT2020_CONST_LUM; + default: + return V4L2_YCBCR_ENC_DEFAULT; + } +} + int iris_hfi_core_init(struct iris_core *core) { const struct iris_hfi_command_ops *hfi_ops = core->hfi_ops; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h index c54c88658633..6241098dc31d 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h @@ -138,6 +138,9 @@ struct hfi_subscription_params { u32 level; }; +u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries); +u32 iris_hfi_get_v4l2_transfer_char(u32 hfi_characterstics); +u32 iris_hfi_get_v4l2_matrix_coefficients(u32 hfi_coefficients); int iris_hfi_core_init(struct iris_core *core); int iris_hfi_pm_suspend(struct iris_core *core); int iris_hfi_pm_resume(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 108449d703e1..416e9a19a26f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -44,18 +44,28 @@ #define HFI_EVENT_SYS_ERROR 0x1 #define HFI_EVENT_SESSION_ERROR 0x2 +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES 0x1000001 +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES 0x1000002 +#define HFI_EVENT_SESSION_SEQUENCE_CHANGED 0x1000003 + #define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 #define HFI_FLUSH_OUTPUT 0x1000002 #define HFI_FLUSH_OUTPUT2 0x1000003 #define HFI_FLUSH_ALL 0x1000004 +#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000e + #define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL 0x201001 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO 0x201002 #define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE 0x201008 #define HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL 0x20100c +#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 + #define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER 0x1200001 +#define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e +#define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 #define HFI_BUFFER_INPUT 0x1 #define HFI_BUFFER_OUTPUT 0x2 @@ -69,11 +79,15 @@ #define HFI_PROPERTY_PARAM_FRAME_SIZE 0x1001 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT 0x1003 +#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT 0x1005 #define HFI_PROPERTY_PARAM_WORK_MODE 0x1015 #define HFI_PROPERTY_PARAM_WORK_ROUTE 0x1017 #define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE 0x2002 #define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM 0x1003001 +#define HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH 0x1003007 +#define HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT 0x1003009 +#define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE 0x100300a #define HFI_CORE_ID_1 1 #define HFI_COLOR_FORMAT_NV12 0x02 #define HFI_COLOR_FORMAT_NV12_UBWC 0x8002 @@ -249,6 +263,11 @@ struct hfi_enable { u32 enable; }; +struct hfi_profile_level { + u32 profile; + u32 level; +}; + struct hfi_framesize { u32 buffer_type; u32 width; @@ -267,6 +286,37 @@ struct hfi_video_work_route { u32 video_work_route; }; +struct hfi_bit_depth { + u32 buffer_type; + u32 bit_depth; +}; + +struct hfi_pic_struct { + u32 progressive_only; +}; + +struct hfi_colour_space { + u32 colour_space; +}; + +struct hfi_extradata_input_crop { + u32 size; + u32 version; + u32 port_index; + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct hfi_dpb_counts { + u32 max_dpb_count; + u32 max_ref_frames; + u32 max_dec_buffering; + u32 max_reorder_frames; + u32 fw_min_count; +}; + struct hfi_uncompressed_format_select { u32 buffer_type; u32 format; @@ -301,6 +351,38 @@ struct hfi_multi_stream { u32 enable; }; +struct hfi_buffer_requirements { + u32 type; + u32 size; + u32 region_size; + u32 hold_count; + u32 count_min; + u32 count_actual; + u32 contiguous; + u32 alignment; +}; + +struct hfi_event_data { + u32 error; + u32 height; + u32 width; + u32 event_type; + u32 packet_buffer; + u32 extradata_buffer; + u32 tag; + u32 profile; + u32 level; + u32 bit_depth; + u32 pic_struct; + u32 colour_space; + u32 entropy_mode; + u32 buf_count; + struct { + u32 left, top; + u32 width, height; + } input_crop; +}; + struct hfi_msg_session_empty_buffer_done_pkt { struct hfi_msg_session_hdr_pkt shdr; u32 offset; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c index 23a8bf29e381..3a47d9f39695 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c @@ -3,11 +3,216 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include <linux/bitfield.h> #include <media/v4l2-mem2mem.h> #include "iris_hfi_gen1.h" #include "iris_hfi_gen1_defines.h" #include "iris_instance.h" +#include "iris_vdec.h" +#include "iris_vpu_buffer.h" + +static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst, + struct hfi_msg_event_notify_pkt *pkt) +{ + struct v4l2_pix_format_mplane *pixmp_ip = &inst->fmt_src->fmt.pix_mp; + struct v4l2_pix_format_mplane *pixmp_op = &inst->fmt_dst->fmt.pix_mp; + u32 num_properties_changed = pkt->event_data2; + u8 *data_ptr = (u8 *)&pkt->ext_event_data[0]; + u32 primaries, matrix_coeff, transfer_char; + struct hfi_dpb_counts *iris_vpu_dpb_count; + struct hfi_profile_level *profile_level; + struct hfi_buffer_requirements *bufreq; + struct hfi_extradata_input_crop *crop; + struct hfi_colour_space *colour_info; + struct iris_core *core = inst->core; + u32 colour_description_present_flag; + u32 video_signal_type_present_flag; + struct hfi_event_data event = {0}; + struct hfi_bit_depth *pixel_depth; + struct hfi_pic_struct *pic_struct; + struct hfi_framesize *frame_sz; + struct vb2_queue *dst_q; + struct v4l2_ctrl *ctrl; + u32 full_range, ptype; + + do { + ptype = *((u32 *)data_ptr); + switch (ptype) { + case HFI_PROPERTY_PARAM_FRAME_SIZE: + data_ptr += sizeof(u32); + frame_sz = (struct hfi_framesize *)data_ptr; + event.width = frame_sz->width; + event.height = frame_sz->height; + data_ptr += sizeof(*frame_sz); + break; + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + data_ptr += sizeof(u32); + profile_level = (struct hfi_profile_level *)data_ptr; + event.profile = profile_level->profile; + event.level = profile_level->level; + data_ptr += sizeof(*profile_level); + break; + case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + data_ptr += sizeof(u32); + pixel_depth = (struct hfi_bit_depth *)data_ptr; + event.bit_depth = pixel_depth->bit_depth; + data_ptr += sizeof(*pixel_depth); + break; + case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + data_ptr += sizeof(u32); + pic_struct = (struct hfi_pic_struct *)data_ptr; + event.pic_struct = pic_struct->progressive_only; + data_ptr += sizeof(*pic_struct); + break; + case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + data_ptr += sizeof(u32); + colour_info = (struct hfi_colour_space *)data_ptr; + event.colour_space = colour_info->colour_space; + data_ptr += sizeof(*colour_info); + break; + case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: + data_ptr += sizeof(u32); + event.entropy_mode = *(u32 *)data_ptr; + data_ptr += sizeof(u32); + break; + case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + data_ptr += sizeof(u32); + bufreq = (struct hfi_buffer_requirements *)data_ptr; + event.buf_count = bufreq->count_min; + data_ptr += sizeof(*bufreq); + break; + case HFI_INDEX_EXTRADATA_INPUT_CROP: + data_ptr += sizeof(u32); + crop = (struct hfi_extradata_input_crop *)data_ptr; + event.input_crop.left = crop->left; + event.input_crop.top = crop->top; + event.input_crop.width = crop->width; + event.input_crop.height = crop->height; + data_ptr += sizeof(*crop); + break; + case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + data_ptr += sizeof(u32); + iris_vpu_dpb_count = (struct hfi_dpb_counts *)data_ptr; + event.buf_count = iris_vpu_dpb_count->fw_min_count; + data_ptr += sizeof(*iris_vpu_dpb_count); + break; + default: + break; + } + num_properties_changed--; + } while (num_properties_changed > 0); + + pixmp_ip->width = event.width; + pixmp_ip->height = event.height; + + pixmp_op->width = ALIGN(event.width, 128); + pixmp_op->height = ALIGN(event.height, 32); + pixmp_op->plane_fmt[0].bytesperline = ALIGN(event.width, 128); + pixmp_op->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); + + matrix_coeff = FIELD_GET(GENMASK(7, 0), event.colour_space); + transfer_char = FIELD_GET(GENMASK(15, 8), event.colour_space); + primaries = FIELD_GET(GENMASK(23, 16), event.colour_space); + colour_description_present_flag = FIELD_GET(GENMASK(24, 24), event.colour_space); + full_range = FIELD_GET(GENMASK(25, 25), event.colour_space); + video_signal_type_present_flag = FIELD_GET(GENMASK(29, 29), event.colour_space); + + pixmp_op->colorspace = V4L2_COLORSPACE_DEFAULT; + pixmp_op->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pixmp_op->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pixmp_op->quantization = V4L2_QUANTIZATION_DEFAULT; + + if (video_signal_type_present_flag) { + pixmp_op->quantization = + full_range ? + V4L2_QUANTIZATION_FULL_RANGE : + V4L2_QUANTIZATION_LIM_RANGE; + if (colour_description_present_flag) { + pixmp_op->colorspace = + iris_hfi_get_v4l2_color_primaries(primaries); + pixmp_op->xfer_func = + iris_hfi_get_v4l2_transfer_char(transfer_char); + pixmp_op->ycbcr_enc = + iris_hfi_get_v4l2_matrix_coefficients(matrix_coeff); + } + } + + pixmp_ip->colorspace = pixmp_op->colorspace; + pixmp_ip->xfer_func = pixmp_op->xfer_func; + pixmp_ip->ycbcr_enc = pixmp_op->ycbcr_enc; + pixmp_ip->quantization = pixmp_op->quantization; + + if (event.input_crop.width > 0 && event.input_crop.height > 0) { + inst->crop.left = event.input_crop.left; + inst->crop.top = event.input_crop.top; + inst->crop.width = event.input_crop.width; + inst->crop.height = event.input_crop.height; + } else { + inst->crop.left = 0; + inst->crop.top = 0; + inst->crop.width = event.width; + inst->crop.height = event.height; + } + + inst->fw_min_count = event.buf_count; + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + inst->buffers[BUF_OUTPUT].size = pixmp_op->plane_fmt[0].sizeimage; + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->buffers[BUF_OUTPUT].min_count); + + dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + dst_q->min_reqbufs_allocation = inst->buffers[BUF_OUTPUT].min_count; + + if (event.bit_depth || !event.pic_struct) { + dev_err(core->dev, "unsupported content, bit depth: %x, pic_struct = %x\n", + event.bit_depth, event.pic_struct); + iris_inst_change_state(inst, IRIS_INST_ERROR); + } +} + +static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst, + struct hfi_msg_event_notify_pkt *pkt) +{ + struct hfi_session_flush_pkt flush_pkt; + u32 num_properties_changed; + int ret; + + ret = iris_inst_sub_state_change_drc(inst); + if (ret) + return; + + switch (pkt->event_data1) { + case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES: + case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES: + break; + default: + iris_inst_change_state(inst, IRIS_INST_ERROR); + return; + } + + num_properties_changed = pkt->event_data2; + if (!num_properties_changed) { + iris_inst_change_state(inst, IRIS_INST_ERROR); + return; + } + + iris_hfi_gen1_read_changed_params(inst, pkt); + + if (inst->state != IRIS_INST_ERROR) { + 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 = HFI_FLUSH_OUTPUT; + iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size); + } + + iris_vdec_src_change(inst); + iris_inst_sub_state_change_drc_last(inst); +} static void iris_hfi_gen1_sys_event_notify(struct iris_core *core, void *packet) @@ -66,6 +271,9 @@ static void iris_hfi_gen1_session_event_notify(struct iris_inst *inst, void *pac case HFI_EVENT_SESSION_ERROR: iris_hfi_gen1_event_session_error(inst, pkt); break; + case HFI_EVENT_SESSION_SEQUENCE_CHANGED: + iris_hfi_gen1_event_seq_changed(inst, pkt); + break; default: break; } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 8a9f2b5517ad..42cd57d5e3b1 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -19,8 +19,11 @@ #define HFI_CMD_STOP 0x01000006 #define HFI_CMD_BUFFER 0x01000009 #define HFI_CMD_SUBSCRIBE_MODE 0x0100000B +#define HFI_CMD_SETTINGS_CHANGE 0x0100000C #define HFI_CMD_END 0x01FFFFFF +#define HFI_BITMASK_BITSTREAM_WIDTH 0xffff0000 +#define HFI_BITMASK_BITSTREAM_HEIGHT 0x0000ffff #define HFI_BITMASK_FRAME_MBS_ONLY_FLAG 0x00000001 #define HFI_PROP_BEGIN 0x03000000 @@ -75,6 +78,7 @@ #define HFI_INFO_UNSUPPORTED 0x06000001 #define HFI_INFO_DATA_CORRUPT 0x06000002 #define HFI_INFO_BUFFER_OVERFLOW 0x06000004 +#define HFI_INFO_HFI_FLAG_PSC_LAST 0x06000007 #define HFI_INFORMATION_END 0x06FFFFFF enum hfi_property_mode_type { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index e8d8caeef021..c7552e041138 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -8,6 +8,8 @@ #include "iris_hfi_gen2.h" #include "iris_hfi_gen2_defines.h" #include "iris_hfi_gen2_packet.h" +#include "iris_vdec.h" +#include "iris_vpu_buffer.h" #include "iris_vpu_common.h" struct iris_hfi_gen2_core_hfi_range { @@ -199,6 +201,10 @@ static int iris_hfi_gen2_handle_session_info(struct iris_inst *inst, info = "buffer overflow"; inst_hfi_gen2->hfi_frame_info.overflow = 1; break; + case HFI_INFO_HFI_FLAG_PSC_LAST: + info = "drc last flag"; + ret = iris_inst_sub_state_change_drc_last(inst); + break; default: info = "unknown"; break; @@ -329,6 +335,13 @@ static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst, struct v4l2_m2m_buffer *m2m_buffer, *n; struct iris_buffer *buf; bool found = false; + int ret; + + if (hfi_buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) { + ret = iris_inst_sub_state_change_drc_last(inst); + if (ret) + return ret; + } v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) { buf = to_iris_buffer(&m2m_buffer->vb); @@ -440,6 +453,115 @@ static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst, return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); } +static void iris_hfi_gen2_read_input_subcr_params(struct iris_inst *inst) +{ + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + struct v4l2_pix_format_mplane *pixmp_ip = &inst->fmt_src->fmt.pix_mp; + struct v4l2_pix_format_mplane *pixmp_op = &inst->fmt_dst->fmt.pix_mp; + u32 primaries, matrix_coeff, transfer_char; + struct hfi_subscription_params subsc_params; + u32 colour_description_present_flag; + u32 video_signal_type_present_flag; + struct iris_core *core = inst->core; + u32 full_range, width, height; + struct vb2_queue *dst_q; + struct v4l2_ctrl *ctrl; + + subsc_params = inst_hfi_gen2->src_subcr_params; + width = (subsc_params.bitstream_resolution & + HFI_BITMASK_BITSTREAM_WIDTH) >> 16; + height = subsc_params.bitstream_resolution & + HFI_BITMASK_BITSTREAM_HEIGHT; + + pixmp_ip->width = width; + pixmp_ip->height = height; + + pixmp_op->width = ALIGN(width, 128); + pixmp_op->height = ALIGN(height, 32); + pixmp_op->plane_fmt[0].bytesperline = ALIGN(width, 128); + pixmp_op->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); + + matrix_coeff = subsc_params.color_info & 0xFF; + transfer_char = (subsc_params.color_info & 0xFF00) >> 8; + primaries = (subsc_params.color_info & 0xFF0000) >> 16; + colour_description_present_flag = + (subsc_params.color_info & 0x1000000) >> 24; + full_range = (subsc_params.color_info & 0x2000000) >> 25; + video_signal_type_present_flag = + (subsc_params.color_info & 0x20000000) >> 29; + + pixmp_op->colorspace = V4L2_COLORSPACE_DEFAULT; + pixmp_op->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pixmp_op->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pixmp_op->quantization = V4L2_QUANTIZATION_DEFAULT; + + if (video_signal_type_present_flag) { + pixmp_op->quantization = + full_range ? + V4L2_QUANTIZATION_FULL_RANGE : + V4L2_QUANTIZATION_LIM_RANGE; + if (colour_description_present_flag) { + pixmp_op->colorspace = + iris_hfi_get_v4l2_color_primaries(primaries); + pixmp_op->xfer_func = + iris_hfi_get_v4l2_transfer_char(transfer_char); + pixmp_op->ycbcr_enc = + iris_hfi_get_v4l2_matrix_coefficients(matrix_coeff); + } + } + + pixmp_ip->colorspace = pixmp_op->colorspace; + pixmp_ip->xfer_func = pixmp_op->xfer_func; + pixmp_ip->ycbcr_enc = pixmp_op->ycbcr_enc; + pixmp_ip->quantization = pixmp_op->quantization; + + inst->crop.top = subsc_params.crop_offsets[0] & 0xFFFF; + inst->crop.left = (subsc_params.crop_offsets[0] >> 16) & 0xFFFF; + inst->crop.height = pixmp_ip->height - + (subsc_params.crop_offsets[1] & 0xFFFF) - inst->crop.top; + inst->crop.width = pixmp_ip->width - + ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; + + inst->fw_caps[PROFILE].value = subsc_params.profile; + inst->fw_caps[LEVEL].value = subsc_params.level; + inst->fw_caps[POC].value = subsc_params.pic_order_cnt; + + if (subsc_params.bit_depth != BIT_DEPTH_8 || + !(subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)) { + dev_err(core->dev, "unsupported content, bit depth: %x, pic_struct = %x\n", + subsc_params.bit_depth, subsc_params.coded_frames); + iris_inst_change_state(inst, IRIS_INST_ERROR); + } + + inst->fw_min_count = subsc_params.fw_min_count; + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + inst->buffers[BUF_OUTPUT].size = pixmp_op->plane_fmt[0].sizeimage; + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, inst->buffers[BUF_OUTPUT].min_count); + + dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + dst_q->min_reqbufs_allocation = inst->buffers[BUF_OUTPUT].min_count; +} + +static int iris_hfi_gen2_handle_src_change(struct iris_inst *inst, + struct iris_hfi_packet *pkt) +{ + int ret; + + if (pkt->port != HFI_PORT_BITSTREAM) + return 0; + + ret = iris_inst_sub_state_change_drc(inst); + if (ret) + return ret; + + iris_hfi_gen2_read_input_subcr_params(inst); + iris_vdec_src_change(inst); + + return 0; +} + static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst, struct iris_hfi_packet *pkt) { @@ -455,6 +577,9 @@ static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst, case HFI_CMD_BUFFER: ret = iris_hfi_gen2_handle_session_buffer(inst, pkt); break; + case HFI_CMD_SETTINGS_CHANGE: + ret = iris_hfi_gen2_handle_src_change(inst, pkt); + break; default: break; } @@ -588,16 +713,61 @@ static int iris_hfi_gen2_handle_system_response(struct iris_core *core, return 0; } +static void iris_hfi_gen2_init_src_change_param(struct iris_inst *inst) +{ + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + struct v4l2_pix_format_mplane *pixmp_ip = &inst->fmt_src->fmt.pix_mp; + struct v4l2_pix_format_mplane *pixmp_op = &inst->fmt_dst->fmt.pix_mp; + u32 bottom_offset = (pixmp_ip->height - inst->crop.height); + u32 right_offset = (pixmp_ip->width - inst->crop.width); + struct hfi_subscription_params *subsc_params; + u32 primaries, matrix_coeff, transfer_char; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0; + u32 full_range, video_format = 0; + u32 left_offset = inst->crop.left; + u32 top_offset = inst->crop.top; + + subsc_params = &inst_hfi_gen2->src_subcr_params; + subsc_params->bitstream_resolution = + pixmp_ip->width << 16 | pixmp_ip->height; + subsc_params->crop_offsets[0] = + left_offset << 16 | top_offset; + subsc_params->crop_offsets[1] = + right_offset << 16 | bottom_offset; + subsc_params->fw_min_count = inst->buffers[BUF_OUTPUT].min_count; + + primaries = iris_hfi_gen2_get_color_primaries(pixmp_op->colorspace); + matrix_coeff = iris_hfi_gen2_get_matrix_coefficients(pixmp_op->ycbcr_enc); + transfer_char = iris_hfi_gen2_get_transfer_char(pixmp_op->xfer_func); + full_range = pixmp_op->quantization == V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0; + subsc_params->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); + + subsc_params->profile = inst->fw_caps[PROFILE].value; + subsc_params->level = inst->fw_caps[LEVEL].value; + subsc_params->pic_order_cnt = inst->fw_caps[POC].value; + subsc_params->bit_depth = inst->fw_caps[BIT_DEPTH].value; + if (inst->fw_caps[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + subsc_params->coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG; + else + subsc_params->coded_frames = 0; +} + static int iris_hfi_gen2_handle_session_response(struct iris_core *core, struct iris_hfi_header *hdr) { + u8 *pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); struct iris_inst_hfi_gen2 *inst_hfi_gen2; struct iris_hfi_packet *packet; struct iris_inst *inst; bool dequeue = false; int ret = 0; u32 i, j; - u8 *pkt; static const struct iris_hfi_gen2_inst_hfi_range range[] = { {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, iris_hfi_gen2_handle_session_error}, @@ -617,6 +787,17 @@ static int iris_hfi_gen2_handle_session_response(struct iris_core *core, inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); memset(&inst_hfi_gen2->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info)); + for (i = 0; i < hdr->num_packets; i++) { + packet = (struct iris_hfi_packet *)pkt; + if (packet->type == HFI_CMD_SETTINGS_CHANGE) { + if (packet->port == HFI_PORT_BITSTREAM) { + iris_hfi_gen2_init_src_change_param(inst); + break; + } + } + pkt += packet->size; + } + pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); for (i = 0; i < ARRAY_SIZE(range); i++) { pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index 2886491ad59f..89fb63644311 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -31,6 +31,7 @@ * @buffers: array of different iris buffers * @fw_min_count: minimnum count of buffers needed by fw * @state: instance state + * @sub_state: instance sub state * @once_per_session_set: boolean to set once per session property * @m2m_dev: a reference to m2m device structure * @m2m_ctx: a reference to m2m context structure @@ -57,6 +58,7 @@ struct iris_inst { struct iris_buffers buffers[BUF_TYPE_MAX]; u32 fw_min_count; enum iris_inst_state state; + enum iris_inst_sub_state sub_state; bool once_per_session_set; struct v4l2_m2m_dev *m2m_dev; struct v4l2_m2m_ctx *m2m_ctx; diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c index 44362e8fe18f..aad7e734d5c8 100644 --- a/drivers/media/platform/qcom/iris/iris_state.c +++ b/drivers/media/platform/qcom/iris/iris_state.c @@ -102,3 +102,67 @@ int iris_inst_state_change_streamoff(struct iris_inst *inst, u32 plane) return iris_inst_change_state(inst, new_state); } + +int iris_inst_change_sub_state(struct iris_inst *inst, + enum iris_inst_sub_state clear_sub_state, + enum iris_inst_sub_state set_sub_state) +{ + enum iris_inst_sub_state prev_sub_state; + + if (inst->state == IRIS_INST_ERROR) + return 0; + + if (!clear_sub_state && !set_sub_state) + return 0; + + if ((clear_sub_state & set_sub_state) || + set_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE || + clear_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE) + return -EINVAL; + + prev_sub_state = inst->sub_state; + + inst->sub_state |= set_sub_state; + inst->sub_state &= ~clear_sub_state; + + if (inst->sub_state != prev_sub_state) + dev_dbg(inst->core->dev, "sub_state changed from %x to %x\n", + prev_sub_state, inst->sub_state); + + return 0; +} + +int iris_inst_sub_state_change_drc(struct iris_inst *inst) +{ + enum iris_inst_sub_state set_sub_state = 0; + + if (inst->sub_state & IRIS_INST_SUB_DRC) + return -EINVAL; + + if (inst->state == IRIS_INST_INPUT_STREAMING || + inst->state == IRIS_INST_INIT) + set_sub_state = IRIS_INST_SUB_FIRST_IPSC | IRIS_INST_SUB_INPUT_PAUSE; + else + set_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_INPUT_PAUSE; + + return iris_inst_change_sub_state(inst, 0, set_sub_state); +} + +int iris_inst_sub_state_change_drc_last(struct iris_inst *inst) +{ + enum iris_inst_sub_state set_sub_state; + + if (inst->sub_state & IRIS_INST_SUB_DRC_LAST) + return -EINVAL; + + if (!(inst->sub_state & IRIS_INST_SUB_DRC) || + !(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) + return -EINVAL; + + if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) + return 0; + + set_sub_state = IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_OUTPUT_PAUSE; + + return iris_inst_change_sub_state(inst, 0, set_sub_state); +} diff --git a/drivers/media/platform/qcom/iris/iris_state.h b/drivers/media/platform/qcom/iris/iris_state.h index 0bf9d0e063ac..b5f0826142f0 100644 --- a/drivers/media/platform/qcom/iris/iris_state.h +++ b/drivers/media/platform/qcom/iris/iris_state.h @@ -91,9 +91,42 @@ enum iris_inst_state { IRIS_INST_ERROR, }; +#define IRIS_INST_SUB_STATES 8 +#define IRIS_INST_MAX_SUB_STATE_VALUE ((1 << IRIS_INST_SUB_STATES) - 1) + +/** + * enum iris_inst_sub_state + * + * @IRIS_INST_SUB_FIRST_IPSC: indicates source change is received from firmware + * when output port is not yet streaming. + * @IRIS_INST_SUB_DRC: indicates source change is received from firmware + * when output port is streaming and source change event is + * sent to client. + * @IRIS_INST_SUB_DRC_LAST: indicates last buffer is received from firmware + * as part of source change. + * @IRIS_INST_SUB_INPUT_PAUSE: source change is received form firmware. This + * indicates that firmware is paused to process + * any further input frames. + * @IRIS_INST_SUB_OUTPUT_PAUSE: last buffer is received form firmware as part + * of drc sequence. This indicates that + * firmware is paused to process any further output frames. + */ +enum iris_inst_sub_state { + IRIS_INST_SUB_FIRST_IPSC = BIT(0), + IRIS_INST_SUB_DRC = BIT(1), + IRIS_INST_SUB_DRC_LAST = BIT(2), + IRIS_INST_SUB_INPUT_PAUSE = BIT(3), + IRIS_INST_SUB_OUTPUT_PAUSE = BIT(4), +}; + int iris_inst_change_state(struct iris_inst *inst, enum iris_inst_state request_state); +int iris_inst_change_sub_state(struct iris_inst *inst, + enum iris_inst_sub_state clear_sub_state, + enum iris_inst_sub_state set_sub_state); int iris_inst_state_change_streamon(struct iris_inst *inst, u32 plane); int iris_inst_state_change_streamoff(struct iris_inst *inst, u32 plane); +int iris_inst_sub_state_change_drc(struct iris_inst *inst); +int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index 770e51f9ef91..3b94011533e8 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -4,6 +4,7 @@ */ #include <media/videobuf2-dma-contig.h> +#include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> #include "iris_instance.h" @@ -180,6 +181,7 @@ int iris_vb2_buf_out_validate(struct vb2_buffer *vb) void iris_vb2_buf_queue(struct vb2_buffer *vb2) { + static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS }; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); struct v4l2_m2m_ctx *m2m_ctx; struct iris_inst *inst; @@ -203,6 +205,22 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) goto exit; } + if (V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) { + if (inst->sub_state & IRIS_INST_SUB_DRC && + inst->sub_state & IRIS_INST_SUB_DRC_LAST) { + vbuf->flags |= V4L2_BUF_FLAG_LAST; + vbuf->sequence = inst->sequence_cap++; + vbuf->field = V4L2_FIELD_NONE; + vb2_set_plane_payload(vb2, 0, 0); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + if (!v4l2_m2m_has_stopped(m2m_ctx)) { + v4l2_event_queue_fh(&inst->fh, &eos); + v4l2_m2m_mark_stopped(m2m_ctx); + } + goto exit; + } + } + v4l2_m2m_buf_queue(m2m_ctx, vbuf); ret = iris_vdec_qbuf(inst, vbuf); diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index d6b092314b34..1da277ed6cb3 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -223,6 +223,21 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su return ret; } +void iris_vdec_src_change(struct iris_inst *inst) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct v4l2_event event = {0}; + struct vb2_queue *src_q; + + src_q = v4l2_m2m_get_src_vq(m2m_ctx); + if (!vb2_is_streaming(src_q)) + return; + + event.type = V4L2_EVENT_SOURCE_CHANGE; + event.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION; + v4l2_event_queue_fh(&inst->fh, &event); +} + static int iris_vdec_get_num_queued_buffers(struct iris_inst *inst, enum iris_buffer_type type) { diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h index 998d4970a42b..dfcc2089a1ef 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.h +++ b/drivers/media/platform/qcom/iris/iris_vdec.h @@ -14,6 +14,7 @@ int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); +void iris_vdec_src_change(struct iris_inst *inst); int iris_vdec_streamon_input(struct iris_inst *inst); int iris_vdec_streamon_output(struct iris_inst *inst); int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); -- 2.34.1