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