On Fri Feb 7 13:24:59 2025 +0530, Dikshita Agarwal wrote:
> Implement the functions for creating, queueing, releasing and destroying
> the buffers for internal usage.
> 
> 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_buffer.c     | 206 ++++++++++++++++++
 drivers/media/platform/qcom/iris/iris_buffer.h     |   7 +
 drivers/media/platform/qcom/iris/iris_hfi_common.h |   4 +
 .../platform/qcom/iris/iris_hfi_gen1_command.c     | 127 ++++++++++-
 .../platform/qcom/iris/iris_hfi_gen1_defines.h     |  37 ++++
 .../platform/qcom/iris/iris_hfi_gen1_response.c    |   4 +
 .../platform/qcom/iris/iris_hfi_gen2_command.c     | 132 ++++++++++++
 .../platform/qcom/iris/iris_hfi_gen2_defines.h     |   9 +
 .../platform/qcom/iris/iris_hfi_gen2_packet.h      |  41 ++++
 .../platform/qcom/iris/iris_hfi_gen2_response.c    | 149 ++++++++++++-
 .../platform/qcom/iris/iris_platform_common.h      |   5 +
 .../platform/qcom/iris/iris_platform_sm8550.c      |  17 ++
 drivers/media/platform/qcom/iris/iris_vdec.c       |  32 +++
 drivers/media/platform/qcom/iris/iris_vidc.c       |  11 +
 drivers/media/platform/qcom/iris/iris_vpu_buffer.c | 233 ++++++++++++++++++++-
 drivers/media/platform/qcom/iris/iris_vpu_buffer.h |  77 ++++++-
 16 files changed, 1087 insertions(+), 4 deletions(-)

---

diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c 
b/drivers/media/platform/qcom/iris/iris_buffer.c
index 58d45d23393b..e9d372580b5f 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_buffer.c
@@ -7,6 +7,7 @@
 
 #include "iris_buffer.h"
 #include "iris_instance.h"
+#include "iris_vpu_buffer.h"
 
 #define PIXELS_4K 4096
 #define MAX_WIDTH 4096
@@ -228,6 +229,211 @@ int iris_get_buffer_size(struct iris_inst *inst,
        }
 }
 
