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