Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6#include <media/v4l2-mem2mem.h>
7
8#include "iris_common.h"
9#include "iris_ctrls.h"
10#include "iris_instance.h"
11#include "iris_power.h"
12
13int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf)
14{
15 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
16
17 buf->type = iris_v4l2_type_to_driver(vb2->type);
18 buf->index = vb2->index;
19 buf->fd = vb2->planes[0].m.fd;
20 buf->buffer_size = vb2->planes[0].length;
21 buf->data_offset = vb2->planes[0].data_offset;
22 buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset;
23 buf->flags = vbuf->flags;
24 buf->timestamp = vb2->timestamp;
25 buf->attr = 0;
26
27 return 0;
28}
29
30void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf)
31{
32 u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
33 struct vb2_buffer *vb = &vbuf->vb2_buf;
34 u64 ts_us = vb->timestamp;
35
36 if (inst->metadata_idx >= ARRAY_SIZE(inst->tss))
37 inst->metadata_idx = 0;
38
39 do_div(ts_us, NSEC_PER_USEC);
40
41 inst->tss[inst->metadata_idx].flags = vbuf->flags & mask;
42 inst->tss[inst->metadata_idx].tc = vbuf->timecode;
43 inst->tss[inst->metadata_idx].ts_us = ts_us;
44 inst->tss[inst->metadata_idx].ts_ns = vb->timestamp;
45
46 inst->metadata_idx++;
47}
48
49int iris_process_streamon_input(struct iris_inst *inst)
50{
51 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
52 enum iris_inst_sub_state set_sub_state = 0;
53 int ret;
54
55 iris_scale_power(inst);
56
57 ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
58 if (ret)
59 return ret;
60
61 if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
62 ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0);
63 if (ret)
64 return ret;
65 }
66
67 if (inst->domain == DECODER &&
68 (inst->sub_state & IRIS_INST_SUB_DRC ||
69 inst->sub_state & IRIS_INST_SUB_DRAIN ||
70 inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) {
71 if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) {
72 if (hfi_ops->session_pause) {
73 ret = hfi_ops->session_pause(inst,
74 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
75 if (ret)
76 return ret;
77 }
78 set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
79 }
80 }
81
82 ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
83 if (ret)
84 return ret;
85
86 inst->last_buffer_dequeued = false;
87
88 return iris_inst_change_sub_state(inst, 0, set_sub_state);
89}
90
91int iris_process_streamon_output(struct iris_inst *inst)
92{
93 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
94 enum iris_inst_sub_state clear_sub_state = 0;
95 bool drain_active, drc_active, first_ipsc;
96 int ret = 0;
97
98 iris_scale_power(inst);
99
100 first_ipsc = inst->sub_state & IRIS_INST_SUB_FIRST_IPSC;
101
102 drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN &&
103 inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
104
105 drc_active = inst->sub_state & IRIS_INST_SUB_DRC &&
106 inst->sub_state & IRIS_INST_SUB_DRC_LAST;
107
108 if (drc_active)
109 clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
110 else if (drain_active)
111 clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
112
113 /* Input internal buffer reconfiguration required in case of resolution change */
114 if (first_ipsc || drc_active) {
115 ret = iris_alloc_and_queue_input_int_bufs(inst);
116 if (ret)
117 return ret;
118 ret = iris_set_stage(inst, STAGE);
119 if (ret)
120 return ret;
121 ret = iris_set_pipe(inst, PIPE);
122 if (ret)
123 return ret;
124 }
125
126 if (inst->state == IRIS_INST_INPUT_STREAMING &&
127 inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
128 if (!drain_active)
129 ret = hfi_ops->session_resume_drc(inst,
130 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
131 else if (hfi_ops->session_resume_drain)
132 ret = hfi_ops->session_resume_drain(inst,
133 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
134 if (ret)
135 return ret;
136 clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
137 }
138
139 if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)
140 clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC;
141
142 ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
143 if (ret)
144 return ret;
145
146 if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE)
147 clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
148
149 ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
150 if (ret)
151 return ret;
152
153 inst->last_buffer_dequeued = false;
154
155 return iris_inst_change_sub_state(inst, clear_sub_state, 0);
156}
157
158static void iris_flush_deferred_buffers(struct iris_inst *inst,
159 enum iris_buffer_type type)
160{
161 struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
162 struct v4l2_m2m_buffer *buffer, *n;
163 struct iris_buffer *buf;
164
165 if (type == BUF_INPUT) {
166 v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) {
167 buf = to_iris_buffer(&buffer->vb);
168 if (buf->attr & BUF_ATTR_DEFERRED) {
169 if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
170 buf->attr |= BUF_ATTR_BUFFER_DONE;
171 buf->data_size = 0;
172 iris_vb2_buffer_done(inst, buf);
173 }
174 }
175 }
176 } else {
177 v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) {
178 buf = to_iris_buffer(&buffer->vb);
179 if (buf->attr & BUF_ATTR_DEFERRED) {
180 if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
181 buf->attr |= BUF_ATTR_BUFFER_DONE;
182 buf->data_size = 0;
183 iris_vb2_buffer_done(inst, buf);
184 }
185 }
186 }
187 }
188}
189
190static void iris_kill_session(struct iris_inst *inst)
191{
192 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
193
194 if (!inst->session_id)
195 return;
196
197 hfi_ops->session_close(inst);
198 iris_inst_change_state(inst, IRIS_INST_ERROR);
199}
200
201int iris_session_streamoff(struct iris_inst *inst, u32 plane)
202{
203 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
204 enum iris_buffer_type buffer_type;
205 int ret;
206
207 switch (plane) {
208 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
209 buffer_type = BUF_INPUT;
210 break;
211 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
212 buffer_type = BUF_OUTPUT;
213 break;
214 default:
215 return -EINVAL;
216 }
217
218 ret = hfi_ops->session_stop(inst, plane);
219 if (ret)
220 goto error;
221
222 ret = iris_inst_state_change_streamoff(inst, plane);
223 if (ret)
224 goto error;
225
226 iris_flush_deferred_buffers(inst, buffer_type);
227
228 return 0;
229
230error:
231 iris_kill_session(inst);
232 iris_flush_deferred_buffers(inst, buffer_type);
233
234 return ret;
235}