+static void iris_fill_internal_buf_info(struct iris_inst *inst,
+                                       enum iris_buffer_type buffer_type)
+{
+       struct iris_buffers *buffers = &inst->buffers[buffer_type];
+
+       buffers->size = iris_vpu_buf_size(inst, buffer_type);
+       buffers->min_count = iris_vpu_buf_count(inst, buffer_type);
+}
+
+void iris_get_internal_buffers(struct iris_inst *inst, u32 plane)
+{
+       const struct iris_platform_data *platform_data = 
inst->core->iris_platform_data;
+       const u32 *internal_buf_type;
+       u32 internal_buffer_count, i;
+
+       if (V4L2_TYPE_IS_OUTPUT(plane)) {
+               internal_buf_type = platform_data->dec_ip_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
+               for (i = 0; i < internal_buffer_count; i++)
+                       iris_fill_internal_buf_info(inst, internal_buf_type[i]);
+       } else {
+               internal_buf_type = platform_data->dec_op_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
+               for (i = 0; i < internal_buffer_count; i++)
+                       iris_fill_internal_buf_info(inst, internal_buf_type[i]);
+       }
+}
+
+static int iris_create_internal_buffer(struct iris_inst *inst,
+                                      enum iris_buffer_type buffer_type, u32 
index)
+{
+       struct iris_buffers *buffers = &inst->buffers[buffer_type];
+       struct iris_core *core = inst->core;
+       struct iris_buffer *buffer;
+
+       if (!buffers->size)
+               return 0;
+
+       buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&buffer->list);
+       buffer->type = buffer_type;
+       buffer->index = index;
+       buffer->buffer_size = buffers->size;
+       buffer->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;
+       list_add_tail(&buffer->list, &buffers->list);
+
+       buffer->kvaddr = dma_alloc_attrs(core->dev, buffer->buffer_size,
+                                        &buffer->device_addr, GFP_KERNEL, 
buffer->dma_attrs);
+       if (!buffer->kvaddr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int iris_create_internal_buffers(struct iris_inst *inst, u32 plane)
+{
+       const struct iris_platform_data *platform_data = 
inst->core->iris_platform_data;
+       u32 internal_buffer_count, i, j;
+       struct iris_buffers *buffers;
+       const u32 *internal_buf_type;
+       int ret;
+
+       if (V4L2_TYPE_IS_OUTPUT(plane)) {
+               internal_buf_type = platform_data->dec_ip_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
+       } else {
+               internal_buf_type = platform_data->dec_op_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
+       }
+
+       for (i = 0; i < internal_buffer_count; i++) {
+               buffers = &inst->buffers[internal_buf_type[i]];
+               for (j = 0; j < buffers->min_count; j++) {
+                       ret = iris_create_internal_buffer(inst, 
internal_buf_type[i], j);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf)
+{
+       const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
+       int ret;
+
+       ret = hfi_ops->session_queue_buf(inst, buf);
+       if (ret)
+               return ret;
+
+       buf->attr &= ~BUF_ATTR_DEFERRED;
+       buf->attr |= BUF_ATTR_QUEUED;
+
+       return 0;
+}
+
+int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane)
+{
+       const struct iris_platform_data *platform_data = 
inst->core->iris_platform_data;
+       struct iris_buffer *buffer, *next;
+       struct iris_buffers *buffers;
+       const u32 *internal_buf_type;
+       u32 internal_buffer_count, i;
+       int ret;
+
+       if (V4L2_TYPE_IS_OUTPUT(plane)) {
+               internal_buf_type = platform_data->dec_ip_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size;
+       } else {
+               internal_buf_type = platform_data->dec_op_int_buf_tbl;
+               internal_buffer_count = platform_data->dec_op_int_buf_tbl_size;
+       }
+
+       for (i = 0; i < internal_buffer_count; i++) {
+               buffers = &inst->buffers[internal_buf_type[i]];
+               list_for_each_entry_safe(buffer, next, &buffers->list, list) {
+                       if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
+                               continue;
+                       if (buffer->attr & BUF_ATTR_QUEUED)
+                               continue;
+                       ret = iris_queue_buffer(inst, buffer);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer 
*buffer)
+{
+       struct iris_core *core = inst->core;
+
+       list_del(&buffer->list);
+       dma_free_attrs(core->dev, buffer->buffer_size, buffer->kvaddr,
+                      buffer->device_addr, buffer->dma_attrs);
+       kfree(buffer);
+
+       return 0;
+}
+
+int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane)
+{
+       const struct iris_platform_data *platform_data = 
inst->core->iris_platform_data;
+       struct iris_buffer *buf, *next;
+       struct iris_buffers *buffers;
+       const u32 *internal_buf_type;
+       u32 i, len;
+       int ret;
+
+       if (V4L2_TYPE_IS_OUTPUT(plane)) {
+               internal_buf_type = platform_data->dec_ip_int_buf_tbl;
+               len = platform_data->dec_ip_int_buf_tbl_size;
+       } else {
+               internal_buf_type = platform_data->dec_op_int_buf_tbl;
+               len = platform_data->dec_op_int_buf_tbl_size;
+       }
+
+       for (i = 0; i < len; i++) {
+               buffers = &inst->buffers[internal_buf_type[i]];
+               list_for_each_entry_safe(buf, next, &buffers->list, list) {
+                       ret = iris_destroy_internal_buffer(inst, buf);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst)
+{
+       struct iris_buffers *buffers = &inst->buffers[BUF_PERSIST];
+       struct iris_buffer *buffer, *next;
+       int ret;
+       u32 i;
+
+       if (!list_empty(&buffers->list))
+               return 0;
+
+       iris_fill_internal_buf_info(inst, BUF_PERSIST);
+
+       for (i = 0; i < buffers->min_count; i++) {
+               ret = iris_create_internal_buffer(inst, BUF_PERSIST, i);
+               if (ret)
+                       return ret;
+       }
+
+       list_for_each_entry_safe(buffer, next, &buffers->list, list) {
+               if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
+                       continue;
+               if (buffer->attr & BUF_ATTR_QUEUED)
+                       continue;
+               ret = iris_queue_buffer(inst, buffer);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 void iris_vb2_queue_error(struct iris_inst *inst)
 {
        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h 
b/drivers/media/platform/qcom/iris/iris_buffer.h
index ae2ec5637108..73f3a16ff7a2 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_buffer.h
@@ -102,6 +102,13 @@ struct iris_buffers {
 };
 
 int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type 
buffer_type);
+void iris_get_internal_buffers(struct iris_inst *inst, u32 plane);
+int iris_create_internal_buffers(struct iris_inst *inst, u32 plane);
+int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane);
+int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer 
*buffer);
+int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane);
+int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst);
+int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf);
 void iris_vb2_queue_error(struct iris_inst *inst);
 
 #endif
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h 
b/drivers/media/platform/qcom/iris/iris_hfi_common.h
index 1fba5a9292af..c54c88658633 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_common.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h
@@ -9,6 +9,8 @@
 #include <linux/types.h>
 #include <media/v4l2-device.h>
 
+#include "iris_buffer.h"
+
 struct iris_inst;
 struct iris_core;
 
@@ -114,6 +116,8 @@ struct iris_hfi_command_ops {
                                    void *payload, u32 payload_size);
        int (*session_open)(struct iris_inst *inst);
        int (*session_start)(struct iris_inst *inst, u32 plane);
+       int (*session_queue_buf)(struct iris_inst *inst, struct iris_buffer 
*buffer);
+       int (*session_release_buf)(struct iris_inst *inst, struct iris_buffer 
*buffer);
        int (*session_stop)(struct iris_inst *inst, u32 plane);
        int (*session_close)(struct iris_inst *inst);
 };
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c 
b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
index 26fe65ddba8a..603ca485992d 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
@@ -8,6 +8,24 @@
 #include "iris_instance.h"
 #include "iris_vpu_buffer.h"
 
+static u32 iris_hfi_gen1_buf_type_from_driver(enum iris_buffer_type 
buffer_type)
+{
+       switch (buffer_type) {
+       case BUF_INPUT:
+               return HFI_BUFFER_INPUT;
+       case BUF_OUTPUT:
+               return HFI_BUFFER_OUTPUT;
+       case BUF_PERSIST:
+               return HFI_BUFFER_INTERNAL_PERSIST_1;
+       case BUF_BIN:
+               return HFI_BUFFER_INTERNAL_SCRATCH;
+       case BUF_SCRATCH_1:
+               return HFI_BUFFER_INTERNAL_SCRATCH_1;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int iris_hfi_gen1_sys_init(struct iris_core *core)
 {
        struct hfi_sys_init_pkt sys_init_pkt;
@@ -183,6 +201,111 @@ static int iris_hfi_gen1_session_stop(struct iris_inst 
*inst, u32 plane)
        return ret;
 }
 
+static int iris_hfi_gen1_queue_internal_buffer(struct iris_inst *inst, struct 
iris_buffer *buf)
+{
+       struct hfi_session_set_buffers_pkt *int_pkt;
+       u32 buffer_type, i;
+       u32 packet_size;
+       int ret;
+
+       packet_size = struct_size(int_pkt, buffer_info, 1);
+       int_pkt = kzalloc(packet_size, GFP_KERNEL);
+       if (!int_pkt)
+               return -ENOMEM;
+
+       int_pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_BUFFERS;
+       int_pkt->shdr.session_id = inst->session_id;
+       int_pkt->buffer_size = buf->buffer_size;
+       int_pkt->min_buffer_size = buf->buffer_size;
+       int_pkt->num_buffers = 1;
+       int_pkt->extradata_size = 0;
+       int_pkt->shdr.hdr.size = packet_size;
+       for (i = 0; i < int_pkt->num_buffers; i++)
+               int_pkt->buffer_info[i] = buf->device_addr;
+       buffer_type = iris_hfi_gen1_buf_type_from_driver(buf->type);
+       if (buffer_type == -EINVAL) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       int_pkt->buffer_type = buffer_type;
+       ret = iris_hfi_queue_cmd_write(inst->core, int_pkt, 
int_pkt->shdr.hdr.size);
+
+exit:
+       kfree(int_pkt);
+
+       return ret;
+}
+
+static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct 
iris_buffer *buf)
+{
+       switch (buf->type) {
+       case BUF_PERSIST:
+       case BUF_BIN:
+       case BUF_SCRATCH_1:
+               return iris_hfi_gen1_queue_internal_buffer(inst, buf);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct 
iris_buffer *buf)
+{
+       struct hfi_session_release_buffer_pkt *pkt;
+       u32 packet_size, buffer_type, i;
+       int ret;
+
+       buffer_type = iris_hfi_gen1_buf_type_from_driver(buf->type);
+       if (buffer_type == -EINVAL)
+               return -EINVAL;
+
+       if (buffer_type == HFI_BUFFER_INPUT)
+               return 0;
+
+       packet_size = sizeof(*pkt) + sizeof(struct hfi_buffer_info);
+       pkt = kzalloc(packet_size, GFP_KERNEL);
+       if (!pkt)
+               return -ENOMEM;
+
+       pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
+       pkt->shdr.session_id = inst->session_id;
+       pkt->buffer_size = buf->buffer_size;
+       pkt->num_buffers = 1;
+
+       if (buffer_type == HFI_BUFFER_OUTPUT ||
+           buffer_type == HFI_BUFFER_OUTPUT2) {
+               struct hfi_buffer_info *bi;
+
+               bi = (struct hfi_buffer_info *)pkt->buffer_info;
+               for (i = 0; i < pkt->num_buffers; i++) {
+                       bi->buffer_addr = buf->device_addr;
+                       bi->extradata_addr = 0;
+               }
+               pkt->shdr.hdr.size = packet_size;
+       } else {
+               for (i = 0; i < pkt->num_buffers; i++)
+                       pkt->buffer_info[i] = buf->device_addr;
+               pkt->extradata_size = 0;
+               pkt->shdr.hdr.size =
+                               sizeof(struct hfi_session_set_buffers_pkt) +
+                               ((pkt->num_buffers) * sizeof(u32));
+       }
+
+       pkt->response_req = true;
+       pkt->buffer_type = buffer_type;
+
+       ret = iris_hfi_queue_cmd_write(inst->core, pkt, pkt->shdr.hdr.size);
+       if (ret)
+               goto exit;
+
+       ret = iris_wait_for_session_response(inst, false);
+
+exit:
+       kfree(pkt);
+
+       return ret;
+}
+
 static int
 iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt 
*packet,
                                          struct iris_inst *inst, u32 ptype, 
void *pdata)
@@ -495,7 +618,7 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst)
 
        if (iris_split_mode_enabled(inst)) {
                bufsz.type = HFI_BUFFER_OUTPUT;
-               bufsz.size = iris_vpu_dec_dpb_size(inst);
+               bufsz.size = iris_vpu_buf_size(inst, BUF_DPB);
 
                ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz));
                if (ret)
