1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <media/videobuf2-dma-contig.h>
7 #include <media/v4l2-event.h>
8 #include <media/v4l2-mem2mem.h>
9 
10 #include "iris_instance.h"
11 #include "iris_vb2.h"
12 #include "iris_vdec.h"
13 
14 int iris_vb2_buf_init(struct vb2_buffer *vb2)
15 {
16 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
17 	struct iris_buffer *buf = to_iris_buffer(vbuf);
18 
19 	buf->device_addr = vb2_dma_contig_plane_dma_addr(vb2, 0);
20 
21 	return 0;
22 }
23 
24 int iris_vb2_queue_setup(struct vb2_queue *q,
25 			 unsigned int *num_buffers, unsigned int *num_planes,
26 			 unsigned int sizes[], struct device *alloc_devs[])
27 {
28 	struct iris_inst *inst;
29 	struct iris_core *core;
30 	struct v4l2_format *f;
31 	int ret = 0;
32 
33 	inst = vb2_get_drv_priv(q);
34 
35 	mutex_lock(&inst->lock);
36 	if (inst->state == IRIS_INST_ERROR) {
37 		ret = -EBUSY;
38 		goto unlock;
39 	}
40 
41 	core = inst->core;
42 	f = V4L2_TYPE_IS_OUTPUT(q->type) ? inst->fmt_src : inst->fmt_dst;
43 
44 	if (*num_planes) {
45 		if (*num_planes != f->fmt.pix_mp.num_planes ||
46 		    sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage)
47 			ret = -EINVAL;
48 		goto unlock;
49 	}
50 
51 	if (!inst->once_per_session_set) {
52 		inst->once_per_session_set = true;
53 
54 		ret = core->hfi_ops->session_open(inst);
55 		if (ret) {
56 			ret = -EINVAL;
57 			dev_err(core->dev, "session open failed\n");
58 			goto unlock;
59 		}
60 
61 		ret = iris_inst_change_state(inst, IRIS_INST_INIT);
62 		if (ret)
63 			goto unlock;
64 	}
65 
66 	*num_planes = 1;
67 	sizes[0] = f->fmt.pix_mp.plane_fmt[0].sizeimage;
68 
69 unlock:
70 	mutex_unlock(&inst->lock);
71 
72 	return ret;
73 }
74 
75 int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
76 {
77 	enum iris_buffer_type buf_type;
78 	struct iris_inst *inst;
79 	int ret = 0;
80 
81 	inst = vb2_get_drv_priv(q);
82 
83 	if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT)
84 		return 0;
85 
86 	mutex_lock(&inst->lock);
87 	if (inst->state == IRIS_INST_ERROR) {
88 		ret = -EBUSY;
89 		goto error;
90 	}
91 
92 	if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
93 	    !V4L2_TYPE_IS_CAPTURE(q->type)) {
94 		ret = -EINVAL;
95 		goto error;
96 	}
97 
98 	if (V4L2_TYPE_IS_OUTPUT(q->type))
99 		ret = iris_vdec_streamon_input(inst);
100 	else if (V4L2_TYPE_IS_CAPTURE(q->type))
101 		ret = iris_vdec_streamon_output(inst);
102 	if (ret)
103 		goto error;
104 
105 	buf_type = iris_v4l2_type_to_driver(q->type);
106 
107 	ret = iris_queue_deferred_buffers(inst, buf_type);
108 	if (ret)
109 		goto error;
110 
111 	mutex_unlock(&inst->lock);
112 
113 	return ret;
114 
115 error:
116 	iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED);
117 	iris_inst_change_state(inst, IRIS_INST_ERROR);
118 	mutex_unlock(&inst->lock);
119 
120 	return ret;
121 }
122 
123 void iris_vb2_stop_streaming(struct vb2_queue *q)
124 {
125 	struct iris_inst *inst;
126 	int ret = 0;
127 
128 	inst = vb2_get_drv_priv(q);
129 
130 	if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT)
131 		return;
132 
133 	mutex_lock(&inst->lock);
134 
135 	if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
136 	    !V4L2_TYPE_IS_CAPTURE(q->type))
137 		goto exit;
138 
139 	ret = iris_vdec_session_streamoff(inst, q->type);
140 	if (ret)
141 		goto exit;
142 
143 exit:
144 	iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR);
145 	if (ret)
146 		iris_inst_change_state(inst, IRIS_INST_ERROR);
147 
148 	mutex_unlock(&inst->lock);
149 }
150 
151 int iris_vb2_buf_prepare(struct vb2_buffer *vb)
152 {
153 	struct iris_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
154 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
155 
156 	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
157 		if (vbuf->field == V4L2_FIELD_ANY)
158 			vbuf->field = V4L2_FIELD_NONE;
159 		if (vbuf->field != V4L2_FIELD_NONE)
160 			return -EINVAL;
161 	}
162 
163 	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
164 	    vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT))
165 		return -EINVAL;
166 	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
167 	    vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT))
168 		return -EINVAL;
169 
170 	return 0;
171 }
172 
173 int iris_vb2_buf_out_validate(struct vb2_buffer *vb)
174 {
175 	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
176 
177 	v4l2_buf->field = V4L2_FIELD_NONE;
178 
179 	return 0;
180 }
181 
182 void iris_vb2_buf_queue(struct vb2_buffer *vb2)
183 {
184 	static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS };
185 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
186 	struct v4l2_m2m_ctx *m2m_ctx;
187 	struct iris_inst *inst;
188 	int ret = 0;
189 
190 	inst = vb2_get_drv_priv(vb2->vb2_queue);
191 
192 	mutex_lock(&inst->lock);
193 	if (inst->state == IRIS_INST_ERROR) {
194 		ret = -EBUSY;
195 		goto exit;
196 	}
197 
198 	if (vbuf->field == V4L2_FIELD_ANY)
199 		vbuf->field = V4L2_FIELD_NONE;
200 
201 	m2m_ctx = inst->m2m_ctx;
202 
203 	if (!vb2->planes[0].bytesused && V4L2_TYPE_IS_OUTPUT(vb2->type)) {
204 		ret = -EINVAL;
205 		goto exit;
206 	}
207 
208 	if (V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) {
209 		if ((inst->sub_state & IRIS_INST_SUB_DRC &&
210 		     inst->sub_state & IRIS_INST_SUB_DRC_LAST) ||
211 		    (inst->sub_state & IRIS_INST_SUB_DRAIN &&
212 		     inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)) {
213 			vbuf->flags |= V4L2_BUF_FLAG_LAST;
214 			vbuf->sequence = inst->sequence_cap++;
215 			vbuf->field = V4L2_FIELD_NONE;
216 			vb2_set_plane_payload(vb2, 0, 0);
217 			v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
218 			if (!v4l2_m2m_has_stopped(m2m_ctx)) {
219 				v4l2_event_queue_fh(&inst->fh, &eos);
220 				v4l2_m2m_mark_stopped(m2m_ctx);
221 			}
222 			goto exit;
223 		}
224 	}
225 
226 	v4l2_m2m_buf_queue(m2m_ctx, vbuf);
227 
228 	ret = iris_vdec_qbuf(inst, vbuf);
229 
230 exit:
231 	if (ret) {
232 		iris_inst_change_state(inst, IRIS_INST_ERROR);
233 		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
234 	}
235 	mutex_unlock(&inst->lock);
236 }
237