[PATCH v2 25/34] media: iris: subscribe src change and handle firmware responses

From: Dikshita Agarwal
Date: Mon Dec 18 2023 - 06:49:21 EST


From: Vikash Garodia <quic_vgarodia@xxxxxxxxxxx>

Driver can subscribe to different bitstream parameters
for which it expects a response from firmware.
These are vital bitstream parameters which requires
reconfiguration of buffers or sending updated info
to client. Incase of any change in these subscribed
parameters, firmware sends a response, which is then
sent to client as source change event.

HFI_CMD_SUBSCRIBE_MODE with HFI_MODE_PORT_SETTINGS_CHANGE
- to subscribe for different bitstream parameters.

Below properties are set to firmware as part of this:
HFI_PROP_BITSTREAM_RESOLUTION
HFI_PROP_CROP_OFFSETS
HFI_PROP_LUMA_CHROMA_BIT_DEPTH
HFI_PROP_CODED_FRAMES
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT
HFI_PROP_PIC_ORDER_CNT_TYPE
HFI_PROP_SIGNAL_COLOR_INFO
HFI_PROP_PROFILE
HFI_PROP_LEVEL
HFI_PROP_TIER

Add the handling of different responses
from firmware. Below are different types of responses:

System responses:
- System error - response in case of system error occurred.
- System property - response for system level property - sys image version.
- System init - response for video core init completion.

Session responses:
- Session error - response in case of any session level error.
- Session property - response for all session properties.
HFI_PROP_BITSTREAM_RESOLUTION
HFI_PROP_CROP_OFFSETS
HFI_PROP_LUMA_CHROMA_BIT_DEPTH
HFI_PROP_CODED_FRAMES
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT
HFI_PROP_PIC_ORDER_CNT_TYPE
HFI_PROP_SIGNAL_COLOR_INFO
HFI_PROP_PROFILE
HFI_PROP_LEVEL
HFI_PROP_TIER

- Session command - response for session level commands.
HFI_CMD_OPEN - response for open competition.
HFI_CMD_CLOSE - response for open competition.
HFI_CMD_SETTINGS_CHANGE - response for change in subscribe parameters.
HFI_CMD_SUBSCRIBE_MODE - response for info on subscribed properties.

Signed-off-by: Vikash Garodia <quic_vgarodia@xxxxxxxxxxx>
Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx>
---
.../media/platform/qcom/vcodec/iris/hfi_defines.h | 114 +++-
.../media/platform/qcom/vcodec/iris/iris_common.h | 25 +-
.../media/platform/qcom/vcodec/iris/iris_core.h | 2 +
.../media/platform/qcom/vcodec/iris/iris_helpers.c | 29 +-
.../media/platform/qcom/vcodec/iris/iris_helpers.h | 4 +
.../platform/qcom/vcodec/iris/iris_hfi_packet.c | 195 +++++++
.../platform/qcom/vcodec/iris/iris_hfi_packet.h | 11 +-
.../platform/qcom/vcodec/iris/iris_hfi_response.c | 364 ++++++++++++-
.../platform/qcom/vcodec/iris/iris_instance.h | 8 +
.../media/platform/qcom/vcodec/iris/iris_vdec.c | 580 +++++++++++++++++++++
.../media/platform/qcom/vcodec/iris/iris_vdec.h | 4 +
.../platform/qcom/vcodec/iris/platform_common.h | 6 +
.../platform/qcom/vcodec/iris/platform_sm8550.c | 44 ++
13 files changed, 1375 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
index a6078a5..0ef6bad 100644
--- a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
+++ b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
@@ -10,6 +10,7 @@

#define HFI_VIDEO_ARCH_LX 0x1

+#define HFI_CMD_BEGIN 0x01000000
#define HFI_CMD_INIT 0x01000001
#define HFI_CMD_OPEN 0x01000003
#define HFI_CMD_CLOSE 0x01000004
@@ -31,7 +32,18 @@ enum hfi_property_mode_type {
HFI_MODE_PROPERTY = 0x00000002,
};

-#define HFI_CMD_SUBSCRIBE_MODE 0x0100000B
+#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
+
+#define HFI_PROP_IMAGE_VERSION 0x03000001

