[PATCH v4 5/5] media: iris: Add BUF_ROIMB_DELTAQP metadata buffer for ROI delta QP
From: Deepa Guthyappa Madivalara
Date: Tue Aug 11 2026 - 14:33:51 EST
- Introduce BUF_ROIMB_DELTAQP as a new internal buffer type to carry
per-macroblock ROI delta QP data to the firmware. This buffer is
allocated on demand when the application sets ROI parameters via
V4L2_CID_MPEG_VIDEO_ROI_MB_DELTA_QP, and is queued alongside each
raw input buffer as an HFI_BUFFER_METADATA packet on HFI_PORT_RAW.
- The metadata buffer layout follows the firmware-defined metabuf_header
and metapayload_header structures. The s8 per-MB delta QP values
supplied by userspace are widened to s16 as required by the firmware.
Signed-off-by: Deepa Guthyappa Madivalara <deepa.madivalara@xxxxxxxxxxxxxxxx>
---
drivers/media/platform/qcom/iris/iris_buffer.c | 98 ++++++++++++++++++++++
drivers/media/platform/qcom/iris/iris_buffer.h | 4 +
.../platform/qcom/iris/iris_hfi_gen2_command.c | 23 +++++
.../platform/qcom/iris/iris_hfi_gen2_response.c | 2 +
drivers/media/platform/qcom/iris/iris_vidc.c | 2 +
5 files changed, 129 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c
index eb8de60c1177f5e1ab83b90a3c8c80e0b4d1f02e..e7283a5054f685741bb55d5545a6c11188861b5d 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_buffer.c
@@ -5,11 +5,13 @@
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
+#include <linux/slab.h>
#include "iris_buffer.h"
#include "iris_instance.h"
#include "iris_power.h"
#include "iris_vpu_buffer.h"
+#include "iris_hfi_gen2_defines.h"
#define PIXELS_4K 4096
#define MAX_WIDTH 4096
@@ -705,6 +707,19 @@ int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane)
return iris_destroy_internal_buffers(inst, plane, false);
}
+int iris_destroy_roi_metadata_buffers(struct iris_inst *inst)
+{
+ struct iris_buffer *buf, *next;
+ struct iris_buffers *buffers;
+
+ if (inst->domain == ENCODER) {
+ buffers = &inst->buffers[BUF_ROIMB_DELTAQP];
+ list_for_each_entry_safe(buf, next, &buffers->list, list)
+ iris_destroy_internal_buffer(inst, buf);
+ }
+
+ return 0;
+}
static int iris_release_internal_buffers(struct iris_inst *inst,
enum iris_buffer_type buffer_type)
{
@@ -928,3 +943,86 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf)
return 0;
}
+
+static int iris_fill_roi_data(struct iris_inst *inst, struct iris_buffer *buffer)
+{
+ s8 *p_array = (s8 *)inst->fw_caps[ROI_PARAMS].p_array;
+ u32 array_size = inst->fw_caps[ROI_PARAMS].elems;
+ struct metabuf_header *mbuf_hdr = buffer->kvaddr;
+ struct metapayload_header *mbuf_payload_hdr;
+ s16 *p_16;
+ u32 payload_offset;
+
+ memset(mbuf_hdr, 0, sizeof(struct metabuf_header));
+ mbuf_hdr->count = 1;
+ mbuf_hdr->size = sizeof(struct metabuf_header) +
+ sizeof(struct metapayload_header);
+ mbuf_hdr->version = BIT(16);
+ mbuf_hdr++;
+ mbuf_payload_hdr = (struct metapayload_header *)(mbuf_hdr);
+ payload_offset = sizeof(struct metabuf_header) +
+ sizeof(struct metapayload_header);
+
+ memset(mbuf_payload_hdr, 0, sizeof(struct metapayload_header));
+ mbuf_payload_hdr->type = HFI_PROP_ROI_INFO;
+ mbuf_payload_hdr->size = array_size * sizeof(s16);
+ mbuf_payload_hdr->version = 1 << 16;
+ mbuf_payload_hdr->offset = ALIGN(payload_offset, (u32)256);
+ mbuf_payload_hdr->flags = 0;
+
+ /* Firmware expects 2bytes of delta_Qp, int16_t */
+ p_16 = buffer->kvaddr + mbuf_payload_hdr->offset;
+ for (int i = 0; i < array_size; i++)
+ p_16[i] = p_array[i];
+
+ return 0;
+}
+
+int iris_hfi_gen2_session_alloc_roi_metadata_buffer(struct iris_inst *inst)
+{
+ struct iris_buffers *buffers = &inst->buffers[BUF_ROIMB_DELTAQP];
+ struct iris_core *core = inst->core;
+ struct iris_buffer *buffer, *first_buffer, *next;
+ bool found = false;
+ int ret = 0;
+
+ if (!buffers->size)
+ return 0;
+
+ list_for_each_entry_safe(buffer, next, &buffers->list, list) {
+ if (buffer->attr & BUF_ATTR_DEQUEUED) {
+ buffer->attr &= ~BUF_ATTR_DEQUEUED;
+ list_move(&buffer->list, &buffers->list);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ buffer = kzalloc_obj(*buffer);
+ if (!buffer)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&buffer->list);
+ buffer->type = BUF_ROIMB_DELTAQP;
+ buffer->index++;
+ buffer->buffer_size = buffers->size;
+ buffer->dma_attrs = DMA_ATTR_WRITE_COMBINE;
+
+ buffer->kvaddr = dma_alloc_attrs(core->dev, buffer->buffer_size,
+ &buffer->device_addr, GFP_KERNEL,
+ buffer->dma_attrs);
+
+ if (!buffer->kvaddr) {
+ kfree(buffer);
+ return -ENOMEM;
+ }
+ list_add(&buffer->list, &buffers->list);
+ }
+
+ first_buffer = list_first_entry(&buffers->list, struct iris_buffer, list);
+ ret = iris_fill_roi_data(inst, first_buffer);
+ if (ret)
+ return ret;
+
+ return ret;
+}
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h
index ee2d24bb69c57220b0a735d9b4aae4434a33daf6..df9d018493f3ec37fd5e6b0ba049dba0b5ae76e9 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_buffer.h
@@ -28,6 +28,7 @@ struct iris_inst;
* @BUF_SCRATCH_2: buffer to store encoding context data for HW
* @BUF_VPSS: buffer to store VPSS context data for HW
* @BUF_PARTIAL: buffer for AV1 IBC data
+ * @BUF_ROIMB_DELTAQP: metadata buffer for ROI MB DeltaQp
* @BUF_TYPE_MAX: max buffer types
*/
enum iris_buffer_type {
@@ -44,6 +45,7 @@ enum iris_buffer_type {
BUF_SCRATCH_2,
BUF_VPSS,
BUF_PARTIAL,
+ BUF_ROIMB_DELTAQP,
BUF_TYPE_MAX,
};
@@ -139,5 +141,7 @@ int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf);
int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type);
int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf);
void iris_vb2_queue_error(struct iris_inst *inst);
+int iris_hfi_gen2_session_alloc_roi_metadata_buffer(struct iris_inst *inst);
+int iris_destroy_roi_metadata_buffers(struct iris_inst *inst);
#endif
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 c08926609a3b7f5bb63df369da519accdd490121..070335dba173231c191d0e5842d6e226a057aeaf 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
@@ -134,6 +134,7 @@ static u32 iris_hfi_gen2_get_port_from_buf_type(struct iris_inst *inst,
switch (buffer_type) {
case BUF_INPUT:
case BUF_VPSS:
+ case BUF_ROIMB_DELTAQP:
return HFI_PORT_RAW;
case BUF_OUTPUT:
case BUF_BIN:
@@ -1267,6 +1268,8 @@ static u32 iris_hfi_gen2_buf_type_from_driver(u32 domain, enum iris_buffer_type
return HFI_BUFFER_VPSS;
case BUF_PARTIAL:
return HFI_BUFFER_PARTIAL_DATA;
+ case BUF_ROIMB_DELTAQP:
+ return HFI_BUFFER_METADATA;
default:
return 0;
}
@@ -1349,7 +1352,27 @@ static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct iri
HFI_PAYLOAD_STRUCTURE,
&hfi_buffer,
sizeof(hfi_buffer));
+
+ /* check if any metadata buffer is available not queued, queueit */
+ if (port == HFI_PORT_RAW) {
+ buffer = iris_queue_metadata_buffers(inst, BUF_ROIMB_DELTAQP, buffer->index);
+ if (buffer) {
+ iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_meta_buffer);
+ port = iris_hfi_gen2_get_port_from_buf_type(inst, buffer->type);
+ iris_hfi_gen2_create_packet(inst_hfi_gen2->packet,
+ HFI_CMD_BUFFER,
+ HFI_HOST_FLAGS_INTR_REQUIRED,
+ HFI_PAYLOAD_STRUCTURE,
+ port,
+ inst->core->packet_id++,
+ &hfi_meta_buffer,
+ sizeof(hfi_meta_buffer));
+
+ buffer->attr |= BUF_ATTR_QUEUED;
+ buffer->attr &= ~BUF_ATTR_DEQUEUED;
+ }
}
+
return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
inst_hfi_gen2->packet->size);
}
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 84b629b957442c024dccc18b354ac9a7e541abaa..f63e0a7723e8583da818c2b004e367c1dd3d94f7 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
@@ -58,6 +58,8 @@ static u32 iris_hfi_gen2_buf_type_to_driver(struct iris_inst *inst,
return BUF_PARTIAL;
case HFI_BUFFER_VPSS:
return BUF_VPSS;
+ case HFI_BUFFER_METADATA:
+ return BUF_ROIMB_DELTAQP;
default:
return 0;
}
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index fcbc60016beec693f2ce27927a09a2d51494bc38..fae3d113a9dc990f06167ee0b7fb8fab24a0552c 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -180,6 +180,7 @@ int iris_open(struct file *filp)
INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_2].list);
INIT_LIST_HEAD(&inst->buffers[BUF_VPSS].list);
INIT_LIST_HEAD(&inst->buffers[BUF_PARTIAL].list);
+ INIT_LIST_HEAD(&inst->buffers[BUF_ROIMB_DELTAQP].list);
init_completion(&inst->completion);
init_completion(&inst->flush_completion);
@@ -299,6 +300,7 @@ int iris_close(struct file *filp)
iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ iris_destroy_roi_metadata_buffers(inst);
iris_remove_session(inst);
mutex_unlock(&inst->lock);
mutex_destroy(&inst->ctx_q_lock);
--
2.34.1