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