1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cedrus VPU driver
4  *
5  * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6  * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7  * Copyright (C) 2018 Bootlin
8  *
9  * Based on the vim2m driver, that is:
10  *
11  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12  * Pawel Osciak, <pawel@osciak.com>
13  * Marek Szyprowski, <m.szyprowski@samsung.com>
14  */
15 
16 #include <media/videobuf2-dma-contig.h>
17 #include <media/v4l2-device.h>
18 #include <media/v4l2-ioctl.h>
19 #include <media/v4l2-event.h>
20 #include <media/v4l2-mem2mem.h>
21 
22 #include "cedrus.h"
23 #include "cedrus_video.h"
24 #include "cedrus_dec.h"
25 #include "cedrus_hw.h"
26 
27 #define CEDRUS_DECODE_SRC	BIT(0)
28 #define CEDRUS_DECODE_DST	BIT(1)
29 
30 #define CEDRUS_MIN_WIDTH	16U
31 #define CEDRUS_MIN_HEIGHT	16U
32 #define CEDRUS_MAX_WIDTH	4096U
33 #define CEDRUS_MAX_HEIGHT	2304U
34 
35 static struct cedrus_format cedrus_formats[] = {
36 	{
37 		.pixelformat	= V4L2_PIX_FMT_MPEG2_SLICE,
38 		.directions	= CEDRUS_DECODE_SRC,
39 	},
40 	{
41 		.pixelformat	= V4L2_PIX_FMT_H264_SLICE,
42 		.directions	= CEDRUS_DECODE_SRC,
43 	},
44 	{
45 		.pixelformat	= V4L2_PIX_FMT_HEVC_SLICE,
46 		.directions	= CEDRUS_DECODE_SRC,
47 		.capabilities	= CEDRUS_CAPABILITY_H265_DEC,
48 	},
49 	{
50 		.pixelformat	= V4L2_PIX_FMT_SUNXI_TILED_NV12,
51 		.directions	= CEDRUS_DECODE_DST,
52 	},
53 	{
54 		.pixelformat	= V4L2_PIX_FMT_NV12,
55 		.directions	= CEDRUS_DECODE_DST,
56 		.capabilities	= CEDRUS_CAPABILITY_UNTILED,
57 	},
58 };
59 
60 #define CEDRUS_FORMATS_COUNT	ARRAY_SIZE(cedrus_formats)
61 
62 static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
63 {
64 	return container_of(file->private_data, struct cedrus_ctx, fh);
65 }
66 
67 static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
68 						unsigned int capabilities)
69 {
70 	struct cedrus_format *first_valid_fmt = NULL;
71 	struct cedrus_format *fmt;
72 	unsigned int i;
73 
74 	for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
75 		fmt = &cedrus_formats[i];
76 
77 		if ((fmt->capabilities & capabilities) != fmt->capabilities ||
78 		    !(fmt->directions & directions))
79 			continue;
80 
81 		if (fmt->pixelformat == pixelformat)
82 			break;
83 
84 		if (!first_valid_fmt)
85 			first_valid_fmt = fmt;
86 	}
87 
88 	if (i == CEDRUS_FORMATS_COUNT)
89 		return first_valid_fmt;
90 
91 	return &cedrus_formats[i];
92 }
93 
94 void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
95 {
96 	unsigned int width = pix_fmt->width;
97 	unsigned int height = pix_fmt->height;
98 	unsigned int sizeimage = pix_fmt->sizeimage;
99 	unsigned int bytesperline = pix_fmt->bytesperline;
100 
101 	pix_fmt->field = V4L2_FIELD_NONE;
102 
103 	/* Limit to hardware min/max. */
104 	width = clamp(width, CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
105 	height = clamp(height, CEDRUS_MIN_HEIGHT, CEDRUS_MAX_HEIGHT);
106 
107 	switch (pix_fmt->pixelformat) {
108 	case V4L2_PIX_FMT_MPEG2_SLICE:
109 	case V4L2_PIX_FMT_H264_SLICE:
110 	case V4L2_PIX_FMT_HEVC_SLICE:
111 		/* Zero bytes per line for encoded source. */
112 		bytesperline = 0;
113 		/* Choose some minimum size since this can't be 0 */
114 		sizeimage = max_t(u32, SZ_1K, sizeimage);
115 		break;
116 
117 	case V4L2_PIX_FMT_SUNXI_TILED_NV12:
118 		/* 32-aligned stride. */
119 		bytesperline = ALIGN(width, 32);
120 
121 		/* 32-aligned height. */
122 		height = ALIGN(height, 32);
123 
124 		/* Luma plane size. */
125 		sizeimage = bytesperline * height;
126 
127 		/* Chroma plane size. */
128 		sizeimage += bytesperline * height / 2;
129 
130 		break;
131 
132 	case V4L2_PIX_FMT_NV12:
133 		/* 16-aligned stride. */
134 		bytesperline = ALIGN(width, 16);
135 
136 		/* 16-aligned height. */
137 		height = ALIGN(height, 16);
138 
139 		/* Luma plane size. */
140 		sizeimage = bytesperline * height;
141 
142 		/* Chroma plane size. */
143 		sizeimage += bytesperline * height / 2;
144 
145 		break;
146 	}
147 
148 	pix_fmt->width = width;
149 	pix_fmt->height = height;
150 
151 	pix_fmt->bytesperline = bytesperline;
152 	pix_fmt->sizeimage = sizeimage;
153 }
154 
155 static int cedrus_querycap(struct file *file, void *priv,
156 			   struct v4l2_capability *cap)
157 {
158 	strscpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver));
159 	strscpy(cap->card, CEDRUS_NAME, sizeof(cap->card));
160 	snprintf(cap->bus_info, sizeof(cap->bus_info),
161 		 "platform:%s", CEDRUS_NAME);
162 
163 	return 0;
164 }
165 
166 static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
167 			   u32 direction)
168 {
169 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
170 	struct cedrus_dev *dev = ctx->dev;
171 	unsigned int capabilities = dev->capabilities;
172 	struct cedrus_format *fmt;
173 	unsigned int i, index;
174 
175 	/* Index among formats that match the requested direction. */
176 	index = 0;
177 
178 	for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
179 		fmt = &cedrus_formats[i];
180 
181 		if (fmt->capabilities && (fmt->capabilities & capabilities) !=
182 		    fmt->capabilities)
183 			continue;
184 
185 		if (!(cedrus_formats[i].directions & direction))
186 			continue;
187 
188 		if (index == f->index)
189 			break;
190 
191 		index++;
192 	}
193 
194 	/* Matched format. */
195 	if (i < CEDRUS_FORMATS_COUNT) {
196 		f->pixelformat = cedrus_formats[i].pixelformat;
197 
198 		return 0;
199 	}
200 
201 	return -EINVAL;
202 }
203 
204 static int cedrus_enum_fmt_vid_cap(struct file *file, void *priv,
205 				   struct v4l2_fmtdesc *f)
206 {
207 	return cedrus_enum_fmt(file, f, CEDRUS_DECODE_DST);
208 }
209 
210 static int cedrus_enum_fmt_vid_out(struct file *file, void *priv,
211 				   struct v4l2_fmtdesc *f)
212 {
213 	return cedrus_enum_fmt(file, f, CEDRUS_DECODE_SRC);
214 }
215 
216 static int cedrus_g_fmt_vid_cap(struct file *file, void *priv,
217 				struct v4l2_format *f)
218 {
219 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
220 
221 	f->fmt.pix = ctx->dst_fmt;
222 	return 0;
223 }
224 
225 static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
226 				struct v4l2_format *f)
227 {
228 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
229 
230 	f->fmt.pix = ctx->src_fmt;
231 	return 0;
232 }
233 
234 static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
235 				  struct v4l2_format *f)
236 {
237 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
238 	struct cedrus_dev *dev = ctx->dev;
239 	struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
240 	struct cedrus_format *fmt =
241 		cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
242 				   dev->capabilities);
243 
244 	if (!fmt)
245 		return -EINVAL;
246 
247 	pix_fmt->pixelformat = fmt->pixelformat;
248 	cedrus_prepare_format(pix_fmt);
249 
250 	return 0;
251 }
252 
253 static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
254 				  struct v4l2_format *f)
255 {
256 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
257 	struct cedrus_dev *dev = ctx->dev;
258 	struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
259 	struct cedrus_format *fmt =
260 		cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC,
261 				   dev->capabilities);
262 
263 	if (!fmt)
264 		return -EINVAL;
265 
266 	pix_fmt->pixelformat = fmt->pixelformat;
267 	cedrus_prepare_format(pix_fmt);
268 
269 	return 0;
270 }
271 
272 static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
273 				struct v4l2_format *f)
274 {
275 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
276 	struct cedrus_dev *dev = ctx->dev;
277 	struct vb2_queue *vq;
278 	int ret;
279 
280 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
281 	if (vb2_is_busy(vq))
282 		return -EBUSY;
283 
284 	ret = cedrus_try_fmt_vid_cap(file, priv, f);
285 	if (ret)
286 		return ret;
287 
288 	ctx->dst_fmt = f->fmt.pix;
289 
290 	cedrus_dst_format_set(dev, &ctx->dst_fmt);
291 
292 	return 0;
293 }
294 
295 static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
296 				struct v4l2_format *f)
297 {
298 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
299 	struct vb2_queue *vq;
300 	int ret;
301 
302 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
303 	if (vb2_is_busy(vq))
304 		return -EBUSY;
305 
306 	ret = cedrus_try_fmt_vid_out(file, priv, f);
307 	if (ret)
308 		return ret;
309 
310 	ctx->src_fmt = f->fmt.pix;
311 
312 	switch (ctx->src_fmt.pixelformat) {
313 	case V4L2_PIX_FMT_H264_SLICE:
314 		vq->subsystem_flags |=
315 			VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
316 		break;
317 	default:
318 		vq->subsystem_flags &=
319 			~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
320 		break;
321 	}
322 
323 	/* Propagate colorspace information to capture. */
324 	ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
325 	ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
326 	ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
327 	ctx->dst_fmt.quantization = f->fmt.pix.quantization;
328 
329 	return 0;
330 }
331 
332 const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
333 	.vidioc_querycap		= cedrus_querycap,
334 
335 	.vidioc_enum_fmt_vid_cap	= cedrus_enum_fmt_vid_cap,
336 	.vidioc_g_fmt_vid_cap		= cedrus_g_fmt_vid_cap,
337 	.vidioc_try_fmt_vid_cap		= cedrus_try_fmt_vid_cap,
338 	.vidioc_s_fmt_vid_cap		= cedrus_s_fmt_vid_cap,
339 
340 	.vidioc_enum_fmt_vid_out	= cedrus_enum_fmt_vid_out,
341 	.vidioc_g_fmt_vid_out		= cedrus_g_fmt_vid_out,
342 	.vidioc_try_fmt_vid_out		= cedrus_try_fmt_vid_out,
343 	.vidioc_s_fmt_vid_out		= cedrus_s_fmt_vid_out,
344 
345 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
346 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
347 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
348 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
349 	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
350 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
351 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
352 
353 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
354 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
355 
356 	.vidioc_try_decoder_cmd		= v4l2_m2m_ioctl_stateless_try_decoder_cmd,
357 	.vidioc_decoder_cmd		= v4l2_m2m_ioctl_stateless_decoder_cmd,
358 
359 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
360 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
361 };
362 
363 static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
364 			      unsigned int *nplanes, unsigned int sizes[],
365 			      struct device *alloc_devs[])
366 {
367 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
368 	struct v4l2_pix_format *pix_fmt;
369 
370 	if (V4L2_TYPE_IS_OUTPUT(vq->type))
371 		pix_fmt = &ctx->src_fmt;
372 	else
373 		pix_fmt = &ctx->dst_fmt;
374 
375 	if (*nplanes) {
376 		if (sizes[0] < pix_fmt->sizeimage)
377 			return -EINVAL;
378 	} else {
379 		sizes[0] = pix_fmt->sizeimage;
380 		*nplanes = 1;
381 	}
382 
383 	return 0;
384 }
385 
386 static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
387 {
388 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
389 	struct vb2_v4l2_buffer *vbuf;
390 
391 	for (;;) {
392 		if (V4L2_TYPE_IS_OUTPUT(vq->type))
393 			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
394 		else
395 			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
396 
397 		if (!vbuf)
398 			return;
399 
400 		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
401 					   &ctx->hdl);
402 		v4l2_m2m_buf_done(vbuf, state);
403 	}
404 }
405 
406 static int cedrus_buf_out_validate(struct vb2_buffer *vb)
407 {
408 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
409 
410 	vbuf->field = V4L2_FIELD_NONE;
411 	return 0;
412 }
413 
414 static int cedrus_buf_prepare(struct vb2_buffer *vb)
415 {
416 	struct vb2_queue *vq = vb->vb2_queue;
417 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
418 	struct v4l2_pix_format *pix_fmt;
419 
420 	if (V4L2_TYPE_IS_OUTPUT(vq->type))
421 		pix_fmt = &ctx->src_fmt;
422 	else
423 		pix_fmt = &ctx->dst_fmt;
424 
425 	if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
426 		return -EINVAL;
427 
428 	vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
429 
430 	return 0;
431 }
432 
433 static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
434 {
435 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
436 	struct cedrus_dev *dev = ctx->dev;
437 	int ret = 0;
438 
439 	switch (ctx->src_fmt.pixelformat) {
440 	case V4L2_PIX_FMT_MPEG2_SLICE:
441 		ctx->current_codec = CEDRUS_CODEC_MPEG2;
442 		break;
443 
444 	case V4L2_PIX_FMT_H264_SLICE:
445 		ctx->current_codec = CEDRUS_CODEC_H264;
446 		break;
447 
448 	case V4L2_PIX_FMT_HEVC_SLICE:
449 		ctx->current_codec = CEDRUS_CODEC_H265;
450 		break;
451 
452 	default:
453 		return -EINVAL;
454 	}
455 
456 	if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
457 	    dev->dec_ops[ctx->current_codec]->start)
458 		ret = dev->dec_ops[ctx->current_codec]->start(ctx);
459 
460 	if (ret)
461 		cedrus_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
462 
463 	return ret;
464 }
465 
466 static void cedrus_stop_streaming(struct vb2_queue *vq)
467 {
468 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
469 	struct cedrus_dev *dev = ctx->dev;
470 
471 	if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
472 	    dev->dec_ops[ctx->current_codec]->stop)
473 		dev->dec_ops[ctx->current_codec]->stop(ctx);
474 
475 	cedrus_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
476 }
477 
478 static void cedrus_buf_queue(struct vb2_buffer *vb)
479 {
480 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
481 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
482 
483 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
484 }
485 
486 static void cedrus_buf_request_complete(struct vb2_buffer *vb)
487 {
488 	struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
489 
490 	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
491 }
492 
493 static struct vb2_ops cedrus_qops = {
494 	.queue_setup		= cedrus_queue_setup,
495 	.buf_prepare		= cedrus_buf_prepare,
496 	.buf_queue		= cedrus_buf_queue,
497 	.buf_out_validate	= cedrus_buf_out_validate,
498 	.buf_request_complete	= cedrus_buf_request_complete,
499 	.start_streaming	= cedrus_start_streaming,
500 	.stop_streaming		= cedrus_stop_streaming,
501 	.wait_prepare		= vb2_ops_wait_prepare,
502 	.wait_finish		= vb2_ops_wait_finish,
503 };
504 
505 int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
506 		      struct vb2_queue *dst_vq)
507 {
508 	struct cedrus_ctx *ctx = priv;
509 	int ret;
510 
511 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
512 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
513 	src_vq->drv_priv = ctx;
514 	src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
515 	src_vq->min_buffers_needed = 1;
516 	src_vq->ops = &cedrus_qops;
517 	src_vq->mem_ops = &vb2_dma_contig_memops;
518 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
519 	src_vq->lock = &ctx->dev->dev_mutex;
520 	src_vq->dev = ctx->dev->dev;
521 	src_vq->supports_requests = true;
522 	src_vq->requires_requests = true;
523 
524 	ret = vb2_queue_init(src_vq);
525 	if (ret)
526 		return ret;
527 
528 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
529 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
530 	dst_vq->drv_priv = ctx;
531 	dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
532 	dst_vq->min_buffers_needed = 1;
533 	dst_vq->ops = &cedrus_qops;
534 	dst_vq->mem_ops = &vb2_dma_contig_memops;
535 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
536 	dst_vq->lock = &ctx->dev->dev_mutex;
537 	dst_vq->dev = ctx->dev->dev;
538 
539 	return vb2_queue_init(dst_vq);
540 }
541