@@ -600,6 +723,8 @@ static const struct iris_hfi_command_ops 
iris_hfi_gen1_command_ops = {
        .session_set_config_params = iris_hfi_gen1_session_set_config_params,
        .session_set_property = iris_hfi_gen1_session_set_property,
        .session_start = iris_hfi_gen1_session_start,
+       .session_queue_buf = iris_hfi_gen1_session_queue_buffer,
+       .session_release_buf = iris_hfi_gen1_session_unset_buffers,
        .session_stop = iris_hfi_gen1_session_stop,
        .session_close = iris_hfi_gen1_session_close,
 };
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 67e7575351d4..cabd91eafc92 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
@@ -24,11 +24,13 @@
 #define HFI_CMD_SYS_SESSION_END                                0x10008
 
 #define HFI_CMD_SESSION_SET_PROPERTY                   0x11001
+#define HFI_CMD_SESSION_SET_BUFFERS                    0x11002
 
 #define HFI_CMD_SESSION_LOAD_RESOURCES                 0x211001
 #define HFI_CMD_SESSION_START                          0x211002
 #define HFI_CMD_SESSION_STOP                           0x211003
 #define HFI_CMD_SESSION_FLUSH                          0x211008
+#define HFI_CMD_SESSION_RELEASE_BUFFERS                        0x21100b
 #define HFI_CMD_SESSION_RELEASE_RESOURCES              0x21100c
 
 #define HFI_ERR_SESSION_UNSUPPORTED_SETTING            0x1008
@@ -53,6 +55,9 @@
 #define HFI_BUFFER_INPUT                               0x1
 #define HFI_BUFFER_OUTPUT                              0x2
 #define HFI_BUFFER_OUTPUT2                             0x3
+#define HFI_BUFFER_INTERNAL_PERSIST_1                  0x5
+#define HFI_BUFFER_INTERNAL_SCRATCH                    0x6
+#define HFI_BUFFER_INTERNAL_SCRATCH_1                  0x7
 
 #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL                0x5
 #define HFI_PROPERTY_SYS_IMAGE_VERSION                 0x6
@@ -80,6 +85,7 @@
 #define HFI_MSG_SESSION_STOP                           0x221003
 #define HFI_MSG_SESSION_FLUSH                          0x221006
 #define HFI_MSG_SESSION_RELEASE_RESOURCES              0x22100a
+#define HFI_MSG_SESSION_RELEASE_BUFFERS                        0x22100c
 
 struct hfi_pkt_hdr {
        u32 size;
@@ -128,11 +134,36 @@ struct hfi_sys_pc_prep_pkt {
        struct hfi_pkt_hdr hdr;
 };
 
+struct hfi_session_set_buffers_pkt {
+       struct hfi_session_hdr_pkt shdr;
+       u32 buffer_type;
+       u32 buffer_size;
+       u32 extradata_size;
+       u32 min_buffer_size;
+       u32 num_buffers;
+       u32 buffer_info[];
+};
+
 struct hfi_session_flush_pkt {
        struct hfi_session_hdr_pkt shdr;
        u32 flush_type;
 };
 
+struct hfi_session_release_buffer_pkt {
+       struct hfi_session_hdr_pkt shdr;
+       u32 buffer_type;
+       u32 buffer_size;
+       u32 extradata_size;
+       u32 response_req;
+       u32 num_buffers;
+       u32 buffer_info[];
+};
+
+struct hfi_buffer_info {
+       u32 buffer_addr;
+       u32 extradata_addr;
+};
+
 struct hfi_msg_event_notify_pkt {
        struct hfi_session_hdr_pkt shdr;
        u32 event_id;
@@ -227,6 +258,12 @@ struct hfi_multi_stream {
        u32 enable;
 };
 
+struct hfi_msg_session_release_buffers_done_pkt {
+       struct hfi_msg_session_hdr_pkt shdr;
+       u32 num_buffers;
+       u32 buffer_info[];
+};
+
 struct hfi_msg_sys_debug_pkt {
        struct hfi_pkt_hdr hdr;
        u32 msg_type;
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 db5858ec04ea..a84bb00388d9 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
@@ -176,6 +176,10 @@ static const struct iris_hfi_gen1_response_pkt_info 
pkt_infos[] = {
         .pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
+       {
+        .pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
+        .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
+       },
 };
 
 static void iris_hfi_gen1_handle_response(struct iris_core *core, void 
*response)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c 
b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
index dddaa074cae1..cc75231f07f1 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
@@ -100,6 +100,24 @@ static u32 iris_hfi_gen2_get_port(u32 plane)
        }
 }
 
+static u32 iris_hfi_gen2_get_port_from_buf_type(enum iris_buffer_type 
buffer_type)
+{
+       switch (buffer_type) {
+       case BUF_INPUT:
+       case BUF_BIN:
+       case BUF_COMV:
+       case BUF_NON_COMV:
+       case BUF_LINE:
+               return HFI_PORT_BITSTREAM;
+       case BUF_OUTPUT:
+       case BUF_DPB:
+               return HFI_PORT_RAW;
+       case BUF_PERSIST:
+       default:
+               return HFI_PORT_NONE;
+       }
+}
+
 static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 
packet_type, u32 flag,
                                              u32 plane, u32 payload_type, void 
*payload,
                                              u32 payload_size)
