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/platform_device.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/pm.h>
20
21#include <media/v4l2-device.h>
22#include <media/v4l2-ioctl.h>
23#include <media/v4l2-ctrls.h>
24#include <media/v4l2-mem2mem.h>
25
26#include "cedrus.h"
27#include "cedrus_video.h"
28#include "cedrus_dec.h"
29#include "cedrus_hw.h"
30
31static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
32{
33 if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) {
34 const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
35
36 if (sps->chroma_format_idc != 1)
37 /* Only 4:2:0 is supported */
38 return -EINVAL;
39 if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
40 /* Luma and chroma bit depth mismatch */
41 return -EINVAL;
42 if (sps->bit_depth_luma_minus8 != 0)
43 /* Only 8-bit is supported */
44 return -EINVAL;
45 } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
46 const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
47 struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
48 unsigned int bit_depth, max_depth;
49 struct vb2_queue *vq;
50
51 if (sps->chroma_format_idc != 1)
52 /* Only 4:2:0 is supported */
53 return -EINVAL;
54
55 bit_depth = max(sps->bit_depth_luma_minus8,
56 sps->bit_depth_chroma_minus8) + 8;
57
58 if (cedrus_is_capable(ctx, CEDRUS_CAPABILITY_H265_10_DEC))
59 max_depth = 10;
60 else
61 max_depth = 8;
62
63 if (bit_depth > max_depth)
64 return -EINVAL;
65
66 vq = v4l2_m2m_get_vq(m2m_ctx: ctx->fh.m2m_ctx,
67 type: V4L2_BUF_TYPE_VIDEO_CAPTURE);
68
69 /*
70 * Bit depth can't be higher than currently set once
71 * buffers are allocated.
72 */
73 if (vb2_is_busy(q: vq)) {
74 if (ctx->bit_depth < bit_depth)
75 return -EINVAL;
76 } else {
77 ctx->bit_depth = bit_depth;
78 cedrus_reset_cap_format(ctx);
79 }
80 }
81
82 return 0;
83}
84
85static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
86 .try_ctrl = cedrus_try_ctrl,
87};
88
89static const struct cedrus_control cedrus_controls[] = {
90 {
91 .cfg = {
92 .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
93 },
94 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
95 },
96 {
97 .cfg = {
98 .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
99 },
100 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
101 },
102 {
103 .cfg = {
104 .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
105 },
106 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
107 },
108 {
109 .cfg = {
110 .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
111 },
112 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
113 },
114 {
115 .cfg = {
116 .id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
117 },
118 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
119 },
120 {
121 .cfg = {
122 .id = V4L2_CID_STATELESS_H264_SPS,
123 .ops = &cedrus_ctrl_ops,
124 },
125 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
126 },
127 {
128 .cfg = {
129 .id = V4L2_CID_STATELESS_H264_PPS,
130 },
131 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
132 },
133 {
134 .cfg = {
135 .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
136 },
137 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
138 },
139 {
140 .cfg = {
141 .id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
142 },
143 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
144 },
145 {
146 .cfg = {
147 .id = V4L2_CID_STATELESS_H264_DECODE_MODE,
148 .max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
149 .def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
150 },
151 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
152 },
153 {
154 .cfg = {
155 .id = V4L2_CID_STATELESS_H264_START_CODE,
156 .max = V4L2_STATELESS_H264_START_CODE_NONE,
157 .def = V4L2_STATELESS_H264_START_CODE_NONE,
158 },
159 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
160 },
161 /*
162 * We only expose supported profiles information,
163 * and not levels as it's not clear what is supported
164 * for each hardware/core version.
165 * In any case, TRY/S_FMT will clamp the format resolution
166 * to the maximum supported.
167 */
168 {
169 .cfg = {
170 .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
171 .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
172 .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
173 .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
174 .menu_skip_mask =
175 BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
176 },
177 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
178 },
179 {
180 .cfg = {
181 .id = V4L2_CID_STATELESS_HEVC_SPS,
182 .ops = &cedrus_ctrl_ops,
183 },
184 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
185 },
186 {
187 .cfg = {
188 .id = V4L2_CID_STATELESS_HEVC_PPS,
189 },
190 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
191 },
192 {
193 .cfg = {
194 .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
195 /* The driver can only handle 1 entry per slice for now */
196 .dims = { 1 },
197 },
198 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
199 },
200 {
201 .cfg = {
202 .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
203 },
204 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
205 },
206 {
207 .cfg = {
208 .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS,
209 /* maximum 256 entry point offsets per slice */
210 .dims = { 256 },
211 .max = 0xffffffff,
212 .step = 1,
213 },
214 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
215 },
216 {
217 .cfg = {
218 .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
219 .max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
220 .def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
221 },
222 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
223 },
224 {
225 .cfg = {
226 .id = V4L2_CID_STATELESS_HEVC_START_CODE,
227 .max = V4L2_STATELESS_HEVC_START_CODE_NONE,
228 .def = V4L2_STATELESS_HEVC_START_CODE_NONE,
229 },
230 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
231 },
232 {
233 .cfg = {
234 .id = V4L2_CID_STATELESS_VP8_FRAME,
235 },
236 .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
237 },
238 {
239 .cfg = {
240 .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
241 },
242 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
243 },
244};
245
246#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
247
248void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
249{
250 unsigned int i;
251
252 for (i = 0; ctx->ctrls[i]; i++)
253 if (ctx->ctrls[i]->id == id)
254 return ctx->ctrls[i]->p_cur.p;
255
256 return NULL;
257}
258
259u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id)
260{
261 unsigned int i;
262
263 for (i = 0; ctx->ctrls[i]; i++)
264 if (ctx->ctrls[i]->id == id)
265 return ctx->ctrls[i]->elems;
266
267 return 0;
268}
269
270static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
271{
272 struct v4l2_ctrl_handler *hdl = &ctx->hdl;
273 struct v4l2_ctrl *ctrl;
274 unsigned int ctrl_size;
275 unsigned int i, j;
276
277 v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
278 if (hdl->error) {
279 v4l2_err(&dev->v4l2_dev,
280 "Failed to initialize control handler: %d\n",
281 hdl->error);
282 return hdl->error;
283 }
284
285 ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
286
287 ctx->ctrls = kzalloc(size: ctrl_size, GFP_KERNEL);
288 if (!ctx->ctrls)
289 return -ENOMEM;
290
291 j = 0;
292 for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
293 if (!cedrus_is_capable(ctx, capabilities: cedrus_controls[i].capabilities))
294 continue;
295
296 ctrl = v4l2_ctrl_new_custom(hdl, cfg: &cedrus_controls[i].cfg,
297 NULL);
298 if (hdl->error) {
299 v4l2_err(&dev->v4l2_dev,
300 "Failed to create %s control: %d\n",
301 v4l2_ctrl_get_name(cedrus_controls[i].cfg.id),
302 hdl->error);
303
304 v4l2_ctrl_handler_free(hdl);
305 kfree(objp: ctx->ctrls);
306 ctx->ctrls = NULL;
307 return hdl->error;
308 }
309
310 ctx->ctrls[j++] = ctrl;
311 }
312
313 ctx->fh.ctrl_handler = hdl;
314 v4l2_ctrl_handler_setup(hdl);
315
316 return 0;
317}
318
319static int cedrus_request_validate(struct media_request *req)
320{
321 struct media_request_object *obj;
322 struct cedrus_ctx *ctx = NULL;
323 unsigned int count;
324
325 list_for_each_entry(obj, &req->objects, list) {
326 struct vb2_buffer *vb;
327
328 if (vb2_request_object_is_buffer(obj)) {
329 vb = container_of(obj, struct vb2_buffer, req_obj);
330 ctx = vb2_get_drv_priv(q: vb->vb2_queue);
331
332 break;
333 }
334 }
335
336 if (!ctx)
337 return -ENOENT;
338
339 count = vb2_request_buffer_cnt(req);
340 if (!count) {
341 v4l2_info(&ctx->dev->v4l2_dev,
342 "No buffer was provided with the request\n");
343 return -ENOENT;
344 } else if (count > 1) {
345 v4l2_info(&ctx->dev->v4l2_dev,
346 "More than one buffer was provided with the request\n");
347 return -EINVAL;
348 }
349
350 return vb2_request_validate(req);
351}
352
353static int cedrus_open(struct file *file)
354{
355 struct cedrus_dev *dev = video_drvdata(file);
356 struct cedrus_ctx *ctx = NULL;
357 int ret;
358
359 if (mutex_lock_interruptible(&dev->dev_mutex))
360 return -ERESTARTSYS;
361
362 ctx = kzalloc(size: sizeof(*ctx), GFP_KERNEL);
363 if (!ctx) {
364 mutex_unlock(lock: &dev->dev_mutex);
365 return -ENOMEM;
366 }
367
368 v4l2_fh_init(fh: &ctx->fh, vdev: video_devdata(file));
369 file->private_data = &ctx->fh;
370 ctx->dev = dev;
371 ctx->bit_depth = 8;
372
373 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m_dev: dev->m2m_dev, drv_priv: ctx,
374 queue_init: &cedrus_queue_init);
375 if (IS_ERR(ptr: ctx->fh.m2m_ctx)) {
376 ret = PTR_ERR(ptr: ctx->fh.m2m_ctx);
377 goto err_free;
378 }
379
380 cedrus_reset_out_format(ctx);
381
382 ret = cedrus_init_ctrls(dev, ctx);
383 if (ret)
384 goto err_m2m_release;
385
386 v4l2_fh_add(fh: &ctx->fh);
387
388 mutex_unlock(lock: &dev->dev_mutex);
389
390 return 0;
391
392err_m2m_release:
393 v4l2_m2m_ctx_release(m2m_ctx: ctx->fh.m2m_ctx);
394err_free:
395 kfree(objp: ctx);
396 mutex_unlock(lock: &dev->dev_mutex);
397
398 return ret;
399}
400
401static int cedrus_release(struct file *file)
402{
403 struct cedrus_dev *dev = video_drvdata(file);
404 struct cedrus_ctx *ctx = container_of(file->private_data,
405 struct cedrus_ctx, fh);
406
407 mutex_lock(&dev->dev_mutex);
408
409 v4l2_fh_del(fh: &ctx->fh);
410 v4l2_m2m_ctx_release(m2m_ctx: ctx->fh.m2m_ctx);
411
412 v4l2_ctrl_handler_free(hdl: &ctx->hdl);
413 kfree(objp: ctx->ctrls);
414
415 v4l2_fh_exit(fh: &ctx->fh);
416
417 kfree(objp: ctx);
418
419 mutex_unlock(lock: &dev->dev_mutex);
420
421 return 0;
422}
423
424static const struct v4l2_file_operations cedrus_fops = {
425 .owner = THIS_MODULE,
426 .open = cedrus_open,
427 .release = cedrus_release,
428 .poll = v4l2_m2m_fop_poll,
429 .unlocked_ioctl = video_ioctl2,
430 .mmap = v4l2_m2m_fop_mmap,
431};
432
433static const struct video_device cedrus_video_device = {
434 .name = CEDRUS_NAME,
435 .vfl_dir = VFL_DIR_M2M,
436 .fops = &cedrus_fops,
437 .ioctl_ops = &cedrus_ioctl_ops,
438 .minor = -1,
439 .release = video_device_release_empty,
440 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
441};
442
443static const struct v4l2_m2m_ops cedrus_m2m_ops = {
444 .device_run = cedrus_device_run,
445};
446
447static const struct media_device_ops cedrus_m2m_media_ops = {
448 .req_validate = cedrus_request_validate,
449 .req_queue = v4l2_m2m_request_queue,
450};
451
452static int cedrus_probe(struct platform_device *pdev)
453{
454 struct cedrus_dev *dev;
455 struct video_device *vfd;
456 int ret;
457
458 dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*dev), GFP_KERNEL);
459 if (!dev)
460 return -ENOMEM;
461
462 platform_set_drvdata(pdev, data: dev);
463
464 dev->vfd = cedrus_video_device;
465 dev->dev = &pdev->dev;
466 dev->pdev = pdev;
467
468 ret = cedrus_hw_probe(dev);
469 if (ret) {
470 dev_err(&pdev->dev, "Failed to probe hardware\n");
471 return ret;
472 }
473
474 mutex_init(&dev->dev_mutex);
475
476 INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog);
477
478 ret = v4l2_device_register(dev: &pdev->dev, v4l2_dev: &dev->v4l2_dev);
479 if (ret) {
480 dev_err(&pdev->dev, "Failed to register V4L2 device\n");
481 return ret;
482 }
483
484 vfd = &dev->vfd;
485 vfd->lock = &dev->dev_mutex;
486 vfd->v4l2_dev = &dev->v4l2_dev;
487
488 snprintf(buf: vfd->name, size: sizeof(vfd->name), fmt: "%s", cedrus_video_device.name);
489 video_set_drvdata(vdev: vfd, data: dev);
490
491 dev->m2m_dev = v4l2_m2m_init(m2m_ops: &cedrus_m2m_ops);
492 if (IS_ERR(ptr: dev->m2m_dev)) {
493 v4l2_err(&dev->v4l2_dev,
494 "Failed to initialize V4L2 M2M device\n");
495 ret = PTR_ERR(ptr: dev->m2m_dev);
496
497 goto err_v4l2;
498 }
499
500 dev->mdev.dev = &pdev->dev;
501 strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
502 strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME,
503 sizeof(dev->mdev.bus_info));
504
505 media_device_init(mdev: &dev->mdev);
506 dev->mdev.ops = &cedrus_m2m_media_ops;
507 dev->v4l2_dev.mdev = &dev->mdev;
508
509 ret = video_register_device(vdev: vfd, type: VFL_TYPE_VIDEO, nr: 0);
510 if (ret) {
511 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
512 goto err_m2m;
513 }
514
515 v4l2_info(&dev->v4l2_dev,
516 "Device registered as /dev/video%d\n", vfd->num);
517
518 ret = v4l2_m2m_register_media_controller(m2m_dev: dev->m2m_dev, vdev: vfd,
519 MEDIA_ENT_F_PROC_VIDEO_DECODER);
520 if (ret) {
521 v4l2_err(&dev->v4l2_dev,
522 "Failed to initialize V4L2 M2M media controller\n");
523 goto err_video;
524 }
525
526 ret = media_device_register(&dev->mdev);
527 if (ret) {
528 v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
529 goto err_m2m_mc;
530 }
531
532 return 0;
533
534err_m2m_mc:
535 v4l2_m2m_unregister_media_controller(m2m_dev: dev->m2m_dev);
536err_video:
537 video_unregister_device(vdev: &dev->vfd);
538err_m2m:
539 v4l2_m2m_release(m2m_dev: dev->m2m_dev);
540err_v4l2:
541 v4l2_device_unregister(v4l2_dev: &dev->v4l2_dev);
542
543 return ret;
544}
545
546static void cedrus_remove(struct platform_device *pdev)
547{
548 struct cedrus_dev *dev = platform_get_drvdata(pdev);
549
550 cancel_delayed_work_sync(dwork: &dev->watchdog_work);
551 if (media_devnode_is_registered(devnode: dev->mdev.devnode)) {
552 media_device_unregister(mdev: &dev->mdev);
553 v4l2_m2m_unregister_media_controller(m2m_dev: dev->m2m_dev);
554 media_device_cleanup(mdev: &dev->mdev);
555 }
556
557 v4l2_m2m_release(m2m_dev: dev->m2m_dev);
558 video_unregister_device(vdev: &dev->vfd);
559 v4l2_device_unregister(v4l2_dev: &dev->v4l2_dev);
560
561 cedrus_hw_remove(dev);
562}
563
564static const struct cedrus_variant sun4i_a10_cedrus_variant = {
565 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC |
566 CEDRUS_CAPABILITY_H264_DEC |
567 CEDRUS_CAPABILITY_VP8_DEC,
568 .mod_rate = 320000000,
569};
570
571static const struct cedrus_variant sun5i_a13_cedrus_variant = {
572 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC |
573 CEDRUS_CAPABILITY_H264_DEC |
574 CEDRUS_CAPABILITY_VP8_DEC,
575 .mod_rate = 320000000,
576};
577
578static const struct cedrus_variant sun7i_a20_cedrus_variant = {
579 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC |
580 CEDRUS_CAPABILITY_H264_DEC |
581 CEDRUS_CAPABILITY_VP8_DEC,
582 .mod_rate = 320000000,
583};
584
585static const struct cedrus_variant sun8i_a33_cedrus_variant = {
586 .capabilities = CEDRUS_CAPABILITY_UNTILED |
587 CEDRUS_CAPABILITY_MPEG2_DEC |
588 CEDRUS_CAPABILITY_H264_DEC |
589 CEDRUS_CAPABILITY_VP8_DEC,
590 .mod_rate = 320000000,
591};
592
593static const struct cedrus_variant sun8i_h3_cedrus_variant = {
594 .capabilities = CEDRUS_CAPABILITY_UNTILED |
595 CEDRUS_CAPABILITY_MPEG2_DEC |
596 CEDRUS_CAPABILITY_H264_DEC |
597 CEDRUS_CAPABILITY_H265_DEC |
598 CEDRUS_CAPABILITY_VP8_DEC,
599 .mod_rate = 402000000,
600};
601
602static const struct cedrus_variant sun8i_v3s_cedrus_variant = {
603 .capabilities = CEDRUS_CAPABILITY_UNTILED |
604 CEDRUS_CAPABILITY_H264_DEC,
605 .mod_rate = 297000000,
606};
607
608static const struct cedrus_variant sun8i_r40_cedrus_variant = {
609 .capabilities = CEDRUS_CAPABILITY_UNTILED |
610 CEDRUS_CAPABILITY_MPEG2_DEC |
611 CEDRUS_CAPABILITY_H264_DEC |
612 CEDRUS_CAPABILITY_VP8_DEC,
613 .mod_rate = 297000000,
614};
615
616static const struct cedrus_variant sun20i_d1_cedrus_variant = {
617 .capabilities = CEDRUS_CAPABILITY_UNTILED |
618 CEDRUS_CAPABILITY_MPEG2_DEC |
619 CEDRUS_CAPABILITY_H264_DEC |
620 CEDRUS_CAPABILITY_H265_DEC,
621 .mod_rate = 432000000,
622};
623
624static const struct cedrus_variant sun50i_a64_cedrus_variant = {
625 .capabilities = CEDRUS_CAPABILITY_UNTILED |
626 CEDRUS_CAPABILITY_MPEG2_DEC |
627 CEDRUS_CAPABILITY_H264_DEC |
628 CEDRUS_CAPABILITY_H265_DEC |
629 CEDRUS_CAPABILITY_VP8_DEC,
630 .mod_rate = 402000000,
631};
632
633static const struct cedrus_variant sun50i_h5_cedrus_variant = {
634 .capabilities = CEDRUS_CAPABILITY_UNTILED |
635 CEDRUS_CAPABILITY_MPEG2_DEC |
636 CEDRUS_CAPABILITY_H264_DEC |
637 CEDRUS_CAPABILITY_H265_DEC |
638 CEDRUS_CAPABILITY_VP8_DEC,
639 .mod_rate = 402000000,
640};
641
642static const struct cedrus_variant sun50i_h6_cedrus_variant = {
643 .capabilities = CEDRUS_CAPABILITY_UNTILED |
644 CEDRUS_CAPABILITY_MPEG2_DEC |
645 CEDRUS_CAPABILITY_H264_DEC |
646 CEDRUS_CAPABILITY_H265_DEC |
647 CEDRUS_CAPABILITY_H265_10_DEC |
648 CEDRUS_CAPABILITY_VP8_DEC,
649 .mod_rate = 600000000,
650};
651
652static const struct of_device_id cedrus_dt_match[] = {
653 {
654 .compatible = "allwinner,sun4i-a10-video-engine",
655 .data = &sun4i_a10_cedrus_variant,
656 },
657 {
658 .compatible = "allwinner,sun5i-a13-video-engine",
659 .data = &sun5i_a13_cedrus_variant,
660 },
661 {
662 .compatible = "allwinner,sun7i-a20-video-engine",
663 .data = &sun7i_a20_cedrus_variant,
664 },
665 {
666 .compatible = "allwinner,sun8i-a33-video-engine",
667 .data = &sun8i_a33_cedrus_variant,
668 },
669 {
670 .compatible = "allwinner,sun8i-h3-video-engine",
671 .data = &sun8i_h3_cedrus_variant,
672 },
673 {
674 .compatible = "allwinner,sun8i-v3s-video-engine",
675 .data = &sun8i_v3s_cedrus_variant,
676 },
677 {
678 .compatible = "allwinner,sun8i-r40-video-engine",
679 .data = &sun8i_r40_cedrus_variant,
680 },
681 {
682 .compatible = "allwinner,sun20i-d1-video-engine",
683 .data = &sun20i_d1_cedrus_variant,
684 },
685 {
686 .compatible = "allwinner,sun50i-a64-video-engine",
687 .data = &sun50i_a64_cedrus_variant,
688 },
689 {
690 .compatible = "allwinner,sun50i-h5-video-engine",
691 .data = &sun50i_h5_cedrus_variant,
692 },
693 {
694 .compatible = "allwinner,sun50i-h6-video-engine",
695 .data = &sun50i_h6_cedrus_variant,
696 },
697 { /* sentinel */ }
698};
699MODULE_DEVICE_TABLE(of, cedrus_dt_match);
700
701static const struct dev_pm_ops cedrus_dev_pm_ops = {
702 SET_RUNTIME_PM_OPS(cedrus_hw_suspend,
703 cedrus_hw_resume, NULL)
704};
705
706static struct platform_driver cedrus_driver = {
707 .probe = cedrus_probe,
708 .remove_new = cedrus_remove,
709 .driver = {
710 .name = CEDRUS_NAME,
711 .of_match_table = cedrus_dt_match,
712 .pm = &cedrus_dev_pm_ops,
713 },
714};
715module_platform_driver(cedrus_driver);
716
717MODULE_LICENSE("GPL v2");
718MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
719MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
720MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
721MODULE_DESCRIPTION("Cedrus VPU driver");
722

source code of linux/drivers/staging/media/sunxi/cedrus/cedrus.c