On Fri Feb 7 13:25:01 2025 +0530, Dikshita Agarwal wrote:
> 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 <hverk...@xs4all.nl>
> Tested-by: Stefan Schmidt <stefan.schm...@linaro.org> # x1e80100 (Dell XPS 13 
> 9345)
> Reviewed-by: Stefan Schmidt <stefan.schm...@linaro.org>
> Tested-by: Neil Armstrong <neil.armstr...@linaro.org> # on SM8550-QRD
> Tested-by: Neil Armstrong <neil.armstr...@linaro.org> # on SM8550-HDK
> Signed-off-by: Dikshita Agarwal <quic_diksh...@quicinc.com>
> Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>

Patch committed.

Thanks,
Hans Verkuil

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

Reply via email to