@@ -719,6 +737,118 @@ static int iris_hfi_gen2_session_stop(struct iris_inst 
*inst, u32 plane)
        return iris_wait_for_session_response(inst, false);
 }
 
+static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type 
buffer_type)
+{
+       switch (buffer_type) {
+       case BUF_INPUT:
+               return HFI_BUFFER_BITSTREAM;
+       case BUF_OUTPUT:
+               return HFI_BUFFER_RAW;
+       case BUF_BIN:
+               return HFI_BUFFER_BIN;
+       case BUF_COMV:
+               return HFI_BUFFER_COMV;
+       case BUF_NON_COMV:
+               return HFI_BUFFER_NON_COMV;
+       case BUF_LINE:
+               return HFI_BUFFER_LINE;
+       case BUF_DPB:
+               return HFI_BUFFER_DPB;
+       case BUF_PERSIST:
+               return HFI_BUFFER_PERSIST;
+       default:
+               return 0;
+       }
+}
+
+static int iris_set_num_comv(struct iris_inst *inst)
+{
+       struct platform_inst_caps *caps;
+       struct iris_core *core = inst->core;
+       u32 num_comv;
+
+       caps = core->iris_platform_data->inst_caps;
+       num_comv = caps->num_comv;
+
+       return core->hfi_ops->session_set_property(inst,
+                                                  HFI_PROP_COMV_BUFFER_COUNT,
+                                                  HFI_HOST_FLAGS_NONE,
+                                                  HFI_PORT_BITSTREAM,
+                                                  HFI_PAYLOAD_U32,
+                                                  &num_comv, sizeof(u32));
+}
+
+static void iris_hfi_gen2_get_buffer(struct iris_buffer *buffer, struct 
iris_hfi_buffer *buf)
+{
+       memset(buf, 0, sizeof(*buf));
+       buf->type = iris_hfi_gen2_buf_type_from_driver(buffer->type);
+       buf->index = buffer->index;
+       buf->base_address = buffer->device_addr;
+       buf->addr_offset = 0;
+       buf->buffer_size = buffer->buffer_size;
+
+       if (buffer->type == BUF_INPUT)
+               buf->buffer_size = ALIGN(buffer->buffer_size, 256);
+       buf->data_offset = buffer->data_offset;
+       buf->data_size = buffer->data_size;
+       if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
+               buf->flags |= HFI_BUF_HOST_FLAG_RELEASE;
+       buf->flags |= HFI_BUF_HOST_FLAGS_CB_NON_SECURE;
+       buf->timestamp = buffer->timestamp;
+}
+
+static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct 
iris_buffer *buffer)
+{
+       struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
+       struct iris_hfi_buffer hfi_buffer;
+       u32 port;
+       int ret;
+
+       iris_hfi_gen2_get_buffer(buffer, &hfi_buffer);
+       if (buffer->type == BUF_COMV) {
+               ret = iris_set_num_comv(inst);
+               if (ret)
+                       return ret;
+       }
+
+       port = iris_hfi_gen2_get_port_from_buf_type(buffer->type);
+       iris_hfi_gen2_packet_session_command(inst,
+                                            HFI_CMD_BUFFER,
+                                            HFI_HOST_FLAGS_INTR_REQUIRED,
+                                            port,
+                                            inst->session_id,
+                                            HFI_PAYLOAD_STRUCTURE,
+                                            &hfi_buffer,
+                                            sizeof(hfi_buffer));
+
+       return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
+                                       inst_hfi_gen2->packet->size);
+}
+
+static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct 
iris_buffer *buffer)
+{
+       struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
+       struct iris_hfi_buffer hfi_buffer;
+       u32 port;
+
+       iris_hfi_gen2_get_buffer(buffer, &hfi_buffer);
+       hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE;
+       port = iris_hfi_gen2_get_port_from_buf_type(buffer->type);
+
+       iris_hfi_gen2_packet_session_command(inst,
+                                            HFI_CMD_BUFFER,
+                                            (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+                                            HFI_HOST_FLAGS_INTR_REQUIRED),
+                                            port,
+                                            inst->session_id,
+                                            HFI_PAYLOAD_STRUCTURE,
+                                            &hfi_buffer,
+                                            sizeof(hfi_buffer));
+
+       return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
+                                       inst_hfi_gen2->packet->size);
+}
+
 static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = {
        .sys_init = iris_hfi_gen2_sys_init,
        .sys_image_version = iris_hfi_gen2_sys_image_version,
@@ -728,6 +858,8 @@ static const struct iris_hfi_command_ops 
iris_hfi_gen2_command_ops = {
        .session_set_config_params = iris_hfi_gen2_session_set_config_params,
        .session_set_property = iris_hfi_gen2_session_set_property,
        .session_start = iris_hfi_gen2_session_start,
+       .session_queue_buf = iris_hfi_gen2_session_queue_buffer,
+       .session_release_buf = iris_hfi_gen2_session_release_buffer,
        .session_stop = iris_hfi_gen2_session_stop,
        .session_close = iris_hfi_gen2_session_close,
 };
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 4fb7a4e4604d..afbdf1f1e68a 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
@@ -17,6 +17,7 @@
 #define HFI_CMD_CLOSE                          0x01000004
 #define HFI_CMD_START                          0x01000005
 #define HFI_CMD_STOP                           0x01000006
+#define HFI_CMD_BUFFER                         0x01000009
 #define HFI_CMD_SUBSCRIBE_MODE                 0x0100000B
 #define HFI_CMD_END                            0x01FFFFFF
 
@@ -53,6 +54,7 @@
 #define HFI_PROP_DEC_DEFAULT_HEADER            0x03000168
 #define HFI_PROP_DEC_START_FROM_RAP_FRAME      0x03000169
 #define HFI_PROP_NO_OUTPUT                     0x0300016a
+#define HFI_PROP_COMV_BUFFER_COUNT             0x03000193
 #define HFI_PROP_END                           0x03FFFFFF
 
 #define HFI_SESSION_ERROR_BEGIN                        0x04000000
@@ -106,6 +108,13 @@ enum hfi_buffer_type {
        HFI_BUFFER_VPSS                         = 0x0000000D,
 };
 
+enum hfi_buffer_host_flags {
+       HFI_BUF_HOST_FLAG_RELEASE               = 0x00000001,
+       HFI_BUF_HOST_FLAG_READONLY              = 0x00000010,
+       HFI_BUF_HOST_FLAG_CODEC_CONFIG          = 0x00000100,
+       HFI_BUF_HOST_FLAGS_CB_NON_SECURE        = 0x00000200,
+};
+
 enum hfi_packet_firmware_flags {
        HFI_FW_FLAGS_SUCCESS                    = 0x00000001,
        HFI_FW_FLAGS_INFORMATION                = 0x00000002,
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h 
b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h
index 0333e37572f6..25b9582349ca 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h
@@ -61,6 +61,47 @@ struct iris_hfi_packet {
        u32 payload[];
 };
 
+/**
+ * struct iris_hfi_buffer
+ *
+ * @type: buffer type indicated by "enum hfi_buffer_type"
+ *        FW needs to return proper type for any buffer command.
+ * @index: index of the buffer
+ * @base_address: base address of the buffer.
+ *                This buffer address is always 4KBytes aligned.
+ * @addr_offset: accessible buffer offset from base address
+ *               Decoder bitstream buffer: 256 Bytes aligned
+ *               Firmware can uniquely identify a buffer based on
+ *               base_address & addr_offset.
+ *               HW can read memory only from base_address+addr_offset.
+ * @buffer_size: accessible buffer size in bytes starting from addr_offset
+ * @data_offset: data starts from "base_address + addr_offset + data_offset"
+ *               RAW buffer: data_offset is 0. Restriction: 4KBytes aligned
+ *               decoder bitstream buffer: no restriction (can be any value)
+ * @data_size: data size in bytes
+ * @flags: buffer flags. It is represented as bit masks.
+ *         host buffer flags are "enum hfi_buffer_host_flags"
+ *         firmware buffer flags are "enum hfi_buffer_firmware_flags"
+ * @timestamp: timestamp of the buffer in nano seconds (ns)
+ *             It is Presentation timestamp (PTS) for encoder & decoder.
+ *             Decoder: it is pass through from bitstream to raw buffer.
+ *                      firmware does not need to return as part of input 
buffer done.
+ *             For any internal buffers: there is no timestamp. Host sets as 0.
+ * @reserved: reserved for future use
+ */
+struct iris_hfi_buffer {
+       u32 type;
+       u32 index;
+       u64 base_address;
+       u32 addr_offset;
+       u32 buffer_size;
+       u32 data_offset;
+       u32 data_size;
+       u64 timestamp;
+       u32 flags;
+       u32 reserved[5];
+};
+
 u32 iris_hfi_gen2_get_color_primaries(u32 primaries);
 u32 iris_hfi_gen2_get_transfer_char(u32 characterstics);
 u32 iris_hfi_gen2_get_matrix_coefficients(u32 coefficients);
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 336b43740b72..9f3764f1903b 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
@@ -25,6 +25,94 @@ struct iris_hfi_gen2_packet_handle {
        int (*handle)(struct iris_inst *inst, struct iris_hfi_packet *pkt);
 };
 
+static u32 iris_hfi_gen2_buf_type_to_driver(enum hfi_buffer_type buf_type)
+{
+       switch (buf_type) {
+       case HFI_BUFFER_BITSTREAM:
+               return BUF_INPUT;
+       case HFI_BUFFER_RAW:
+               return BUF_OUTPUT;
+       case HFI_BUFFER_BIN:
+               return BUF_BIN;
+       case HFI_BUFFER_ARP:
+               return BUF_ARP;
+       case HFI_BUFFER_COMV:
+               return BUF_COMV;
+       case HFI_BUFFER_NON_COMV:
+               return BUF_NON_COMV;
+       case HFI_BUFFER_LINE:
+               return BUF_LINE;
+       case HFI_BUFFER_DPB:
+               return BUF_DPB;
+       case HFI_BUFFER_PERSIST:
+               return BUF_PERSIST;
+       default:
+               return 0;
+       }
+}
+
+static bool iris_hfi_gen2_is_valid_hfi_buffer_type(u32 buffer_type)
+{
+       switch (buffer_type) {
+       case HFI_BUFFER_BITSTREAM:
+       case HFI_BUFFER_RAW:
+       case HFI_BUFFER_BIN:
+       case HFI_BUFFER_ARP:
+       case HFI_BUFFER_COMV:
+       case HFI_BUFFER_NON_COMV:
+       case HFI_BUFFER_LINE:
+       case HFI_BUFFER_DPB:
+       case HFI_BUFFER_PERSIST:
+       case HFI_BUFFER_VPSS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type)
+{
+       if (port == HFI_PORT_NONE && buffer_type != HFI_BUFFER_PERSIST)
+               return false;
+
+       if (port != HFI_PORT_BITSTREAM && port != HFI_PORT_RAW)
+               return false;
+
+       return true;
+}
+
+static bool iris_hfi_gen2_validate_packet_payload(struct iris_hfi_packet *pkt)
+{
+       u32 payload_size = 0;
+
+       switch (pkt->payload_info) {
+       case HFI_PAYLOAD_U32:
+       case HFI_PAYLOAD_S32:
+       case HFI_PAYLOAD_Q16:
+       case HFI_PAYLOAD_U32_ENUM:
+       case HFI_PAYLOAD_32_PACKED:
+               payload_size = 4;
+               break;
+       case HFI_PAYLOAD_U64:
+       case HFI_PAYLOAD_S64:
+       case HFI_PAYLOAD_64_PACKED:
+               payload_size = 8;
+               break;
+       case HFI_PAYLOAD_STRUCTURE:
+               if (pkt->type == HFI_CMD_BUFFER)
+                       payload_size = sizeof(struct iris_hfi_buffer);
+               break;
+       default:
+               payload_size = 0;
+               break;
+       }
+
+       if (pkt->size < sizeof(struct iris_hfi_packet) + payload_size)
+               return false;
+
+       return true;
+}
+
 static int iris_hfi_gen2_validate_packet(u8 *response_pkt, u8 *core_resp_pkt)
 {
        u8 *response_limit = core_resp_pkt + IFACEQ_CORE_PKT_SIZE;
@@ -149,9 +237,65 @@ static void iris_hfi_gen2_handle_session_close(struct 
iris_inst *inst,
        complete(&inst->completion);
 }
 
+static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst,
+                                                       struct iris_hfi_buffer 
*buffer)
+{
+       struct iris_buffer *buf, *iter;
+       struct iris_buffers *buffers;
+       u32 buf_type;
+       int ret = 0;
+       bool found;
+
+       buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type);
+       buffers = &inst->buffers[buf_type];
+
+       found = false;
+       list_for_each_entry(iter, &buffers->list, list) {
+               if (iter->device_addr == buffer->base_address) {
+                       found = true;
+                       buf = iter;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+
+       buf->attr &= ~BUF_ATTR_QUEUED;
+
+       if (buf->attr & BUF_ATTR_PENDING_RELEASE)
+               ret = iris_destroy_internal_buffer(inst, buf);
+
+       return ret;
+}
+
+static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst,
+                                              struct iris_hfi_packet *pkt)
+{
+       struct iris_hfi_buffer *buffer;
+
+       if (pkt->payload_info == HFI_PAYLOAD_NONE)
+               return 0;
+
+       if (!iris_hfi_gen2_validate_packet_payload(pkt)) {
+               iris_inst_change_state(inst, IRIS_INST_ERROR);
+               return 0;
+       }
+
+       buffer = (struct iris_hfi_buffer *)((u8 *)pkt + sizeof(*pkt));
+       if (!iris_hfi_gen2_is_valid_hfi_buffer_type(buffer->type))
+               return 0;
+
+       if (!iris_hfi_gen2_is_valid_hfi_port(pkt->port, buffer->type))
+               return 0;
+
+       return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer);
+}
+
 static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst,
                                                struct iris_hfi_packet *pkt)
 {
+       int ret = 0;
+
        switch (pkt->type) {
        case HFI_CMD_CLOSE:
                iris_hfi_gen2_handle_session_close(inst, pkt);
@@ -159,11 +303,14 @@ static int iris_hfi_gen2_handle_session_command(struct 
iris_inst *inst,
        case HFI_CMD_STOP:
                complete(&inst->completion);
                break;
+       case HFI_CMD_BUFFER:
+               ret = iris_hfi_gen2_handle_session_buffer(inst, pkt);
+               break;
        default:
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst,
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h 
b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 50965450cbb9..de0388a100c3 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -67,6 +67,7 @@ struct platform_inst_caps {
        u32 min_frame_height;
        u32 max_frame_height;
        u32 max_mbpf;
+       u32 num_comv;
 };
 
 enum platform_inst_fw_cap_type {
@@ -151,6 +152,10 @@ struct iris_platform_data {
        unsigned int dec_input_prop_size;
        const u32 *dec_output_prop;
        unsigned int dec_output_prop_size;
+       const u32 *dec_ip_int_buf_tbl;
+       unsigned int dec_ip_int_buf_tbl_size;
+       const u32 *dec_op_int_buf_tbl;
+       unsigned int dec_op_int_buf_tbl_size;
 };
 
 #endif
diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c 
b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c
index 703e48802795..dc51df71c377 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c
@@ -126,6 +126,7 @@ static struct platform_inst_caps platform_inst_cap_sm8550 = 
{
        .min_frame_height = 96,
        .max_frame_height = 8192,
        .max_mbpf = (8192 * 4352) / 256,
+       .num_comv = 0,
 };
 
 static void iris_set_sm8550_preset_registers(struct iris_core *core)
@@ -192,6 +193,17 @@ static const u32 sm8550_vdec_subscribe_output_properties[] 
= {
        HFI_PROP_CABAC_SESSION,
 };
 
+static const u32 sm8550_dec_ip_int_buf_tbl[] = {
+       BUF_BIN,
+       BUF_COMV,
+       BUF_NON_COMV,
+       BUF_LINE,
+};
+
+static const u32 sm8550_dec_op_int_buf_tbl[] = {
+       BUF_DPB,
+};
+
 struct iris_platform_data sm8550_data = {
        .get_instance = iris_hfi_gen2_get_instance,
        .init_hfi_command_ops = iris_hfi_gen2_command_ops_init,
@@ -233,4 +245,9 @@ struct iris_platform_data sm8550_data = {
        .dec_input_prop_size = 
ARRAY_SIZE(sm8550_vdec_subscribe_input_properties),
        .dec_output_prop = sm8550_vdec_subscribe_output_properties,
        .dec_output_prop_size = 
ARRAY_SIZE(sm8550_vdec_subscribe_output_properties),
+
+       .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl,
+       .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl),
+       .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl,
+       .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl),
 };
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c 
b/drivers/media/platform/qcom/iris/iris_vdec.c
index 13902f4e9724..8d489530da31 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -273,6 +273,24 @@ int iris_vdec_streamon_input(struct iris_inst *inst)
        if (ret)
                return ret;
 
+       ret = iris_alloc_and_queue_persist_bufs(inst);
+       if (ret)
+               return ret;
+
+       iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+       ret = iris_destroy_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       if (ret)
+               return ret;
+
+       ret = iris_create_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       if (ret)
+               return ret;
+
+       ret = iris_queue_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       if (ret)
+               return ret;
+
        return iris_vdec_process_streamon_input(inst);
 }
 
@@ -297,10 +315,24 @@ int iris_vdec_streamon_output(struct iris_inst *inst)
        if (ret)
                return ret;
 
+       iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+       ret = iris_destroy_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       if (ret)
+               return ret;
+
+       ret = iris_create_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       if (ret)
+               return ret;
+
        ret = iris_vdec_process_streamon_output(inst);
        if (ret)
                goto error;
 
+       ret = iris_queue_internal_buffers(inst, 
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       if (ret)
+               goto error;
+
        return ret;
 
 error:
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c 
b/drivers/media/platform/qcom/iris/iris_vidc.c
index 1d10c430c795..ec5694c1c8de 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -149,6 +149,15 @@ int iris_open(struct file *filp)
 
        mutex_init(&inst->lock);
        mutex_init(&inst->ctx_q_lock);
+
+       INIT_LIST_HEAD(&inst->buffers[BUF_BIN].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_ARP].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_COMV].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_NON_COMV].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_LINE].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_DPB].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_PERSIST].list);
+       INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_1].list);
        init_completion(&inst->completion);
        init_completion(&inst->flush_completion);
 