enum hfi_color_format {
HFI_COLOR_FMT_OPAQUE = 0,
@@ -46,8 +58,12 @@ enum hfi_color_format {

#define HFI_PROP_COLOR_FORMAT 0x03000101

+#define HFI_PROP_BITSTREAM_RESOLUTION 0x03000103
+
#define HFI_PROP_LINEAR_STRIDE_SCANLINE 0x03000104

+#define HFI_PROP_CROP_OFFSETS 0x03000105
+
#define HFI_PROP_PROFILE 0x03000107

#define HFI_PROP_LEVEL 0x03000108
@@ -68,13 +84,83 @@ enum hfi_color_format {

#define HFI_PROP_BUFFER_HOST_MAX_COUNT 0x03000123

+#define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT 0x03000124
+
#define HFI_PROP_PIC_ORDER_CNT_TYPE 0x03000128

+#define HFI_PROP_QUALITY_MODE 0x03000148
+
+enum hfi_color_primaries {
+ HFI_PRIMARIES_RESERVED = 0,
+ HFI_PRIMARIES_BT709 = 1,
+ HFI_PRIMARIES_UNSPECIFIED = 2,
+ HFI_PRIMARIES_BT470_SYSTEM_M = 4,
+ HFI_PRIMARIES_BT470_SYSTEM_BG = 5,
+ HFI_PRIMARIES_BT601_525 = 6,
+ HFI_PRIMARIES_SMPTE_ST240M = 7,
+ HFI_PRIMARIES_GENERIC_FILM = 8,
+ HFI_PRIMARIES_BT2020 = 9,
+ HFI_PRIMARIES_SMPTE_ST428_1 = 10,
+ HFI_PRIMARIES_SMPTE_RP431_2 = 11,
+ HFI_PRIMARIES_SMPTE_EG431_1 = 12,
+ HFI_PRIMARIES_SMPTE_EBU_TECH = 22,
+};
+
+enum hfi_transfer_characteristics {
+ HFI_TRANSFER_RESERVED = 0,
+ HFI_TRANSFER_BT709 = 1,
+ HFI_TRANSFER_UNSPECIFIED = 2,
+ HFI_TRANSFER_BT470_SYSTEM_M = 4,
+ HFI_TRANSFER_BT470_SYSTEM_BG = 5,
+ HFI_TRANSFER_BT601_525_OR_625 = 6,
+ HFI_TRANSFER_SMPTE_ST240M = 7,
+ HFI_TRANSFER_LINEAR = 8,
+ HFI_TRANSFER_LOG_100_1 = 9,
+ HFI_TRANSFER_LOG_SQRT = 10,
+ HFI_TRANSFER_XVYCC = 11,
+ HFI_TRANSFER_BT1361_0 = 12,
+ HFI_TRANSFER_SRGB_SYCC = 13,
+ HFI_TRANSFER_BT2020_14 = 14,
+ HFI_TRANSFER_BT2020_15 = 15,
+ HFI_TRANSFER_SMPTE_ST2084_PQ = 16,
+ HFI_TRANSFER_SMPTE_ST428_1 = 17,
+ HFI_TRANSFER_BT2100_2_HLG = 18,
+};
+
+enum hfi_matrix_coefficients {
+ HFI_MATRIX_COEFF_SRGB_SMPTE_ST428_1 = 0,
+ HFI_MATRIX_COEFF_BT709 = 1,
+ HFI_MATRIX_COEFF_UNSPECIFIED = 2,
+ HFI_MATRIX_COEFF_RESERVED = 3,
+ HFI_MATRIX_COEFF_FCC_TITLE_47 = 4,
+ HFI_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625 = 5,
+ HFI_MATRIX_COEFF_BT601_525_BT1358_525_OR_625 = 6,
+ HFI_MATRIX_COEFF_SMPTE_ST240 = 7,
+ HFI_MATRIX_COEFF_YCGCO = 8,
+ HFI_MATRIX_COEFF_BT2020_NON_CONSTANT = 9,
+ HFI_MATRIX_COEFF_BT2020_CONSTANT = 10,
+ HFI_MATRIX_COEFF_SMPTE_ST2085 = 11,
+ HFI_MATRIX_COEFF_SMPTE_CHROM_DERV_NON_CONSTANT = 12,
+ HFI_MATRIX_COEFF_SMPTE_CHROM_DERV_CONSTANT = 13,
+ HFI_MATRIX_COEFF_BT2100 = 14,
+};
+
+#define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155
+
#define HFI_PROP_DECODE_ORDER_OUTPUT 0x0300015b

+enum hfi_picture_type {
+ HFI_PICTURE_IDR = 0x00000001,
+ HFI_PICTURE_P = 0x00000002,
+ HFI_PICTURE_B = 0x00000004,
+ HFI_PICTURE_I = 0x00000008,
+ HFI_PICTURE_CRA = 0x00000010,
+ HFI_PICTURE_BLA = 0x00000020,
+};
+
#define HFI_PROP_PICTURE_TYPE 0x03000162

-#define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168
+#define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168

#define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169

@@ -86,7 +172,29 @@ enum hfi_color_format {

#define HFI_PROP_COMV_BUFFER_COUNT 0x03000193

-#define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001
+#define HFI_PROP_END 0x03FFFFFF
+
+#define HFI_SESSION_ERROR_BEGIN 0x04000000
+
+#define HFI_ERROR_UNKNOWN_SESSION 0x04000001
+
+#define HFI_ERROR_MAX_SESSIONS 0x04000002
+
+#define HFI_ERROR_FATAL 0x04000003
+
+#define HFI_ERROR_INVALID_STATE 0x04000004
+
+#define HFI_ERROR_INSUFFICIENT_RESOURCES 0x04000005
+
+#define HFI_ERROR_BUFFER_NOT_SET 0x04000006
+
+#define HFI_SESSION_ERROR_END 0x04FFFFFF
+
+#define HFI_SYSTEM_ERROR_BEGIN 0x05000000
+
+#define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001
+
+#define HFI_SYSTEM_ERROR_END 0x05FFFFFF

struct hfi_debug_header {
u32 size;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_common.h b/drivers/media/platform/qcom/vcodec/iris/iris_common.h
index 6b771f8..0fbd139 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_common.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_common.h
@@ -8,7 +8,6 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>

#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
@@ -16,6 +15,7 @@
#define DEFAULT_WIDTH 320
#define DEFAULT_HEIGHT 240
#define DEFAULT_BSE_VPP_DELAY 2
+#define IRIS_VERSION_LENGTH 128

#define MAX_EVENTS 30

@@ -23,6 +23,9 @@

#define NUM_MBS_4k (((4096 + 15) >> 4) * ((2304 + 15) >> 4))

+#define MAX_DPB_LIST_ARRAY_SIZE (16 * 4)
+#define MAX_DPB_LIST_PAYLOAD_SIZE (16 * 4 * 4)
+
enum codec_type {
H264 = BIT(0),
HEVC = BIT(1),
@@ -95,4 +98,24 @@ struct iris_buffer {
struct dma_buf_attachment *attach;
};

+struct subscription_params {
+ u32 bitstream_resolution;
+ u32 crop_offsets[2];
+ u32 bit_depth;
+ u32 coded_frames;
+ u32 fw_min_count;
+ u32 pic_order_cnt;
+ u32 color_info;
+ u32 profile;
+ u32 level;
+ u32 tier;
+};
+
+struct iris_hfi_frame_info {
+ u32 picture_type;
+ u32 no_output;
+ u32 data_corrupt;
+ u32 overflow;
+};
+
#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index 154991c..6452ea7 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -57,6 +57,7 @@
* @inst_caps: a pointer to supported instance capabilities
* @instances: a list_head of all instances
* @intr_status: interrupt status
+ * @fw_version: firmware version
*/

struct iris_core {
@@ -99,6 +100,7 @@ struct iris_core {
struct plat_inst_caps *inst_caps;
struct list_head instances;
u32 intr_status;
+ char fw_version[IRIS_VERSION_LENGTH];
};

int iris_core_init(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
index ff44cda..4cad673 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c
@@ -3,6 +3,8 @@
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/

+#include "hfi_defines.h"
+#include "iris_core.h"
#include "iris_helpers.h"
#include "iris_hfi.h"
#include "iris_hfi_packet.h"
@@ -66,7 +68,7 @@ int get_mbpf(struct iris_inst *inst)
return NUM_MBS_PER_FRAME(height, width);
}

-bool is_linear_colorformat(u32 colorformat)
+inline bool is_linear_colorformat(u32 colorformat)
{
return colorformat == V4L2_PIX_FMT_NV12 || colorformat == V4L2_PIX_FMT_NV21;
}
@@ -350,3 +352,28 @@ int check_session_supported(struct iris_inst *inst)

return ret;
}
+
+int signal_session_msg_receipt(struct iris_inst *inst,
+ enum signal_session_response cmd)
+{
+ if (cmd < MAX_SIGNAL)
+ complete(&inst->completions[cmd]);
+
+ return 0;
+}
+
+struct iris_inst *to_instance(struct iris_core *core, u32 session_id)
+{
+ struct iris_inst *inst = NULL;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->session_id == session_id) {
+ mutex_unlock(&core->lock);
+ return inst;
+ }
+ }
+ mutex_unlock(&core->lock);
+
+ return NULL;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
index fe85d23..cb22adf 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h
@@ -31,6 +31,10 @@ bool is_linear_colorformat(u32 colorformat);
bool is_10bit_colorformat(enum colorformat_type colorformat);
bool is_8bit_colorformat(enum colorformat_type colorformat);
bool is_split_mode_enabled(struct iris_inst *inst);
+int signal_session_msg_receipt(struct iris_inst *inst,
+ enum signal_session_response cmd);
+struct iris_inst *to_instance(struct iris_core *core, u32 session_id);
+
u32 v4l2_codec_from_driver(struct iris_inst *inst, enum codec_type codec);
enum codec_type v4l2_codec_to_driver(struct iris_inst *inst, u32 v4l2_codec);
u32 v4l2_colorformat_from_driver(struct iris_inst *inst, enum colorformat_type colorformat);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
index d4cdfcf..dc7157d 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
@@ -100,6 +100,201 @@ u32 get_hfi_colorformat(u32 colorformat)
return hfi_colorformat;
}

+u32 get_hfi_color_primaries(u32 primaries)
+{
+ u32 hfi_primaries = HFI_PRIMARIES_RESERVED;
+
+ switch (primaries) {
+ case V4L2_COLORSPACE_DEFAULT:
+ hfi_primaries = HFI_PRIMARIES_RESERVED;
+ break;
+ case V4L2_COLORSPACE_REC709:
+ hfi_primaries = HFI_PRIMARIES_BT709;
+ break;
+ case V4L2_COLORSPACE_470_SYSTEM_M:
+ hfi_primaries = HFI_PRIMARIES_BT470_SYSTEM_M;
+ break;
+ case V4L2_COLORSPACE_470_SYSTEM_BG:
+ hfi_primaries = HFI_PRIMARIES_BT470_SYSTEM_BG;
+ break;
+ case V4L2_COLORSPACE_SMPTE170M:
+ hfi_primaries = HFI_PRIMARIES_BT601_525;
+ break;
+ case V4L2_COLORSPACE_SMPTE240M:
+ hfi_primaries = HFI_PRIMARIES_SMPTE_ST240M;
+ break;
+ case V4L2_COLORSPACE_BT2020:
+ hfi_primaries = HFI_PRIMARIES_BT2020;
+ break;
+ case V4L2_COLORSPACE_DCI_P3:
+ hfi_primaries = HFI_PRIMARIES_SMPTE_RP431_2;
+ break;
+ default:
+ break;
+ }
+
+ return hfi_primaries;
+}
+
+u32 get_hfi_transfer_char(u32 characterstics)
+{
+ u32 hfi_characterstics = HFI_TRANSFER_RESERVED;
+
+ switch (characterstics) {
+ case V4L2_XFER_FUNC_DEFAULT:
+ hfi_characterstics = HFI_TRANSFER_RESERVED;
+ break;
+ case V4L2_XFER_FUNC_709:
+ hfi_characterstics = HFI_TRANSFER_BT709;
+ break;
+ case V4L2_XFER_FUNC_SMPTE240M:
+ hfi_characterstics = HFI_TRANSFER_SMPTE_ST240M;
+ break;
+ case V4L2_XFER_FUNC_SRGB:
+ hfi_characterstics = HFI_TRANSFER_SRGB_SYCC;
+ break;
+ case V4L2_XFER_FUNC_SMPTE2084:
+ hfi_characterstics = HFI_TRANSFER_SMPTE_ST2084_PQ;
+ break;
+ default:
+ break;
+ }
+
+ return hfi_characterstics;
+}
+
+u32 get_hfi_matrix_coefficients(u32 coefficients)
+{
+ u32 hfi_coefficients = HFI_MATRIX_COEFF_RESERVED;
+
+ switch (coefficients) {
+ case V4L2_YCBCR_ENC_DEFAULT:
+ hfi_coefficients = HFI_MATRIX_COEFF_RESERVED;
+ break;
+ case V4L2_YCBCR_ENC_709:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT709;
+ break;
+ case V4L2_YCBCR_ENC_XV709:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT709;
+ break;
+ case V4L2_YCBCR_ENC_XV601:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625;
+ break;
+ case V4L2_YCBCR_ENC_601:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT601_525_BT1358_525_OR_625;
+ break;
+ case V4L2_YCBCR_ENC_SMPTE240M:
+ hfi_coefficients = HFI_MATRIX_COEFF_SMPTE_ST240;
+ break;
+ case V4L2_YCBCR_ENC_BT2020:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT2020_NON_CONSTANT;
+ break;
+ case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+ hfi_coefficients = HFI_MATRIX_COEFF_BT2020_CONSTANT;
+ break;
+ default:
+ break;
+ }
+
+ return hfi_coefficients;
+}
+
+u32 get_v4l2_color_primaries(u32 hfi_primaries)
+{
+ u32 primaries = V4L2_COLORSPACE_DEFAULT;
+
+ switch (hfi_primaries) {
+ case HFI_PRIMARIES_RESERVED:
+ primaries = V4L2_COLORSPACE_DEFAULT;
+ break;
+ case HFI_PRIMARIES_BT709:
+ primaries = V4L2_COLORSPACE_REC709;
+ break;
+ case HFI_PRIMARIES_BT470_SYSTEM_M:
+ primaries = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ case HFI_PRIMARIES_BT470_SYSTEM_BG:
+ primaries = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ case HFI_PRIMARIES_BT601_525:
+ primaries = V4L2_COLORSPACE_SMPTE170M;
+ break;
+ case HFI_PRIMARIES_SMPTE_ST240M:
+ primaries = V4L2_COLORSPACE_SMPTE240M;
+ break;
+ case HFI_PRIMARIES_BT2020:
+ primaries = V4L2_COLORSPACE_BT2020;
+ break;
+ case V4L2_COLORSPACE_DCI_P3:
+ primaries = HFI_PRIMARIES_SMPTE_RP431_2;
+ break;
+ default:
+ break;
+ }
+
+ return primaries;
+}
+
+u32 get_v4l2_transfer_char(u32 hfi_characterstics)
+{
+ u32 characterstics = V4L2_XFER_FUNC_DEFAULT;
+
+ switch (hfi_characterstics) {
+ case HFI_TRANSFER_RESERVED:
+ characterstics = V4L2_XFER_FUNC_DEFAULT;
+ break;
+ case HFI_TRANSFER_BT709:
+ characterstics = V4L2_XFER_FUNC_709;
+ break;
+ case HFI_TRANSFER_SMPTE_ST240M:
+ characterstics = V4L2_XFER_FUNC_SMPTE240M;
+ break;
+ case HFI_TRANSFER_SRGB_SYCC:
+ characterstics = V4L2_XFER_FUNC_SRGB;
+ break;
+ case HFI_TRANSFER_SMPTE_ST2084_PQ:
+ characterstics = V4L2_XFER_FUNC_SMPTE2084;
+ break;
+ default:
+ break;
+ }
+
+ return characterstics;
+}
+
+u32 get_v4l2_matrix_coefficients(u32 hfi_coefficients)
+{
+ u32 coefficients = V4L2_YCBCR_ENC_DEFAULT;
+
+ switch (hfi_coefficients) {
+ case HFI_MATRIX_COEFF_RESERVED:
+ coefficients = V4L2_YCBCR_ENC_DEFAULT;
+ break;
+ case HFI_MATRIX_COEFF_BT709:
+ coefficients = V4L2_YCBCR_ENC_709;
+ break;
+ case HFI_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625:
+ coefficients = V4L2_YCBCR_ENC_XV601;
+ break;
+ case HFI_MATRIX_COEFF_BT601_525_BT1358_525_OR_625:
+ coefficients = V4L2_YCBCR_ENC_601;
+ break;
+ case HFI_MATRIX_COEFF_SMPTE_ST240:
+ coefficients = V4L2_YCBCR_ENC_SMPTE240M;
+ break;
+ case HFI_MATRIX_COEFF_BT2020_NON_CONSTANT:
+ coefficients = V4L2_YCBCR_ENC_BT2020;
+ break;
+ case HFI_MATRIX_COEFF_BT2020_CONSTANT:
+ coefficients = V4L2_YCBCR_ENC_BT2020_CONST_LUM;
+ break;
+ default:
+ break;
+ }
+
+ return coefficients;
+}
+
int get_hfi_buffer(struct iris_buffer *buffer, struct hfi_buffer *buf)
{
memset(buf, 0, sizeof(*buf));
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
index 4276d6d..f813116 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
@@ -80,10 +80,17 @@ enum hfi_packet_port_type {
};

u32 get_hfi_port_from_buffer_type(enum iris_buffer_type buffer_type);
-int get_hfi_buffer(struct iris_buffer *buffer, struct hfi_buffer *buf);
-u32 get_hfi_colorformat(u32 colorformat);
u32 get_hfi_port(u32 plane);

+u32 get_hfi_colorformat(u32 colorformat);
+u32 get_hfi_color_primaries(u32 primaries);
+u32 get_hfi_transfer_char(u32 characterstics);
+u32 get_hfi_matrix_coefficients(u32 coefficients);
+u32 get_v4l2_color_primaries(u32 hfi_primaries);
+u32 get_v4l2_transfer_char(u32 hfi_characterstics);
+u32 get_v4l2_matrix_coefficients(u32 hfi_coefficients);
+int get_hfi_buffer(struct iris_buffer *buffer, struct hfi_buffer *buf);
+
int hfi_packet_sys_init(struct iris_core *core,
u8 *pkt, u32 pkt_size);
int hfi_packet_image_version(struct iris_core *core,
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
index 829f3f6..4ca9314 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
@@ -4,8 +4,27 @@
*/

#include "hfi_defines.h"
+#include "iris_helpers.h"
#include "iris_hfi_packet.h"
#include "iris_hfi_response.h"
+#include "iris_vdec.h"
+
+struct iris_core_hfi_range {
+ u32 begin;
+ u32 end;
+ int (*handle)(struct iris_core *core, struct hfi_packet *pkt);
+};
+
+struct iris_inst_hfi_range {
+ u32 begin;
+ u32 end;
+ int (*handle)(struct iris_inst *inst, struct hfi_packet *pkt);
+};
+
+struct iris_hfi_packet_handle {
+ enum hfi_buffer_type type;
+ int (*handle)(struct iris_inst *inst, struct hfi_packet *pkt);
+};

static void print_sfr_message(struct iris_core *core)
{
@@ -25,8 +44,7 @@ static void print_sfr_message(struct iris_core *core)
}
}

-static int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
- u32 core_resp_pkt_size)
+static int validate_packet(u8 *response_pkt, u8 *core_resp_pkt, u32 core_resp_pkt_size)
{
u32 response_pkt_size = 0;
u8 *response_limit;
@@ -52,8 +70,7 @@ static int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
return 0;
}

-static int validate_hdr_packet(struct iris_core *core,
- struct hfi_header *hdr)
+static int validate_hdr_packet(struct iris_core *core, struct hfi_header *hdr)
{
struct hfi_packet *packet;
int i, ret = 0;
@@ -76,6 +93,45 @@ static int validate_hdr_packet(struct iris_core *core,
return ret;
}

+static int handle_session_error(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ struct iris_core *core;
+ char *error;
+
+ core = inst->core;
+
+ switch (pkt->type) {
+ case HFI_ERROR_MAX_SESSIONS:
+ error = "exceeded max sessions";
+ break;
+ case HFI_ERROR_UNKNOWN_SESSION:
+ error = "unknown session id";
+ break;
+ case HFI_ERROR_INVALID_STATE:
+ error = "invalid operation for current state";
+ break;
+ case HFI_ERROR_INSUFFICIENT_RESOURCES:
+ error = "insufficient resources";
+ break;
+ case HFI_ERROR_BUFFER_NOT_SET:
+ error = "internal buffers not set";
+ break;
+ case HFI_ERROR_FATAL:
+ error = "fatal error";
+ break;
+ default:
+ error = "unknown";
+ break;
+ }
+
+ dev_err(core->dev, "session error received %#x: %s\n",
+ pkt->type, error);
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+
+ return 0;
+}
+
static int handle_system_error(struct iris_core *core,
struct hfi_packet *pkt)
{
@@ -86,6 +142,301 @@ static int handle_system_error(struct iris_core *core,
return 0;
}

+static int handle_system_init(struct iris_core *core,
+ struct hfi_packet *pkt)
+{
+ if (!(pkt->flags & HFI_FW_FLAGS_SUCCESS))
+ return 0;
+
+ mutex_lock(&core->lock);
+ if (pkt->packet_id != core->sys_init_id)
+ goto unlock;
+
+ iris_change_core_state(core, IRIS_CORE_INIT);
+
+unlock:
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static int handle_session_close(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ signal_session_msg_receipt(inst, SIGNAL_CMD_CLOSE);
+
+ return 0;
+}
+
+static int handle_src_change(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ int ret = 0;
+
+ if (pkt->port == HFI_PORT_BITSTREAM)
+ ret = vdec_src_change(inst);
+ else if (pkt->port == HFI_PORT_RAW)
+ ret = 0;
+
+ if (ret)
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+
+ return ret;
+}
+
+static int handle_session_command(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ int i, ret = 0;
+ static const struct iris_hfi_packet_handle hfi_pkt_handle[] = {
+ {HFI_CMD_OPEN, NULL },
+ {HFI_CMD_CLOSE, handle_session_close },
+ {HFI_CMD_SETTINGS_CHANGE, handle_src_change },
+ {HFI_CMD_SUBSCRIBE_MODE, NULL },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(hfi_pkt_handle); i++) {
+ if (hfi_pkt_handle[i].type == pkt->type) {
+ if (hfi_pkt_handle[i].handle) {
+ ret = hfi_pkt_handle[i].handle(inst, pkt);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(hfi_pkt_handle))
+ return -EINVAL;
+
+ return ret;
+}
+
+static int handle_dpb_list_property(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ u8 *payload_start;
+ u32 payload_size;
+
+ payload_size = pkt->size - sizeof(*pkt);
+ payload_start = (u8 *)((u8 *)pkt + sizeof(*pkt));
+ memset(inst->dpb_list_payload, 0, MAX_DPB_LIST_ARRAY_SIZE);
+
+ if (payload_size > MAX_DPB_LIST_PAYLOAD_SIZE) {
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ return -EINVAL;
+ }
+
+ memcpy(inst->dpb_list_payload, payload_start, payload_size);
+
+ return 0;
+}
+
+static int handle_session_property(struct iris_inst *inst,
+ struct hfi_packet *pkt)
+{
+ u32 *payload_ptr = NULL;
+ int ret = 0;
+
+ if (pkt->port != HFI_PORT_BITSTREAM)
+ return 0;
+
+ if (pkt->flags & HFI_FW_FLAGS_INFORMATION)
+ return 0;
+
+ payload_ptr = (u32 *)((u8 *)pkt + sizeof(*pkt));
+ if (!payload_ptr)
+ return -EINVAL;
+
+ switch (pkt->type) {
+ case HFI_PROP_BITSTREAM_RESOLUTION:
+ inst->src_subcr_params.bitstream_resolution = payload_ptr[0];
+ break;
+ case HFI_PROP_CROP_OFFSETS:
+ inst->src_subcr_params.crop_offsets[0] = payload_ptr[0];
+ inst->src_subcr_params.crop_offsets[1] = payload_ptr[1];
+ break;
+ case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
+ inst->src_subcr_params.bit_depth = payload_ptr[0];
+ break;
+ case HFI_PROP_CODED_FRAMES:
+ inst->src_subcr_params.coded_frames = payload_ptr[0];
+ break;
+ case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
+ inst->src_subcr_params.fw_min_count = payload_ptr[0];
+ break;
+ case HFI_PROP_PIC_ORDER_CNT_TYPE:
+ inst->src_subcr_params.pic_order_cnt = payload_ptr[0];
+ break;
+ case HFI_PROP_SIGNAL_COLOR_INFO:
+ inst->src_subcr_params.color_info = payload_ptr[0];
+ break;
+ case HFI_PROP_PROFILE:
+ inst->src_subcr_params.profile = payload_ptr[0];
+ break;
+ case HFI_PROP_LEVEL:
+ inst->src_subcr_params.level = payload_ptr[0];
+ break;
+ case HFI_PROP_TIER:
+ inst->src_subcr_params.tier = payload_ptr[0];
+ break;
+ case HFI_PROP_PICTURE_TYPE:
+ inst->hfi_frame_info.picture_type = payload_ptr[0];
+ break;
+ case HFI_PROP_DPB_LIST:
+ ret = handle_dpb_list_property(inst, pkt);
+ if (ret)
+ break;
+ break;
+ case HFI_PROP_NO_OUTPUT:
+ inst->hfi_frame_info.no_output = 1;
+ break;
+ case HFI_PROP_QUALITY_MODE:
+ case HFI_PROP_STAGE:
+ case HFI_PROP_PIPE:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int handle_image_version_property(struct iris_core *core,
+ struct hfi_packet *pkt)
+{
+ u8 *str_image_version;
+ u32 req_bytes;
+ u32 i = 0;
+
+ req_bytes = pkt->size - sizeof(*pkt);
+ if (req_bytes < IRIS_VERSION_LENGTH - 1)
+ return -EINVAL;
+
+ str_image_version = (u8 *)pkt + sizeof(*pkt);
+
+ for (i = 0; i < IRIS_VERSION_LENGTH - 1; i++) {
+ if (str_image_version[i] != '\0')
+ core->fw_version[i] = str_image_version[i];
+ else
+ core->fw_version[i] = ' ';
+ }
+ core->fw_version[i] = '\0';
+
+ return 0;
+}
+
+static int handle_system_property(struct iris_core *core,
+ struct hfi_packet *pkt)
+{
+ int ret = 0;
+
+ switch (pkt->type) {
+ case HFI_PROP_IMAGE_VERSION:
+ ret = handle_image_version_property(core, pkt);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int handle_system_response(struct iris_core *core,
+ struct hfi_header *hdr)
+{
+ struct hfi_packet *packet;
+ u8 *pkt, *start_pkt;
+ int ret = 0;
+ int i, j;
+ static const struct iris_core_hfi_range be[] = {
+ {HFI_SYSTEM_ERROR_BEGIN, HFI_SYSTEM_ERROR_END, handle_system_error },
+ {HFI_PROP_BEGIN, HFI_PROP_END, handle_system_property },
+ {HFI_CMD_BEGIN, HFI_CMD_END, handle_system_init },
+ };
+
+ start_pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
+ for (i = 0; i < ARRAY_SIZE(be); i++) {
+ pkt = start_pkt;
+ for (j = 0; j < hdr->num_packets; j++) {
+ packet = (struct hfi_packet *)pkt;
+ if (packet->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
+ ret = handle_system_error(core, packet);
+ return ret;
+ }
+
+ if (packet->type > be[i].begin && packet->type < be[i].end) {
+ ret = be[i].handle(core, packet);
+ if (ret)
+ return ret;
+
+ if (packet->type > HFI_SYSTEM_ERROR_BEGIN &&
+ packet->type < HFI_SYSTEM_ERROR_END)
+ return 0;
+ }
+ pkt += packet->size;
+ }
+ }
+
+ return ret;
+}
+
+static int handle_session_response(struct iris_core *core,
+ struct hfi_header *hdr)
+{
+ struct hfi_packet *packet;
+ struct iris_inst *inst;
+ u8 *pkt, *start_pkt;
+ int ret = 0;
+ int i, j;
+ static const struct iris_inst_hfi_range be[] = {
+ {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, handle_session_error },
+ {HFI_PROP_BEGIN, HFI_PROP_END, handle_session_property },
+ {HFI_CMD_BEGIN, HFI_CMD_END, handle_session_command },
+ };
+
+ inst = to_instance(core, hdr->session_id);
+ if (!inst)
+ return -EINVAL;
+
+ mutex_lock(&inst->lock);
+ memset(&inst->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info));
+
+ pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
+ for (i = 0; i < hdr->num_packets; i++) {
+ packet = (struct hfi_packet *)pkt;
+ if (packet->type == HFI_CMD_SETTINGS_CHANGE) {
+ if (packet->port == HFI_PORT_BITSTREAM) {
+ vdec_init_src_change_param(inst);
+ break;
+ }
+ }
+ pkt += packet->size;
+ }
+
+ start_pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
+ for (i = 0; i < ARRAY_SIZE(be); i++) {
+ pkt = start_pkt;
+ for (j = 0; j < hdr->num_packets; j++) {
+ packet = (struct hfi_packet *)pkt;
+ if (packet->flags & HFI_FW_FLAGS_SESSION_ERROR)
+ handle_session_error(inst, packet);
+
+ if (packet->type > be[i].begin && packet->type < be[i].end) {
+ ret = be[i].handle(inst, packet);
+ if (ret)
+ iris_inst_change_state(inst, IRIS_INST_ERROR);
+ }
+ pkt += packet->size;
+ }
+ }
+
+ memset(&inst->hfi_frame_info, 0, sizeof(struct iris_hfi_frame_info));
+ mutex_unlock(&inst->lock);
+
+ return ret;
+}
+
static int handle_response(struct iris_core *core, void *response)
{
struct hfi_header *hdr;
@@ -96,6 +447,11 @@ static int handle_response(struct iris_core *core, void *response)
if (ret)
return handle_system_error(core, NULL);

+ if (!hdr->session_id)
+ return handle_system_response(core, hdr);
+ else
+ return handle_session_response(core, hdr);
+
return ret;
}

diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
index 365f844..4f51d68 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
@@ -40,6 +40,10 @@
* @fw_min_count: minimnum count of buffers needed by fw
* @state: instance state
* @ipsc_properties_set: boolean to set ipsc properties to fw
+ * @hfi_frame_info: structure of frame info
+ * @src_subcr_params: subscription params to fw on input port
+ * @dst_subcr_params: subscription params to fw on output port
+ * @dpb_list_payload: array of dpb buffers
*/

struct iris_inst {
@@ -66,6 +70,10 @@ struct iris_inst {
u32 fw_min_count;
enum iris_inst_state state;
bool ipsc_properties_set;
+ struct iris_hfi_frame_info hfi_frame_info;
+ struct subscription_params src_subcr_params;
+ struct subscription_params dst_subcr_params;
+ u32 dpb_list_payload[MAX_DPB_LIST_ARRAY_SIZE];
};

#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
index 7d16c96..ac47fc0 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
@@ -14,6 +14,13 @@
#include "iris_hfi_packet.h"
#include "iris_vdec.h"

+#define UNSPECIFIED_COLOR_FORMAT 5
+
+struct vdec_prop_type_handle {
+ u32 type;
+ int (*handle)(struct iris_inst *inst);
+};
+
static int vdec_codec_change(struct iris_inst *inst, u32 v4l2_codec)
{
bool session_init = false;
@@ -376,6 +383,455 @@ int vdec_subscribe_property(struct iris_inst *inst, u32 plane)
(subscribe_prop_size + 1) * sizeof(u32));
}

+static int vdec_set_bitstream_resolution(struct iris_inst *inst)
+{
+ u32 resolution;
+
+ resolution = inst->fmt_src->fmt.pix_mp.width << 16 |
+ inst->fmt_src->fmt.pix_mp.height;
+ inst->src_subcr_params.bitstream_resolution = resolution;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_BITSTREAM_RESOLUTION,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32,
+ &resolution,
+ sizeof(u32));
+}
+
+static int vdec_set_crop_offsets(struct iris_inst *inst)
+{
+ u32 left_offset, top_offset, right_offset, bottom_offset;
+ u32 payload[2] = {0};
+
+ left_offset = inst->crop.left;
+ top_offset = inst->crop.top;
+ right_offset = (inst->fmt_src->fmt.pix_mp.width -
+ inst->crop.width);
+ bottom_offset = (inst->fmt_src->fmt.pix_mp.height -
+ inst->crop.height);
+
+ payload[0] = left_offset << 16 | top_offset;
+ payload[1] = right_offset << 16 | bottom_offset;
+ inst->src_subcr_params.crop_offsets[0] = payload[0];
+ inst->src_subcr_params.crop_offsets[1] = payload[1];
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_CROP_OFFSETS,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_64_PACKED,
+ &payload,
+ sizeof(u64));
+}
+
+static int vdec_set_bit_depth(struct iris_inst *inst)
+{
+ u32 bitdepth = 8 << 16 | 8;
+ u32 pix_fmt;
+
+ pix_fmt = inst->fmt_dst->fmt.pix_mp.pixelformat;
+ if (is_10bit_colorformat(pix_fmt))
+ bitdepth = 10 << 16 | 10;
+
+ inst->src_subcr_params.bit_depth = bitdepth;
+ inst->cap[BIT_DEPTH].value = bitdepth;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32,
+ &bitdepth,
+ sizeof(u32));
+}
+
+static int vdec_set_coded_frames(struct iris_inst *inst)
+{
+ u32 coded_frames = 0;
+
+ if (inst->cap[CODED_FRAMES].value == CODED_FRAMES_PROGRESSIVE)
+ coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
+ inst->src_subcr_params.coded_frames = coded_frames;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_CODED_FRAMES,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32,
+ &coded_frames,
+ sizeof(u32));
+}
+
+static int vdec_set_min_output_count(struct iris_inst *inst)
+{
+ u32 min_output;
+
+ min_output = inst->buffers.output.min_count;
+ inst->src_subcr_params.fw_min_count = min_output;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32,
+ &min_output,
+ sizeof(u32));
+}
+
+static int vdec_set_picture_order_count(struct iris_inst *inst)
+{
+ u32 poc = 0;
+
+ inst->src_subcr_params.pic_order_cnt = poc;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_PIC_ORDER_CNT_TYPE,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32,
+ &poc,
+ sizeof(u32));
+}
+
+static int vdec_set_colorspace(struct iris_inst *inst)
+{
+ u32 video_signal_type_present_flag = 0, color_info = 0;
+ u32 matrix_coeff = HFI_MATRIX_COEFF_RESERVED;
+ u32 video_format = UNSPECIFIED_COLOR_FORMAT;
+ struct v4l2_pix_format_mplane *pixmp = NULL;
+ u32 full_range = V4L2_QUANTIZATION_DEFAULT;
+ u32 transfer_char = HFI_TRANSFER_RESERVED;
+ u32 colour_description_present_flag = 0;
+ u32 primaries = HFI_PRIMARIES_RESERVED;
+
+ int ret;
+
+ if (inst->codec == VP9)
+ return 0;
+
+ pixmp = &inst->fmt_src->fmt.pix_mp;
+ if (pixmp->colorspace != V4L2_COLORSPACE_DEFAULT ||
+ pixmp->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT ||
+ pixmp->xfer_func != V4L2_XFER_FUNC_DEFAULT) {
+ colour_description_present_flag = 1;
+ video_signal_type_present_flag = 1;
+ primaries = get_hfi_color_primaries(pixmp->colorspace);
+ matrix_coeff = get_hfi_matrix_coefficients(pixmp->ycbcr_enc);
+ transfer_char = get_hfi_transfer_char(pixmp->xfer_func);
+ }
+
+ if (pixmp->quantization != V4L2_QUANTIZATION_DEFAULT) {
+ video_signal_type_present_flag = 1;
+ full_range = pixmp->quantization ==
+ V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
+ }
+
+ color_info = (matrix_coeff & 0xFF) |
+ ((transfer_char << 8) & 0xFF00) |
+ ((primaries << 16) & 0xFF0000) |
+ ((colour_description_present_flag << 24) & 0x1000000) |
+ ((full_range << 25) & 0x2000000) |
+ ((video_format << 26) & 0x1C000000) |
+ ((video_signal_type_present_flag << 29) & 0x20000000);
+
+ inst->src_subcr_params.color_info = color_info;
+
+ ret = iris_hfi_set_property(inst,
+ HFI_PROP_SIGNAL_COLOR_INFO,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_32_PACKED,
+ &color_info,
+ sizeof(u32));
+
+ return ret;
+}
+
+static int vdec_set_profile(struct iris_inst *inst)
+{
+ u32 profile;
+
+ profile = inst->cap[PROFILE].value;
+ inst->src_subcr_params.profile = profile;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_PROFILE,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32_ENUM,
+ &profile,
+ sizeof(u32));
+}
+
+static int vdec_set_level(struct iris_inst *inst)
+{
+ u32 level;
+
+ level = inst->cap[LEVEL].value;
+ inst->src_subcr_params.level = level;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_LEVEL,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32_ENUM,
+ &level,
+ sizeof(u32));
+}
+
+static int vdec_set_tier(struct iris_inst *inst)
+{
+ u32 tier;
+
+ tier = inst->cap[HEVC_TIER].value;
+ inst->src_subcr_params.tier = tier;
+
+ return iris_hfi_set_property(inst,
+ HFI_PROP_TIER,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(INPUT_MPLANE),
+ HFI_PAYLOAD_U32_ENUM,
+ &tier,
+ sizeof(u32));
+}
+
+int vdec_subscribe_src_change_param(struct iris_inst *inst)
+{
+ const u32 *src_change_param;
+ u32 src_change_param_size;
+ struct iris_core *core;
+ u32 payload[32] = {0};
+ int ret;
+ u32 i, j;
+
+ static const struct vdec_prop_type_handle prop_type_handle_arr[] = {
+ {HFI_PROP_BITSTREAM_RESOLUTION, vdec_set_bitstream_resolution },
+ {HFI_PROP_CROP_OFFSETS, vdec_set_crop_offsets },
+ {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, vdec_set_bit_depth },
+ {HFI_PROP_CODED_FRAMES, vdec_set_coded_frames },
+ {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, vdec_set_min_output_count },
+ {HFI_PROP_PIC_ORDER_CNT_TYPE, vdec_set_picture_order_count },
+ {HFI_PROP_SIGNAL_COLOR_INFO, vdec_set_colorspace },
+ {HFI_PROP_PROFILE, vdec_set_profile },
+ {HFI_PROP_LEVEL, vdec_set_level },
+ {HFI_PROP_TIER, vdec_set_tier },
+ };
+
+ core = inst->core;
+
+ payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+ if (inst->codec == H264) {
+ src_change_param_size = core->platform_data->avc_subscribe_param_size;
+ src_change_param = core->platform_data->avc_subscribe_param;
+ } else if (inst->codec == HEVC) {
+ src_change_param_size = core->platform_data->hevc_subscribe_param_size;
+ src_change_param = core->platform_data->hevc_subscribe_param;
+ } else if (inst->codec == VP9) {
+ src_change_param_size = core->platform_data->vp9_subscribe_param_size;
+ src_change_param = core->platform_data->vp9_subscribe_param;
+ } else {
+ src_change_param = NULL;
+ return -EINVAL;
+ }
+
+ if (!src_change_param || !src_change_param_size)
+ return -EINVAL;
+
+ for (i = 0; i < src_change_param_size; i++)
+ payload[i + 1] = src_change_param[i];
+
+ ret = iris_hfi_session_subscribe_mode(inst,
+ HFI_CMD_SUBSCRIBE_MODE,
+ INPUT_MPLANE,
+ HFI_PAYLOAD_U32_ARRAY,
+ &payload[0],
+ ((src_change_param_size + 1) * sizeof(u32)));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < src_change_param_size; i++) {
+ for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
+ if (prop_type_handle_arr[j].type == src_change_param[i]) {
+ ret = prop_type_handle_arr[j].handle(inst);
+ if (ret)
+ return ret;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int vdec_init_src_change_param(struct iris_inst *inst)
+{
+ u32 left_offset, top_offset, right_offset, bottom_offset;
+ struct v4l2_pix_format_mplane *pixmp_ip, *pixmp_op;
+ u32 primaries, matrix_coeff, transfer_char;
+ struct subscription_params *subsc_params;
+ u32 colour_description_present_flag = 0;
+ u32 video_signal_type_present_flag = 0;
+ u32 full_range = 0, video_format = 0;
+
+ subsc_params = &inst->src_subcr_params;
+ pixmp_ip = &inst->fmt_src->fmt.pix_mp;
+ pixmp_op = &inst->fmt_dst->fmt.pix_mp;
+
+ subsc_params->bitstream_resolution =
+ pixmp_ip->width << 16 | pixmp_ip->height;
+
+ left_offset = inst->crop.left;
+ top_offset = inst->crop.top;
+ right_offset = (pixmp_ip->width - inst->crop.width);
+ bottom_offset = (pixmp_ip->height - inst->crop.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.output.min_count;
+
+ primaries = get_hfi_color_primaries(pixmp_op->colorspace);
+ matrix_coeff = get_hfi_matrix_coefficients(pixmp_op->ycbcr_enc);
+ transfer_char = get_hfi_transfer_char(pixmp_op->xfer_func);
+ full_range = pixmp_op->quantization == V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
+ subsc_params->color_info =
+ (matrix_coeff & 0xFF) |
+ ((transfer_char << 8) & 0xFF00) |
+ ((primaries << 16) & 0xFF0000) |
+ ((colour_description_present_flag << 24) & 0x1000000) |
+ ((full_range << 25) & 0x2000000) |
+ ((video_format << 26) & 0x1C000000) |
+ ((video_signal_type_present_flag << 29) & 0x20000000);
+
+ subsc_params->profile = inst->cap[PROFILE].value;
+ subsc_params->level = inst->cap[LEVEL].value;
+ subsc_params->tier = inst->cap[HEVC_TIER].value;
+ subsc_params->pic_order_cnt = inst->cap[POC].value;
+ subsc_params->bit_depth = inst->cap[BIT_DEPTH].value;
+ if (inst->cap[CODED_FRAMES].value ==
+ CODED_FRAMES_PROGRESSIVE)
+ subsc_params->coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
+ else
+ subsc_params->coded_frames = 0;
+
+ return 0;
+}
+
+static int vdec_read_input_subcr_params(struct iris_inst *inst)
+{
+ struct v4l2_pix_format_mplane *pixmp_ip, *pixmp_op;
+ u32 primaries, matrix_coeff, transfer_char;
+ struct subscription_params subsc_params;
+ u32 colour_description_present_flag = 0;
+ u32 video_signal_type_present_flag = 0;
+ u32 full_range = 0;
+ u32 width, height;
+
+ subsc_params = inst->src_subcr_params;
+ pixmp_ip = &inst->fmt_src->fmt.pix_mp;
+ pixmp_op = &inst->fmt_dst->fmt.pix_mp;
+ 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 = pixmp_op->pixelformat == V4L2_PIX_FMT_QC10C ?
+ ALIGN(width, 192) : ALIGN(width, 128);
+ pixmp_op->height = pixmp_op->pixelformat == V4L2_PIX_FMT_QC10C ?
+ ALIGN(height, 16) : ALIGN(height, 32);
+ pixmp_op->plane_fmt[0].bytesperline =
+ pixmp_op->pixelformat == V4L2_PIX_FMT_QC10C ?
+ ALIGN(ALIGN(width, 192) * 4 / 3, 256) :
+ 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 =
+ get_v4l2_color_primaries(primaries);
+ pixmp_op->xfer_func =
+ get_v4l2_transfer_char(transfer_char);
+ pixmp_op->ycbcr_enc =
+ 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->cap[PROFILE].value = subsc_params.profile;
+ inst->cap[LEVEL].value = subsc_params.level;
+ inst->cap[HEVC_TIER].value = subsc_params.tier;
+ inst->cap[POC].value = subsc_params.pic_order_cnt;
+
+ if (subsc_params.bit_depth == BIT_DEPTH_8)
+ inst->cap[BIT_DEPTH].value = BIT_DEPTH_8;
+ else
+ inst->cap[BIT_DEPTH].value = BIT_DEPTH_10;
+
+ if (subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)
+ inst->cap[CODED_FRAMES].value = CODED_FRAMES_PROGRESSIVE;
+ else
+ inst->cap[CODED_FRAMES].value = CODED_FRAMES_INTERLACE;
+
+ inst->fw_min_count = subsc_params.fw_min_count;
+ inst->buffers.output.min_count = iris_get_buf_min_count(inst, BUF_OUTPUT);
+
+ return 0;
+}
+
+int vdec_src_change(struct iris_inst *inst)
+{
+ struct v4l2_event event = {0};
+ u32 ret;
+
+ if (!inst->vb2q_src->streaming)
+ return 0;
+
+ ret = vdec_read_input_subcr_params(inst);
+ if (ret)
+ return ret;
+
+ event.type = V4L2_EVENT_SOURCE_CHANGE;
+ event.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION;
+ v4l2_event_queue_fh(&inst->fh, &event);
+
+ return ret;
+}
+
static int vdec_set_colorformat(struct iris_inst *inst)
{
u32 hfi_colorformat;
@@ -483,3 +939,127 @@ int vdec_set_output_property(struct iris_inst *inst)

return vdec_set_ubwc_stride_scanline(inst);
}
+
+int vdec_subscribe_dst_change_param(struct iris_inst *inst)
+{
+ u32 prop_type, payload_size, payload_type;
+ struct subscription_params subsc_params;
+ const u32 *dst_change_param = NULL;
+ u32 dst_change_param_size = 0;
+ struct iris_core *core;
+ u32 payload[32] = {0};
+ int ret;
+ u32 i;
+
+ core = inst->core;
+
+ payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+ if (inst->codec == H264) {
+ dst_change_param_size = core->platform_data->avc_subscribe_param_size;
+ dst_change_param = core->platform_data->avc_subscribe_param;
+ } else if (inst->codec == HEVC) {
+ dst_change_param_size = core->platform_data->hevc_subscribe_param_size;
+ dst_change_param = core->platform_data->hevc_subscribe_param;
+ } else if (inst->codec == VP9) {
+ dst_change_param_size = core->platform_data->vp9_subscribe_param_size;
+ dst_change_param = core->platform_data->vp9_subscribe_param;
+ } else {
+ dst_change_param = NULL;
+ return -EINVAL;
+ }
+
+ if (!dst_change_param || !dst_change_param_size)
+ return -EINVAL;
+
+ payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
+ for (i = 0; i < dst_change_param_size; i++)
+ payload[i + 1] = dst_change_param[i];
+
+ ret = iris_hfi_session_subscribe_mode(inst,
+ HFI_CMD_SUBSCRIBE_MODE,
+ OUTPUT_MPLANE,
+ HFI_PAYLOAD_U32_ARRAY,
+ &payload[0],
+ ((dst_change_param_size + 1) * sizeof(u32)));
+ if (ret)
+ return ret;
+
+ subsc_params = inst->dst_subcr_params;
+ for (i = 0; i < dst_change_param_size; i++) {
+ payload[0] = 0;
+ payload[1] = 0;
+ payload_size = 0;
+ payload_type = 0;
+ prop_type = dst_change_param[i];
+ switch (prop_type) {
+ case HFI_PROP_BITSTREAM_RESOLUTION:
+ payload[0] = subsc_params.bitstream_resolution;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_CROP_OFFSETS:
+ payload[0] = subsc_params.crop_offsets[0];
+ payload[1] = subsc_params.crop_offsets[1];
+ payload_size = sizeof(u64);
+ payload_type = HFI_PAYLOAD_64_PACKED;
+ break;
+ case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
+ payload[0] = subsc_params.bit_depth;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_CODED_FRAMES:
+ payload[0] = subsc_params.coded_frames;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
+ payload[0] = subsc_params.fw_min_count;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_PIC_ORDER_CNT_TYPE:
+ payload[0] = subsc_params.pic_order_cnt;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_SIGNAL_COLOR_INFO:
+ payload[0] = subsc_params.color_info;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_PROFILE:
+ payload[0] = subsc_params.profile;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_LEVEL:
+ payload[0] = subsc_params.level;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ case HFI_PROP_TIER:
+ payload[0] = subsc_params.tier;
+ payload_size = sizeof(u32);
+ payload_type = HFI_PAYLOAD_U32;
+ break;
+ default:
+ prop_type = 0;
+ ret = -EINVAL;
+ break;
+ }
+ if (prop_type) {
+ ret = iris_hfi_set_property(inst,
+ prop_type,
+ HFI_HOST_FLAGS_NONE,
+ get_hfi_port(OUTPUT_MPLANE),
+ payload_type,
+ &payload,
+ payload_size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.h b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.h
index 6b0306c..e0db653 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.h
@@ -16,5 +16,9 @@ int vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f);
int vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub);
int vdec_subscribe_property(struct iris_inst *inst, u32 plane);
int vdec_set_output_property(struct iris_inst *inst);
+int vdec_init_src_change_param(struct iris_inst *inst);
+int vdec_src_change(struct iris_inst *inst);
+int vdec_subscribe_src_change_param(struct iris_inst *inst);
+int vdec_subscribe_dst_change_param(struct iris_inst *inst);

#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_common.h b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
index fc12bde..22a8f5b 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_common.h
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_common.h
@@ -206,6 +206,12 @@ struct platform_data {
u32 core_data_size;
struct plat_inst_cap *inst_cap_data;
u32 inst_cap_data_size;
+ const u32 *avc_subscribe_param;
+ unsigned int avc_subscribe_param_size;
+ const u32 *hevc_subscribe_param;
+ unsigned int hevc_subscribe_param_size;
+ const u32 *vp9_subscribe_param;
+ unsigned int vp9_subscribe_param_size;
const u32 *dec_input_prop;
unsigned int dec_input_prop_size;
const u32 *dec_output_prop_avc;
diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
index 6a4bfa3..7ae9715 100644
--- a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
+++ b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c
@@ -382,6 +382,38 @@ static struct format_capability format_data_sm8550 = {
.color_format_info_size = ARRAY_SIZE(color_format_data_sm8550),
};

+static const u32 sm8550_vdec_src_change_param_avc[] = {
+ HFI_PROP_BITSTREAM_RESOLUTION,
+ HFI_PROP_CROP_OFFSETS,
+ HFI_PROP_CODED_FRAMES,
+ HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+ HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+ HFI_PROP_PIC_ORDER_CNT_TYPE,
+ HFI_PROP_PROFILE,
+ HFI_PROP_LEVEL,
+ HFI_PROP_SIGNAL_COLOR_INFO,
+};
+
+static const u32 sm8550_vdec_src_change_param_hevc[] = {
+ HFI_PROP_BITSTREAM_RESOLUTION,
+ HFI_PROP_CROP_OFFSETS,
+ HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+ HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+ HFI_PROP_PROFILE,
+ HFI_PROP_LEVEL,
+ HFI_PROP_TIER,
+ HFI_PROP_SIGNAL_COLOR_INFO,
+};
+
+static const u32 sm8550_vdec_src_change_param_vp9[] = {
+ HFI_PROP_BITSTREAM_RESOLUTION,
+ HFI_PROP_CROP_OFFSETS,
+ HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+ HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
+ HFI_PROP_PROFILE,
+ HFI_PROP_LEVEL,
+};
+
static const u32 sm8550_vdec_input_properties[] = {
HFI_PROP_NO_OUTPUT,
};
@@ -430,6 +462,18 @@ struct platform_data sm8550_data = {
.ubwc_config = ubwc_config_sm8550,
.format_data = &format_data_sm8550,

+ .avc_subscribe_param =
+ sm8550_vdec_src_change_param_avc,
+ .avc_subscribe_param_size =
+ ARRAY_SIZE(sm8550_vdec_src_change_param_avc),
+ .hevc_subscribe_param =
+ sm8550_vdec_src_change_param_hevc,
+ .hevc_subscribe_param_size =
+ ARRAY_SIZE(sm8550_vdec_src_change_param_hevc),
+ .vp9_subscribe_param =
+ sm8550_vdec_src_change_param_vp9,
+ .vp9_subscribe_param_size =
+ ARRAY_SIZE(sm8550_vdec_src_change_param_vp9),
.dec_input_prop = sm8550_vdec_input_properties,
.dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_input_properties),
.dec_output_prop_avc = sm8550_vdec_output_properties_avc,
--
2.7.4