xref: /linux/drivers/staging/media/sunxi/cedrus/cedrus.c (revision 2c869b6969f3061cbbdab587f4c0a88bd7fc3cc9)
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 
31 static 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(ctx->fh.m2m_ctx,
67 				     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(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 
85 static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
86 	.try_ctrl = cedrus_try_ctrl,
87 };
88 
89 static 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 
248 void *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 
259 u32 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 
270 static 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(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, cedrus_controls[i].capabilities))
294 			continue;
295 
296 		ctrl = v4l2_ctrl_new_custom(hdl, &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(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 
319 static 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(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 
353 static 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_obj(*ctx);
363 	if (!ctx) {
364 		mutex_unlock(&dev->dev_mutex);
365 		return -ENOMEM;
366 	}
367 
368 	v4l2_fh_init(&ctx->fh, video_devdata(file));
369 	ctx->dev = dev;
370 	ctx->bit_depth = 8;
371 
372 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
373 					    &cedrus_queue_init);
374 	if (IS_ERR(ctx->fh.m2m_ctx)) {
375 		ret = PTR_ERR(ctx->fh.m2m_ctx);
376 		goto err_free;
377 	}
378 
379 	cedrus_reset_out_format(ctx);
380 
381 	ret = cedrus_init_ctrls(dev, ctx);
382 	if (ret)
383 		goto err_m2m_release;
384 
385 	v4l2_fh_add(&ctx->fh, file);
386 
387 	mutex_unlock(&dev->dev_mutex);
388 
389 	return 0;
390 
391 err_m2m_release:
392 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
393 err_free:
394 	v4l2_fh_exit(&ctx->fh);
395 	kfree(ctx);
396 	mutex_unlock(&dev->dev_mutex);
397 
398 	return ret;
399 }
400 
401 static int cedrus_release(struct file *file)
402 {
403 	struct cedrus_dev *dev = video_drvdata(file);
404 	struct cedrus_ctx *ctx = cedrus_file2ctx(file);
405 
406 	mutex_lock(&dev->dev_mutex);
407 
408 	v4l2_fh_del(&ctx->fh, file);
409 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
410 
411 	v4l2_ctrl_handler_free(&ctx->hdl);
412 	kfree(ctx->ctrls);
413 
414 	v4l2_fh_exit(&ctx->fh);
415 
416 	kfree(ctx);
417 
418 	mutex_unlock(&dev->dev_mutex);
419 
420 	return 0;
421 }
422 
423 static const struct v4l2_file_operations cedrus_fops = {
424 	.owner		= THIS_MODULE,
425 	.open		= cedrus_open,
426 	.release	= cedrus_release,
427 	.poll		= v4l2_m2m_fop_poll,
428 	.unlocked_ioctl	= video_ioctl2,
429 	.mmap		= v4l2_m2m_fop_mmap,
430 };
431 
432 static const struct video_device cedrus_video_device = {
433 	.name		= CEDRUS_NAME,
434 	.vfl_dir	= VFL_DIR_M2M,
435 	.fops		= &cedrus_fops,
436 	.ioctl_ops	= &cedrus_ioctl_ops,
437 	.minor		= -1,
438 	.release	= video_device_release_empty,
439 	.device_caps	= V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
440 };
441 
442 static const struct v4l2_m2m_ops cedrus_m2m_ops = {
443 	.device_run	= cedrus_device_run,
444 };
445 
446 static const struct media_device_ops cedrus_m2m_media_ops = {
447 	.req_validate	= cedrus_request_validate,
448 	.req_queue	= v4l2_m2m_request_queue,
449 };
450 
451 static int cedrus_probe(struct platform_device *pdev)
452 {
453 	struct cedrus_dev *dev;
454 	struct video_device *vfd;
455 	int ret;
456 
457 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
458 	if (!dev)
459 		return -ENOMEM;
460 
461 	platform_set_drvdata(pdev, dev);
462 
463 	dev->vfd = cedrus_video_device;
464 	dev->dev = &pdev->dev;
465 	dev->pdev = pdev;
466 
467 	ret = cedrus_hw_probe(dev);
468 	if (ret) {
469 		dev_err(&pdev->dev, "Failed to probe hardware\n");
470 		return ret;
471 	}
472 
473 	mutex_init(&dev->dev_mutex);
474 
475 	INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog);
476 
477 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
478 	if (ret) {
479 		dev_err(&pdev->dev, "Failed to register V4L2 device\n");
480 		goto err_hw;
481 	}
482 
483 	vfd = &dev->vfd;
484 	vfd->lock = &dev->dev_mutex;
485 	vfd->v4l2_dev = &dev->v4l2_dev;
486 
487 	snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
488 	video_set_drvdata(vfd, dev);
489 
490 	dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
491 	if (IS_ERR(dev->m2m_dev)) {
492 		v4l2_err(&dev->v4l2_dev,
493 			 "Failed to initialize V4L2 M2M device\n");
494 		ret = PTR_ERR(dev->m2m_dev);
495 
496 		goto err_v4l2;
497 	}
498 
499 	dev->mdev.dev = &pdev->dev;
500 	strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
501 	strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME,
502 		sizeof(dev->mdev.bus_info));
503 
504 	media_device_init(&dev->mdev);
505 	dev->mdev.ops = &cedrus_m2m_media_ops;
506 	dev->v4l2_dev.mdev = &dev->mdev;
507 
508 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
509 	if (ret) {
510 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
511 		goto err_media;
512 	}
513 
514 	v4l2_info(&dev->v4l2_dev,
515 		  "Device registered as /dev/video%d\n", vfd->num);
516 
517 	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
518 						 MEDIA_ENT_F_PROC_VIDEO_DECODER);
519 	if (ret) {
520 		v4l2_err(&dev->v4l2_dev,
521 			 "Failed to initialize V4L2 M2M media controller\n");
522 		goto err_video;
523 	}
524 
525 	ret = media_device_register(&dev->mdev);
526 	if (ret) {
527 		v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
528 		goto err_m2m_mc;
529 	}
530 
531 	return 0;
532 
533 err_m2m_mc:
534 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
535 err_video:
536 	video_unregister_device(&dev->vfd);
537 err_media:
538 	media_device_cleanup(&dev->mdev);
539 	v4l2_m2m_release(dev->m2m_dev);
540 err_v4l2:
541 	v4l2_device_unregister(&dev->v4l2_dev);
542 err_hw:
543 	cedrus_hw_remove(dev);
544 
545 	return ret;
546 }
547 
548 static void cedrus_remove(struct platform_device *pdev)
549 {
550 	struct cedrus_dev *dev = platform_get_drvdata(pdev);
551 
552 	cancel_delayed_work_sync(&dev->watchdog_work);
553 	if (media_devnode_is_registered(dev->mdev.devnode)) {
554 		media_device_unregister(&dev->mdev);
555 		v4l2_m2m_unregister_media_controller(dev->m2m_dev);
556 		media_device_cleanup(&dev->mdev);
557 	}
558 
559 	v4l2_m2m_release(dev->m2m_dev);
560 	video_unregister_device(&dev->vfd);
561 	v4l2_device_unregister(&dev->v4l2_dev);
562 
563 	cedrus_hw_remove(dev);
564 }
565 
566 static const struct cedrus_variant sun4i_a10_cedrus_variant = {
567 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
568 			  CEDRUS_CAPABILITY_H264_DEC |
569 			  CEDRUS_CAPABILITY_VP8_DEC,
570 	.mod_rate	= 320000000,
571 };
572 
573 static const struct cedrus_variant sun5i_a13_cedrus_variant = {
574 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
575 			  CEDRUS_CAPABILITY_H264_DEC |
576 			  CEDRUS_CAPABILITY_VP8_DEC,
577 	.mod_rate	= 320000000,
578 };
579 
580 static const struct cedrus_variant sun7i_a20_cedrus_variant = {
581 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
582 			  CEDRUS_CAPABILITY_H264_DEC |
583 			  CEDRUS_CAPABILITY_VP8_DEC,
584 	.mod_rate	= 320000000,
585 };
586 
587 static const struct cedrus_variant sun8i_a33_cedrus_variant = {
588 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
589 			  CEDRUS_CAPABILITY_MPEG2_DEC |
590 			  CEDRUS_CAPABILITY_H264_DEC |
591 			  CEDRUS_CAPABILITY_VP8_DEC,
592 	.mod_rate	= 320000000,
593 };
594 
595 static const struct cedrus_variant sun8i_h3_cedrus_variant = {
596 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
597 			  CEDRUS_CAPABILITY_MPEG2_DEC |
598 			  CEDRUS_CAPABILITY_H264_DEC |
599 			  CEDRUS_CAPABILITY_H265_DEC |
600 			  CEDRUS_CAPABILITY_VP8_DEC,
601 	.mod_rate	= 402000000,
602 };
603 
604 static const struct cedrus_variant sun8i_v3s_cedrus_variant = {
605 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
606 			  CEDRUS_CAPABILITY_H264_DEC,
607 	.mod_rate	= 297000000,
608 };
609 
610 static const struct cedrus_variant sun8i_r40_cedrus_variant = {
611 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
612 			  CEDRUS_CAPABILITY_MPEG2_DEC |
613 			  CEDRUS_CAPABILITY_H264_DEC |
614 			  CEDRUS_CAPABILITY_VP8_DEC,
615 	.mod_rate	= 297000000,
616 };
617 
618 static const struct cedrus_variant sun20i_d1_cedrus_variant = {
619 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
620 			  CEDRUS_CAPABILITY_MPEG2_DEC |
621 			  CEDRUS_CAPABILITY_H264_DEC |
622 			  CEDRUS_CAPABILITY_H265_DEC,
623 	.mod_rate	= 432000000,
624 };
625 
626 static const struct cedrus_variant sun50i_a64_cedrus_variant = {
627 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
628 			  CEDRUS_CAPABILITY_MPEG2_DEC |
629 			  CEDRUS_CAPABILITY_H264_DEC |
630 			  CEDRUS_CAPABILITY_H265_DEC |
631 			  CEDRUS_CAPABILITY_VP8_DEC,
632 	.mod_rate	= 402000000,
633 };
634 
635 static const struct cedrus_variant sun50i_h5_cedrus_variant = {
636 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
637 			  CEDRUS_CAPABILITY_MPEG2_DEC |
638 			  CEDRUS_CAPABILITY_H264_DEC |
639 			  CEDRUS_CAPABILITY_H265_DEC |
640 			  CEDRUS_CAPABILITY_VP8_DEC,
641 	.mod_rate	= 402000000,
642 };
643 
644 static const struct cedrus_variant sun50i_h6_cedrus_variant = {
645 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
646 			  CEDRUS_CAPABILITY_MPEG2_DEC |
647 			  CEDRUS_CAPABILITY_H264_DEC |
648 			  CEDRUS_CAPABILITY_H265_DEC |
649 			  CEDRUS_CAPABILITY_H265_10_DEC |
650 			  CEDRUS_CAPABILITY_VP8_DEC,
651 	.mod_rate	= 600000000,
652 };
653 
654 static const struct of_device_id cedrus_dt_match[] = {
655 	{
656 		.compatible = "allwinner,sun4i-a10-video-engine",
657 		.data = &sun4i_a10_cedrus_variant,
658 	},
659 	{
660 		.compatible = "allwinner,sun5i-a13-video-engine",
661 		.data = &sun5i_a13_cedrus_variant,
662 	},
663 	{
664 		.compatible = "allwinner,sun7i-a20-video-engine",
665 		.data = &sun7i_a20_cedrus_variant,
666 	},
667 	{
668 		.compatible = "allwinner,sun8i-a33-video-engine",
669 		.data = &sun8i_a33_cedrus_variant,
670 	},
671 	{
672 		.compatible = "allwinner,sun8i-h3-video-engine",
673 		.data = &sun8i_h3_cedrus_variant,
674 	},
675 	{
676 		.compatible = "allwinner,sun8i-v3s-video-engine",
677 		.data = &sun8i_v3s_cedrus_variant,
678 	},
679 	{
680 		.compatible = "allwinner,sun8i-r40-video-engine",
681 		.data = &sun8i_r40_cedrus_variant,
682 	},
683 	{
684 		.compatible = "allwinner,sun20i-d1-video-engine",
685 		.data = &sun20i_d1_cedrus_variant,
686 	},
687 	{
688 		.compatible = "allwinner,sun50i-a64-video-engine",
689 		.data = &sun50i_a64_cedrus_variant,
690 	},
691 	{
692 		.compatible = "allwinner,sun50i-h5-video-engine",
693 		.data = &sun50i_h5_cedrus_variant,
694 	},
695 	{
696 		.compatible = "allwinner,sun50i-h6-video-engine",
697 		.data = &sun50i_h6_cedrus_variant,
698 	},
699 	{ /* sentinel */ }
700 };
701 MODULE_DEVICE_TABLE(of, cedrus_dt_match);
702 
703 static const struct dev_pm_ops cedrus_dev_pm_ops = {
704 	SET_RUNTIME_PM_OPS(cedrus_hw_suspend,
705 			   cedrus_hw_resume, NULL)
706 };
707 
708 static struct platform_driver cedrus_driver = {
709 	.probe		= cedrus_probe,
710 	.remove		= cedrus_remove,
711 	.driver		= {
712 		.name		= CEDRUS_NAME,
713 		.of_match_table	= cedrus_dt_match,
714 		.pm		= &cedrus_dev_pm_ops,
715 	},
716 };
717 module_platform_driver(cedrus_driver);
718 
719 MODULE_LICENSE("GPL v2");
720 MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
721 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
722 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
723 MODULE_DESCRIPTION("Cedrus VPU driver");
724