1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018 BayLibre, SAS
4  * Author: Maxime Jourdan <mjourdan@baylibre.com>
5  */
6 
7 #include <linux/gcd.h>
8 #include <media/v4l2-mem2mem.h>
9 #include <media/v4l2-event.h>
10 #include <media/videobuf2-dma-contig.h>
11 
12 #include "vdec_helpers.h"
13 
14 #define NUM_CANVAS_NV12 2
15 #define NUM_CANVAS_YUV420 3
16 
17 u32 amvdec_read_dos(struct amvdec_core *core, u32 reg)
18 {
19 	return readl_relaxed(core->dos_base + reg);
20 }
21 EXPORT_SYMBOL_GPL(amvdec_read_dos);
22 
23 void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val)
24 {
25 	writel_relaxed(val, core->dos_base + reg);
26 }
27 EXPORT_SYMBOL_GPL(amvdec_write_dos);
28 
29 void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
30 {
31 	amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val);
32 }
33 EXPORT_SYMBOL_GPL(amvdec_write_dos_bits);
34 
35 void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
36 {
37 	amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val);
38 }
39 EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits);
40 
41 u32 amvdec_read_parser(struct amvdec_core *core, u32 reg)
42 {
43 	return readl_relaxed(core->esparser_base + reg);
44 }
45 EXPORT_SYMBOL_GPL(amvdec_read_parser);
46 
47 void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
48 {
49 	writel_relaxed(val, core->esparser_base + reg);
50 }
51 EXPORT_SYMBOL_GPL(amvdec_write_parser);
52 
53 static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
54 {
55 	int ret;
56 
57 	if (sess->canvas_num >= MAX_CANVAS) {
58 		dev_err(sess->core->dev, "Reached max number of canvas\n");
59 		return -ENOMEM;
60 	}
61 
62 	ret = meson_canvas_alloc(sess->core->canvas, canvas_id);
63 	if (ret)
64 		return ret;
65 
66 	sess->canvas_alloc[sess->canvas_num++] = *canvas_id;
67 	return 0;
68 }
69 
70 static int set_canvas_yuv420m(struct amvdec_session *sess,
71 			      struct vb2_buffer *vb, u32 width,
72 			      u32 height, u32 reg)
73 {
74 	struct amvdec_core *core = sess->core;
75 	u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */
76 	dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */
77 	int ret, i;
78 
79 	for (i = 0; i < NUM_CANVAS_YUV420; ++i) {
80 		ret = canvas_alloc(sess, &canvas_id[i]);
81 		if (ret)
82 			return ret;
83 
84 		buf_paddr[i] =
85 		    vb2_dma_contig_plane_dma_addr(vb, i);
86 	}
87 
88 	/* Y plane */
89 	meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
90 			    width, height, MESON_CANVAS_WRAP_NONE,
91 			    MESON_CANVAS_BLKMODE_LINEAR,
92 			    MESON_CANVAS_ENDIAN_SWAP64);
93 
94 	/* U plane */
95 	meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
96 			    width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
97 			    MESON_CANVAS_BLKMODE_LINEAR,
98 			    MESON_CANVAS_ENDIAN_SWAP64);
99 
100 	/* V plane */
101 	meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2],
102 			    width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
103 			    MESON_CANVAS_BLKMODE_LINEAR,
104 			    MESON_CANVAS_ENDIAN_SWAP64);
105 
106 	amvdec_write_dos(core, reg,
107 			 ((canvas_id[2]) << 16) |
108 			 ((canvas_id[1]) << 8)  |
109 			 (canvas_id[0]));
110 
111 	return 0;
112 }
113 
114 static int set_canvas_nv12m(struct amvdec_session *sess,
115 			    struct vb2_buffer *vb, u32 width,
116 			    u32 height, u32 reg)
117 {
118 	struct amvdec_core *core = sess->core;
119 	u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */
120 	dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */
121 	int ret, i;
122 
123 	for (i = 0; i < NUM_CANVAS_NV12; ++i) {
124 		ret = canvas_alloc(sess, &canvas_id[i]);
125 		if (ret)
126 			return ret;
127 
128 		buf_paddr[i] =
129 		    vb2_dma_contig_plane_dma_addr(vb, i);
130 	}
131 
132 	/* Y plane */
133 	meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
134 			    width, height, MESON_CANVAS_WRAP_NONE,
135 			    MESON_CANVAS_BLKMODE_LINEAR,
136 			    MESON_CANVAS_ENDIAN_SWAP64);
137 
138 	/* U/V plane */
139 	meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
140 			    width, height / 2, MESON_CANVAS_WRAP_NONE,
141 			    MESON_CANVAS_BLKMODE_LINEAR,
142 			    MESON_CANVAS_ENDIAN_SWAP64);
143 
144 	amvdec_write_dos(core, reg,
145 			 ((canvas_id[1]) << 16) |
146 			 ((canvas_id[1]) << 8)  |
147 			 (canvas_id[0]));
148 
149 	return 0;
150 }
151 
152 int amvdec_set_canvases(struct amvdec_session *sess,
153 			u32 reg_base[], u32 reg_num[])
154 {
155 	struct v4l2_m2m_buffer *buf;
156 	u32 pixfmt = sess->pixfmt_cap;
157 	u32 width = ALIGN(sess->width, 64);
158 	u32 height = ALIGN(sess->height, 64);
159 	u32 reg_cur = reg_base[0];
160 	u32 reg_num_cur = 0;
161 	u32 reg_base_cur = 0;
162 	int i = 0;
163 	int ret;
164 
165 	v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
166 		if (!reg_base[reg_base_cur])
167 			return -EINVAL;
168 
169 		reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4;
170 
171 		switch (pixfmt) {
172 		case V4L2_PIX_FMT_NV12M:
173 			ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width,
174 					       height, reg_cur);
175 			if (ret)
176 				return ret;
177 			break;
178 		case V4L2_PIX_FMT_YUV420M:
179 			ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width,
180 						 height, reg_cur);
181 			if (ret)
182 				return ret;
183 			break;
184 		default:
185 			dev_err(sess->core->dev, "Unsupported pixfmt %08X\n",
186 				pixfmt);
187 			return -EINVAL;
188 		}
189 
190 		reg_num_cur++;
191 		if (reg_num_cur >= reg_num[reg_base_cur]) {
192 			reg_base_cur++;
193 			reg_num_cur = 0;
194 		}
195 
196 		sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index;
197 	}
198 
199 	return 0;
200 }
201 EXPORT_SYMBOL_GPL(amvdec_set_canvases);
202 
203 void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
204 {
205 	struct amvdec_timestamp *new_ts, *tmp;
206 	unsigned long flags;
207 
208 	new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
209 	new_ts->ts = ts;
210 	new_ts->offset = offset;
211 
212 	spin_lock_irqsave(&sess->ts_spinlock, flags);
213 
214 	if (list_empty(&sess->timestamps))
215 		goto add_tail;
216 
217 	list_for_each_entry(tmp, &sess->timestamps, list) {
218 		if (ts <= tmp->ts) {
219 			list_add_tail(&new_ts->list, &tmp->list);
220 			goto unlock;
221 		}
222 	}
223 
224 add_tail:
225 	list_add_tail(&new_ts->list, &sess->timestamps);
226 unlock:
227 	spin_unlock_irqrestore(&sess->ts_spinlock, flags);
228 }
229 EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
230 
231 void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
232 {
233 	struct amvdec_timestamp *tmp;
234 	unsigned long flags;
235 
236 	spin_lock_irqsave(&sess->ts_spinlock, flags);
237 	list_for_each_entry(tmp, &sess->timestamps, list) {
238 		if (tmp->ts == ts) {
239 			list_del(&tmp->list);
240 			kfree(tmp);
241 			goto unlock;
242 		}
243 	}
244 	dev_warn(sess->core->dev_dec,
245 		 "Couldn't remove buffer with timestamp %llu from list\n", ts);
246 
247 unlock:
248 	spin_unlock_irqrestore(&sess->ts_spinlock, flags);
249 }
250 EXPORT_SYMBOL_GPL(amvdec_remove_ts);
251 
252 static void dst_buf_done(struct amvdec_session *sess,
253 			 struct vb2_v4l2_buffer *vbuf,
254 			 u32 field,
255 			 u64 timestamp)
256 {
257 	struct device *dev = sess->core->dev_dec;
258 	u32 output_size = amvdec_get_output_size(sess);
259 
260 	switch (sess->pixfmt_cap) {
261 	case V4L2_PIX_FMT_NV12M:
262 		vbuf->vb2_buf.planes[0].bytesused = output_size;
263 		vbuf->vb2_buf.planes[1].bytesused = output_size / 2;
264 		break;
265 	case V4L2_PIX_FMT_YUV420M:
266 		vbuf->vb2_buf.planes[0].bytesused = output_size;
267 		vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
268 		vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
269 		break;
270 	}
271 
272 	vbuf->vb2_buf.timestamp = timestamp;
273 	vbuf->sequence = sess->sequence_cap++;
274 
275 	if (sess->should_stop &&
276 	    atomic_read(&sess->esparser_queued_bufs) <= 2) {
277 		const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
278 
279 		dev_dbg(dev, "Signaling EOS\n");
280 		v4l2_event_queue_fh(&sess->fh, &ev);
281 		vbuf->flags |= V4L2_BUF_FLAG_LAST;
282 	} else if (sess->should_stop)
283 		dev_dbg(dev, "should_stop, %u bufs remain\n",
284 			atomic_read(&sess->esparser_queued_bufs));
285 
286 	dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
287 	vbuf->field = field;
288 	v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
289 
290 	/* Buffer done probably means the vififo got freed */
291 	schedule_work(&sess->esparser_queue_work);
292 }
293 
294 void amvdec_dst_buf_done(struct amvdec_session *sess,
295 			 struct vb2_v4l2_buffer *vbuf, u32 field)
296 {
297 	struct device *dev = sess->core->dev_dec;
298 	struct amvdec_timestamp *tmp;
299 	struct list_head *timestamps = &sess->timestamps;
300 	u64 timestamp;
301 	unsigned long flags;
302 
303 	spin_lock_irqsave(&sess->ts_spinlock, flags);
304 	if (list_empty(timestamps)) {
305 		dev_err(dev, "Buffer %u done but list is empty\n",
306 			vbuf->vb2_buf.index);
307 
308 		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
309 		spin_unlock_irqrestore(&sess->ts_spinlock, flags);
310 		return;
311 	}
312 
313 	tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
314 	timestamp = tmp->ts;
315 	list_del(&tmp->list);
316 	kfree(tmp);
317 	spin_unlock_irqrestore(&sess->ts_spinlock, flags);
318 
319 	dst_buf_done(sess, vbuf, field, timestamp);
320 	atomic_dec(&sess->esparser_queued_bufs);
321 }
322 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
323 
324 void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
325 				struct vb2_v4l2_buffer *vbuf,
326 				u32 offset, u32 field, bool allow_drop)
327 {
328 	struct device *dev = sess->core->dev_dec;
329 	struct amvdec_timestamp *match = NULL;
330 	struct amvdec_timestamp *tmp, *n;
331 	u64 timestamp = 0;
332 	unsigned long flags;
333 
334 	spin_lock_irqsave(&sess->ts_spinlock, flags);
335 
336 	/* Look for our vififo offset to get the corresponding timestamp. */
337 	list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
338 		s64 delta = (s64)offset - tmp->offset;
339 
340 		/* Offsets reported by codecs usually differ slightly,
341 		 * so we need some wiggle room.
342 		 * 4KiB being the minimum packet size, there is no risk here.
343 		 */
344 		if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
345 			match = tmp;
346 			break;
347 		}
348 
349 		if (!allow_drop)
350 			continue;
351 
352 		/* Delete any timestamp entry that appears before our target
353 		 * (not all src packets/timestamps lead to a frame)
354 		 */
355 		if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
356 			atomic_dec(&sess->esparser_queued_bufs);
357 			list_del(&tmp->list);
358 			kfree(tmp);
359 		}
360 	}
361 
362 	if (!match) {
363 		dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
364 			vbuf->vb2_buf.index, offset);
365 	} else {
366 		timestamp = match->ts;
367 		list_del(&match->list);
368 		kfree(match);
369 	}
370 	spin_unlock_irqrestore(&sess->ts_spinlock, flags);
371 
372 	dst_buf_done(sess, vbuf, field, timestamp);
373 	if (match)
374 		atomic_dec(&sess->esparser_queued_bufs);
375 }
376 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset);
377 
378 void amvdec_dst_buf_done_idx(struct amvdec_session *sess,
379 			     u32 buf_idx, u32 offset, u32 field)
380 {
381 	struct vb2_v4l2_buffer *vbuf;
382 	struct device *dev = sess->core->dev_dec;
383 
384 	vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx,
385 					      sess->fw_idx_to_vb2_idx[buf_idx]);
386 
387 	if (!vbuf) {
388 		dev_err(dev,
389 			"Buffer %u done but it doesn't exist in m2m_ctx\n",
390 			buf_idx);
391 		return;
392 	}
393 
394 	if (offset != -1)
395 		amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true);
396 	else
397 		amvdec_dst_buf_done(sess, vbuf, field);
398 }
399 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx);
400 
401 void amvdec_set_par_from_dar(struct amvdec_session *sess,
402 			     u32 dar_num, u32 dar_den)
403 {
404 	u32 div;
405 
406 	sess->pixelaspect.numerator = sess->height * dar_num;
407 	sess->pixelaspect.denominator = sess->width * dar_den;
408 	div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator);
409 	sess->pixelaspect.numerator /= div;
410 	sess->pixelaspect.denominator /= div;
411 }
412 EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
413 
414 void amvdec_src_change(struct amvdec_session *sess, u32 width,
415 		       u32 height, u32 dpb_size)
416 {
417 	static const struct v4l2_event ev = {
418 		.type = V4L2_EVENT_SOURCE_CHANGE,
419 		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
420 
421 	v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
422 
423 	/* Check if the capture queue is already configured well for our
424 	 * usecase. If so, keep decoding with it and do not send the event
425 	 */
426 	if (sess->width == width &&
427 	    sess->height == height &&
428 	    dpb_size <= sess->num_dst_bufs) {
429 		sess->fmt_out->codec_ops->resume(sess);
430 		return;
431 	}
432 
433 	sess->width = width;
434 	sess->height = height;
435 	sess->status = STATUS_NEEDS_RESUME;
436 
437 	dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n",
438 		width, height, dpb_size);
439 	v4l2_event_queue_fh(&sess->fh, &ev);
440 }
441 EXPORT_SYMBOL_GPL(amvdec_src_change);
442 
443 void amvdec_abort(struct amvdec_session *sess)
444 {
445 	dev_info(sess->core->dev, "Aborting decoding session!\n");
446 	vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
447 	vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
448 }
449 EXPORT_SYMBOL_GPL(amvdec_abort);
450