Files
linux-stable-mirror/drivers/media/platform/qcom/iris/iris_common.c
T
Dikshita Agarwal 8cefa0ac93 media: iris: Add support for buffer management ioctls for encoder device
Implement support for queuing and dequeuing input and output buffers
for the encoder video device using the appropriate V4L2 buffer
management ioctls.

This enables userspace applications to manage streaming buffers
required for encoding operations.

Tested-by: Vikash Garodia <quic_vgarodia@quicinc.com> # X1E80100
Reviewed-by: Vikash Garodia <quic_vgarodia@quicinc.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-HDK
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # x1e80100-crd
[bod: drop dead code size_enc_single_pipe()]
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
2025-09-10 09:02:46 +02:00

233 lines
5.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <media/v4l2-mem2mem.h>
#include "iris_common.h"
#include "iris_ctrls.h"
#include "iris_instance.h"
#include "iris_power.h"
int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
buf->type = iris_v4l2_type_to_driver(vb2->type);
buf->index = vb2->index;
buf->fd = vb2->planes[0].m.fd;
buf->buffer_size = vb2->planes[0].length;
buf->data_offset = vb2->planes[0].data_offset;
buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset;
buf->flags = vbuf->flags;
buf->timestamp = vb2->timestamp;
buf->attr = 0;
return 0;
}
void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf)
{
u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
struct vb2_buffer *vb = &vbuf->vb2_buf;
u64 ts_us = vb->timestamp;
if (inst->metadata_idx >= ARRAY_SIZE(inst->tss))
inst->metadata_idx = 0;
do_div(ts_us, NSEC_PER_USEC);
inst->tss[inst->metadata_idx].flags = vbuf->flags & mask;
inst->tss[inst->metadata_idx].tc = vbuf->timecode;
inst->tss[inst->metadata_idx].ts_us = ts_us;
inst->tss[inst->metadata_idx].ts_ns = vb->timestamp;
inst->metadata_idx++;
}
int iris_process_streamon_input(struct iris_inst *inst)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
enum iris_inst_sub_state set_sub_state = 0;
int ret;
iris_scale_power(inst);
ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (ret)
return ret;
if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0);
if (ret)
return ret;
}
if (inst->domain == DECODER &&
(inst->sub_state & IRIS_INST_SUB_DRC ||
inst->sub_state & IRIS_INST_SUB_DRAIN ||
inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) {
if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) {
if (hfi_ops->session_pause) {
ret = hfi_ops->session_pause(inst,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (ret)
return ret;
}
set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
}
}
ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (ret)
return ret;
inst->last_buffer_dequeued = false;
return iris_inst_change_sub_state(inst, 0, set_sub_state);
}
int iris_process_streamon_output(struct iris_inst *inst)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
bool drain_active = false, drc_active = false;
enum iris_inst_sub_state clear_sub_state = 0;
int ret = 0;
iris_scale_power(inst);
drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN &&
inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
drc_active = inst->sub_state & IRIS_INST_SUB_DRC &&
inst->sub_state & IRIS_INST_SUB_DRC_LAST;
if (drc_active)
clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
else if (drain_active)
clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
ret = iris_alloc_and_queue_input_int_bufs(inst);
if (ret)
return ret;
ret = iris_set_stage(inst, STAGE);
if (ret)
return ret;
ret = iris_set_pipe(inst, PIPE);
if (ret)
return ret;
}
if (inst->state == IRIS_INST_INPUT_STREAMING &&
inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
if (!drain_active)
ret = hfi_ops->session_resume_drc(inst,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
else if (hfi_ops->session_resume_drain)
ret = hfi_ops->session_resume_drain(inst,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
if (ret)
return ret;
clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
}
if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)
clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC;
ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (ret)
return ret;
if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE)
clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (ret)
return ret;
inst->last_buffer_dequeued = false;
return iris_inst_change_sub_state(inst, clear_sub_state, 0);
}
static void iris_flush_deferred_buffers(struct iris_inst *inst,
enum iris_buffer_type type)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
struct v4l2_m2m_buffer *buffer, *n;
struct iris_buffer *buf;
if (type == BUF_INPUT) {
v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) {
buf = to_iris_buffer(&buffer->vb);
if (buf->attr & BUF_ATTR_DEFERRED) {
if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
buf->attr |= BUF_ATTR_BUFFER_DONE;
buf->data_size = 0;
iris_vb2_buffer_done(inst, buf);
}
}
}
} else {
v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) {
buf = to_iris_buffer(&buffer->vb);
if (buf->attr & BUF_ATTR_DEFERRED) {
if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
buf->attr |= BUF_ATTR_BUFFER_DONE;
buf->data_size = 0;
iris_vb2_buffer_done(inst, buf);
}
}
}
}
}
static void iris_kill_session(struct iris_inst *inst)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
if (!inst->session_id)
return;
hfi_ops->session_close(inst);
iris_inst_change_state(inst, IRIS_INST_ERROR);
}
int iris_session_streamoff(struct iris_inst *inst, u32 plane)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
enum iris_buffer_type buffer_type;
int ret;
switch (plane) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
buffer_type = BUF_INPUT;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
buffer_type = BUF_OUTPUT;
break;
default:
return -EINVAL;
}
ret = hfi_ops->session_stop(inst, plane);
if (ret)
goto error;
ret = iris_inst_state_change_streamoff(inst, plane);
if (ret)
goto error;
iris_flush_deferred_buffers(inst, buffer_type);
return 0;
error:
iris_kill_session(inst);
iris_flush_deferred_buffers(inst, buffer_type);
return ret;
}