On 20/11/2024 15:46, Dikshita Agarwal wrote: > Handle the response sent by firmware, when source change is detected by > firmware. Read the parameter subscribed to firmware for source change to > detect the parameter with changed value. Raise the source change event > to 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 client. > > Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx> Reviewed-by: Hans Verkuil <hverkuil@xxxxxxxxx> Regards, Hans > --- > 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 | 19 ++ > drivers/media/platform/qcom/iris/iris_vdec.c | 15 ++ > drivers/media/platform/qcom/iris/iris_vdec.h | 1 + > 12 files changed, 677 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 69273885be21..32fcd9112a7e 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 > @@ -74,6 +77,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 77c4f92b76e1..28857a7a5112 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; > @@ -326,6 +332,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); > @@ -437,6 +450,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) > { > @@ -452,6 +574,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; > } > @@ -585,16 +710,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}, > @@ -614,6 +784,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 6d6fe9e2e8c0..4a747c6cf809 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 > @@ -58,6 +59,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 8a25c0c27df4..11236001c1cc 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..1ff2017673ed 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,23 @@ 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) && > + inst->subscriptions & V4L2_EVENT_EOS) { > + 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 4c99847cec6e..2f68133b4d03 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.c > +++ b/drivers/media/platform/qcom/iris/iris_vdec.c > @@ -226,6 +226,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); >