@@ -221,6 +230,8 @@ int iris_close(struct file *filp)
        iris_session_close(inst);
        iris_inst_change_state(inst, IRIS_INST_DEINIT);
        iris_v4l2_fh_deinit(inst);
+       iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
        iris_remove_session(inst);
        mutex_unlock(&inst->lock);
        mutex_destroy(&inst->ctx_q_lock);
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c 
b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
index 0a65a17f13d2..dce25e410d80 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
@@ -6,7 +6,167 @@
 #include "iris_instance.h"
 #include "iris_vpu_buffer.h"
 
-u32 iris_vpu_dec_dpb_size(struct iris_inst *inst)
+static u32 size_h264d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 
num_vpp_pipes)
+{
+       u32 size_yuv, size_bin_hdr, size_bin_res;
+
+       size_yuv = ((frame_width * frame_height) <= BIN_BUFFER_THRESHOLD) ?
+                       ((BIN_BUFFER_THRESHOLD * 3) >> 1) :
+                       ((frame_width * frame_height * 3) >> 1);
+       size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT;
+       size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT;
+       size_bin_hdr = ALIGN(size_bin_hdr / num_vpp_pipes,
+                            DMA_ALIGNMENT) * num_vpp_pipes;
+       size_bin_res = ALIGN(size_bin_res / num_vpp_pipes,
+                            DMA_ALIGNMENT) * num_vpp_pipes;
+
+       return size_bin_hdr + size_bin_res;
+}
+
+static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 
num_vpp_pipes)
+{
+       u32 n_aligned_h = ALIGN(frame_height, 16);
+       u32 n_aligned_w = ALIGN(frame_width, 16);
+
+       return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, 
num_vpp_pipes);
+}
+
+static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 
_comv_bufcount)
+{
+       u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16);
+       u32 frame_width_in_mbs = DIV_ROUND_UP(frame_width, 16);
+       u32 col_zero_aligned_width = (frame_width_in_mbs << 2);
+       u32 col_mv_aligned_width = (frame_width_in_mbs << 7);
+       u32 col_zero_size, size_colloc;
+
+       col_mv_aligned_width = ALIGN(col_mv_aligned_width, 16);
+       col_zero_aligned_width = ALIGN(col_zero_aligned_width, 16);
+       col_zero_size = col_zero_aligned_width *
+                       ((frame_height_in_mbs + 1) >> 1);
+       col_zero_size = ALIGN(col_zero_size, 64);
+       col_zero_size <<= 1;
+       col_zero_size = ALIGN(col_zero_size, 512);
+       size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + 1) >> 1);
+       size_colloc = ALIGN(size_colloc, 64);
+       size_colloc <<= 1;
+       size_colloc = ALIGN(size_colloc, 512);
+       size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2);
+
+       return (size_colloc * (_comv_bufcount)) + 512;
+}
+
+static u32 size_h264d_bse_cmd_buf(u32 frame_height)
+{
+       u32 height = ALIGN(frame_height, 32);
+
+       return min_t(u32, (DIV_ROUND_UP(height, 16) * 48), H264D_MAX_SLICE) *
+               SIZE_H264D_BSE_CMD_PER_BUF;
+}
+
+static u32 size_h264d_vpp_cmd_buf(u32 frame_height)
+{
+       u32 size, height = ALIGN(frame_height, 32);
+
+       size = min_t(u32, (DIV_ROUND_UP(height, 16) * 48), H264D_MAX_SLICE) *
+                       SIZE_H264D_VPP_CMD_PER_BUF;
+
+       return size > VPP_CMD_MAX_SIZE ? VPP_CMD_MAX_SIZE : size;
+}
+
+static u32 hfi_buffer_persist_h264d(void)
+{
+       return ALIGN(SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 +
+                   H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO +
+                   NUM_HW_PIC_BUF * SIZE_SEI_USERDATA,
+                   DMA_ALIGNMENT);
+}
+
+static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 
num_vpp_pipes)
+{
+       u32 size_bse, size_vpp, size;
+
+       size_bse = size_h264d_bse_cmd_buf(frame_height);
+       size_vpp = size_h264d_vpp_cmd_buf(frame_height);
+       size = ALIGN(size_bse, DMA_ALIGNMENT) +
+               ALIGN(size_vpp, DMA_ALIGNMENT) +
+               ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT);
+
+       return ALIGN(size, DMA_ALIGNMENT);
+}
+
+static u32 size_vpss_lb(u32 frame_width, u32 frame_height)
+{
+       u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size;
+       u32 opb_wr_top_line_chroma_buffer_size;
+       u32 opb_wr_top_line_luma_buffer_size;
+       u32 macrotiling_size = 32;
+
+       opb_wr_top_line_luma_buffer_size =
+               ALIGN(frame_width, macrotiling_size) / macrotiling_size * 256;
+       opb_wr_top_line_luma_buffer_size =
+               ALIGN(opb_wr_top_line_luma_buffer_size, DMA_ALIGNMENT) +
+               (MAX_TILE_COLUMNS - 1) * 256;
+       opb_wr_top_line_luma_buffer_size =
+               max_t(u32, opb_wr_top_line_luma_buffer_size, (32 * 
ALIGN(frame_height, 8)));
+       opb_wr_top_line_chroma_buffer_size = opb_wr_top_line_luma_buffer_size;
+       opb_lb_wr_llb_uv_buffer_size =
+               ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, 32);
+       opb_lb_wr_llb_y_buffer_size =
+               ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, 32);
+       return opb_wr_top_line_luma_buffer_size +
+               opb_wr_top_line_chroma_buffer_size +
+               opb_lb_wr_llb_uv_buffer_size +
+               opb_lb_wr_llb_y_buffer_size;
+}
+
+static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height,
+                                bool is_opb, u32 num_vpp_pipes)
+{
+       u32 vpss_lb_size = 0;
+       u32 size;
+
+       size = ALIGN(size_h264d_lb_fe_top_data(frame_width), DMA_ALIGNMENT) +
+               ALIGN(size_h264d_lb_fe_top_ctrl(frame_width), DMA_ALIGNMENT) +
+               ALIGN(size_h264d_lb_fe_left_ctrl(frame_height), DMA_ALIGNMENT) 
* num_vpp_pipes +
+               ALIGN(size_h264d_lb_se_top_ctrl(frame_width), DMA_ALIGNMENT) +
+               ALIGN(size_h264d_lb_se_left_ctrl(frame_height), DMA_ALIGNMENT) 
* num_vpp_pipes +
+               ALIGN(size_h264d_lb_pe_top_data(frame_width), DMA_ALIGNMENT) +
+               ALIGN(size_h264d_lb_vsp_top(frame_width), DMA_ALIGNMENT) +
+               ALIGN(size_h264d_lb_recon_dma_metadata_wr(frame_height), 
DMA_ALIGNMENT) * 2 +
+               ALIGN(size_h264d_qp(frame_width, frame_height), DMA_ALIGNMENT);
+       size = ALIGN(size, DMA_ALIGNMENT);
+       if (is_opb)
+               vpss_lb_size = size_vpss_lb(frame_width, frame_height);
+
+       return ALIGN((size + vpss_lb_size), DMA_ALIGNMENT);
+}
+
+static u32 iris_vpu_dec_bin_size(struct iris_inst *inst)
+{
+       u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
+       struct v4l2_format *f = inst->fmt_src;
+       u32 height = f->fmt.pix_mp.height;
+       u32 width = f->fmt.pix_mp.width;
+
+       return hfi_buffer_bin_h264d(width, height, num_vpp_pipes);
+}
+
+static u32 iris_vpu_dec_comv_size(struct iris_inst *inst)
+{
+       u32 num_comv = VIDEO_MAX_FRAME;
+       struct v4l2_format *f = inst->fmt_src;
+       u32 height = f->fmt.pix_mp.height;
+       u32 width = f->fmt.pix_mp.width;
+
+       return hfi_buffer_comv_h264d(width, height, num_comv);
+}
+
+static u32 iris_vpu_dec_persist_size(struct iris_inst *inst)
+{
+       return hfi_buffer_persist_h264d();
+}
+
+static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst)
 {
        if (iris_split_mode_enabled(inst))
                return iris_get_buffer_size(inst, BUF_DPB);
@@ -14,6 +174,70 @@ u32 iris_vpu_dec_dpb_size(struct iris_inst *inst)
                return 0;
 }
 
