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 
cedrus_try_ctrl(struct v4l2_ctrl * ctrl)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 
cedrus_find_control_data(struct cedrus_ctx * ctx,u32 id)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 
cedrus_get_num_of_controls(struct cedrus_ctx * ctx,u32 id)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 
cedrus_init_ctrls(struct cedrus_dev * dev,struct cedrus_ctx * ctx)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 
cedrus_request_validate(struct media_request * req)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 
cedrus_open(struct file * file)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(sizeof(*ctx), GFP_KERNEL);
363 	if (!ctx) {
364 		mutex_unlock(&dev->dev_mutex);
365 		return -ENOMEM;
366 	}
367 
368 	v4l2_fh_init(&ctx->fh, 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(dev->m2m_dev, ctx,
374 					    &cedrus_queue_init);
375 	if (IS_ERR(ctx->fh.m2m_ctx)) {
376 		ret = PTR_ERR(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(&ctx->fh);
387 
388 	mutex_unlock(&dev->dev_mutex);
389 
390 	return 0;
391 
392 err_m2m_release:
393 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
394 err_free:
395 	kfree(ctx);
396 	mutex_unlock(&dev->dev_mutex);
397 
398 	return ret;
399 }
400 
cedrus_release(struct file * file)401 static 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(&ctx->fh);
410 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
411 
412 	v4l2_ctrl_handler_free(&ctx->hdl);
413 	kfree(ctx->ctrls);
414 
415 	v4l2_fh_exit(&ctx->fh);
416 
417 	kfree(ctx);
418 
419 	mutex_unlock(&dev->dev_mutex);
420 
421 	return 0;
422 }
423 
424 static 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 
433 static 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 
443 static const struct v4l2_m2m_ops cedrus_m2m_ops = {
444 	.device_run	= cedrus_device_run,
445 };
446 
447 static const struct media_device_ops cedrus_m2m_media_ops = {
448 	.req_validate	= cedrus_request_validate,
449 	.req_queue	= v4l2_m2m_request_queue,
450 };
451 
cedrus_probe(struct platform_device * pdev)452 static 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(&pdev->dev, sizeof(*dev), GFP_KERNEL);
459 	if (!dev)
460 		return -ENOMEM;
461 
462 	platform_set_drvdata(pdev, 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(&pdev->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(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
489 	video_set_drvdata(vfd, dev);
490 
491 	dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
492 	if (IS_ERR(dev->m2m_dev)) {
493 		v4l2_err(&dev->v4l2_dev,
494 			 "Failed to initialize V4L2 M2M device\n");
495 		ret = PTR_ERR(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(&dev->mdev);
506 	dev->mdev.ops = &cedrus_m2m_media_ops;
507 	dev->v4l2_dev.mdev = &dev->mdev;
508 
509 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 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(dev->m2m_dev, 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 
534 err_m2m_mc:
535 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
536 err_video:
537 	video_unregister_device(&dev->vfd);
538 err_m2m:
539 	v4l2_m2m_release(dev->m2m_dev);
540 err_v4l2:
541 	v4l2_device_unregister(&dev->v4l2_dev);
542 
543 	return ret;
544 }
545 
cedrus_remove(struct platform_device * pdev)546 static void cedrus_remove(struct platform_device *pdev)
547 {
548 	struct cedrus_dev *dev = platform_get_drvdata(pdev);
549 
550 	cancel_delayed_work_sync(&dev->watchdog_work);
551 	if (media_devnode_is_registered(dev->mdev.devnode)) {
552 		media_device_unregister(&dev->mdev);
553 		v4l2_m2m_unregister_media_controller(dev->m2m_dev);
554 		media_device_cleanup(&dev->mdev);
555 	}
556 
557 	v4l2_m2m_release(dev->m2m_dev);
558 	video_unregister_device(&dev->vfd);
559 	v4l2_device_unregister(&dev->v4l2_dev);
560 
561 	cedrus_hw_remove(dev);
562 }
563 
564 static 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 
571 static 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 
578 static 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 
585 static 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 
593 static 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 
602 static const struct cedrus_variant sun8i_v3s_cedrus_variant = {
603 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
604 			  CEDRUS_CAPABILITY_H264_DEC,
605 	.mod_rate	= 297000000,
606 };
607 
608 static 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 
616 static 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 
624 static 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 
633 static 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 
642 static 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 
652 static 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 };
699 MODULE_DEVICE_TABLE(of, cedrus_dt_match);
700 
701 static const struct dev_pm_ops cedrus_dev_pm_ops = {
702 	SET_RUNTIME_PM_OPS(cedrus_hw_suspend,
703 			   cedrus_hw_resume, NULL)
704 };
705 
706 static struct platform_driver cedrus_driver = {
707 	.probe		= cedrus_probe,
708 	.remove_new	= cedrus_remove,
709 	.driver		= {
710 		.name		= CEDRUS_NAME,
711 		.of_match_table	= of_match_ptr(cedrus_dt_match),
712 		.pm		= &cedrus_dev_pm_ops,
713 	},
714 };
715 module_platform_driver(cedrus_driver);
716 
717 MODULE_LICENSE("GPL v2");
718 MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
719 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
720 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
721 MODULE_DESCRIPTION("Cedrus VPU driver");
722