xref: /linux/drivers/media/platform/qcom/iris/iris_common.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
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 
13 int 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 
30 void 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 
49 int 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 
91 int 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 
158 static 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 
190 static 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 
201 int 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 
230 error:
231 	iris_kill_session(inst);
232 	iris_flush_deferred_buffers(inst, buffer_type);
233 
234 	return ret;
235 }
236