+static u32 iris_vpu_dec_non_comv_size(struct iris_inst *inst)
+{
+       u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
+       struct v4l2_format *f = inst->fmt_src;
+       u32 height = f->fmt.pix_mp.height;
+       u32 width = f->fmt.pix_mp.width;
+
+       return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes);
+}
+
+static u32 iris_vpu_dec_line_size(struct iris_inst *inst)
+{
+       u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
+       struct v4l2_format *f = inst->fmt_src;
+       u32 height = f->fmt.pix_mp.height;
+       u32 width = f->fmt.pix_mp.width;
+       bool is_opb = false;
+
+       if (iris_split_mode_enabled(inst))
+               is_opb = true;
+
+       return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes);
+}
+
+static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst)
+{
+       return iris_vpu_dec_comv_size(inst) +
+               iris_vpu_dec_non_comv_size(inst) +
+               iris_vpu_dec_line_size(inst);
+}
+
+struct iris_vpu_buf_type_handle {
+       enum iris_buffer_type type;
+       u32 (*handle)(struct iris_inst *inst);
+};
+
+int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type 
buffer_type)
+{
+       const struct iris_vpu_buf_type_handle *buf_type_handle_arr;
+       u32 size = 0, buf_type_handle_size, i;
+
+       static const struct iris_vpu_buf_type_handle 
dec_internal_buf_type_handle[] = {
+               {BUF_BIN,         iris_vpu_dec_bin_size             },
+               {BUF_COMV,        iris_vpu_dec_comv_size            },
+               {BUF_NON_COMV,    iris_vpu_dec_non_comv_size        },
+               {BUF_LINE,        iris_vpu_dec_line_size            },
+               {BUF_PERSIST,     iris_vpu_dec_persist_size         },
+               {BUF_DPB,         iris_vpu_dec_dpb_size             },
+               {BUF_SCRATCH_1,   iris_vpu_dec_scratch1_size        },
+       };
+
+       buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle);
+       buf_type_handle_arr = dec_internal_buf_type_handle;
+
+       for (i = 0; i < buf_type_handle_size; i++) {
+               if (buf_type_handle_arr[i].type == buffer_type) {
+                       size = buf_type_handle_arr[i].handle(inst);
+                       break;
+               }
+       }
+
+       return size;
+}
+
 static inline int iris_vpu_dpb_count(struct iris_inst *inst)
 {
        if (iris_split_mode_enabled(inst)) {
@@ -31,6 +255,13 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum 
iris_buffer_type buffer_type
                return MIN_BUFFERS;
        case BUF_OUTPUT:
                return inst->fw_min_count;
+       case BUF_BIN:
+       case BUF_COMV:
+       case BUF_NON_COMV:
+       case BUF_LINE:
+       case BUF_PERSIST:
+       case BUF_SCRATCH_1:
+               return 1; /* internal buffer count needed by firmware is 1 */
        case BUF_DPB:
                return iris_vpu_dpb_count(inst);
        default:
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h 
b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
index 865539d626b7..62af6ea6ba1f 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
@@ -10,7 +10,82 @@ struct iris_inst;
 
 #define MIN_BUFFERS                    4
 
-u32 iris_vpu_dec_dpb_size(struct iris_inst *inst);
+#define DMA_ALIGNMENT                  256
+
+#define NUM_HW_PIC_BUF                 32
+#define SIZE_HW_PIC(size_per_buf)      (NUM_HW_PIC_BUF * (size_per_buf))
+
+#define MAX_TILE_COLUMNS               32
+#define BIN_BUFFER_THRESHOLD           (1280 * 736)
+#define VPP_CMD_MAX_SIZE               (BIT(20))
+#define H264D_MAX_SLICE                        1800
+
+#define SIZE_H264D_BUFTAB_T            256
+#define SIZE_H264D_BSE_CMD_PER_BUF     (32 * 4)
+#define SIZE_H264D_VPP_CMD_PER_BUF     512
+
+#define NUM_SLIST_BUF_H264             (256 + 32)
+#define SIZE_SLIST_BUF_H264            512
+#define H264_DISPLAY_BUF_SIZE          3328
+#define H264_NUM_FRM_INFO              66
+
+#define SIZE_SEI_USERDATA              4096
+
+#define H264_CABAC_HDR_RATIO_HD_TOT    1
+#define H264_CABAC_RES_RATIO_HD_TOT    3
+#define SIZE_H264D_HW_PIC_T            (BIT(11))
+
+#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64
+#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 16
+#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384
+#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE  640
+
+static inline u32 size_h264d_lb_fe_top_data(u32 frame_width)
+{
+       return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * ALIGN(frame_width, 16) * 
3;
+}
+
+static inline u32 size_h264d_lb_fe_top_ctrl(u32 frame_width)
+{
+       return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * 
DIV_ROUND_UP(frame_width, 16);
+}
+
+static inline u32 size_h264d_lb_fe_left_ctrl(u32 frame_height)
+{
+       return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * 
DIV_ROUND_UP(frame_height, 16);
+}
+
+static inline u32 size_h264d_lb_se_top_ctrl(u32 frame_width)
+{
+       return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * 
DIV_ROUND_UP(frame_width, 16);
+}
+
+static inline u32 size_h264d_lb_se_left_ctrl(u32 frame_height)
+{
+       return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * 
DIV_ROUND_UP(frame_height, 16);
+}
+
+static inline u32 size_h264d_lb_pe_top_data(u32 frame_width)
+{
+       return MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * 
DIV_ROUND_UP(frame_width, 16);
+}
+
+static inline u32 size_h264d_lb_vsp_top(u32 frame_width)
+{
+       return (DIV_ROUND_UP(frame_width, 16) << 7);
+}
+
+static inline u32 size_h264d_lb_recon_dma_metadata_wr(u32 frame_height)
+{
+       return ALIGN(frame_height, 16) * 32;
+}
+
+static inline u32 size_h264d_qp(u32 frame_width, u32 frame_height)
+{
+       return DIV_ROUND_UP(frame_width, 64) * DIV_ROUND_UP(frame_height, 64) * 
128;
+}
+
+int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type 
buffer_type);
 int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type 
buffer_type);
 
 #endif

Reply via email to