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_MPEG_VIDEO_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_MPEG_VIDEO_HEVC_SPS,
168 			.ops	= &cedrus_ctrl_ops,
169 		},
170 		.codec		= CEDRUS_CODEC_H265,
171 	},
172 	{
173 		.cfg = {
174 			.id	= V4L2_CID_MPEG_VIDEO_HEVC_PPS,
175 		},
176 		.codec		= CEDRUS_CODEC_H265,
177 	},
178 	{
179 		.cfg = {
180 			.id	= V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
181 		},
182 		.codec		= CEDRUS_CODEC_H265,
183 	},
184 	{
185 		.cfg = {
186 			.id	= V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
187 		},
188 		.codec		= CEDRUS_CODEC_H265,
189 	},
190 	{
191 		.cfg = {
192 			.id	= V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
193 			.max	= V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
194 			.def	= V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
195 		},
196 		.codec		= CEDRUS_CODEC_H265,
197 	},
198 	{
199 		.cfg = {
200 			.id	= V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
201 			.max	= V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
202 			.def	= V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
203 		},
204 		.codec		= CEDRUS_CODEC_H265,
205 	},
206 	{
207 		.cfg = {
208 			.id	= V4L2_CID_STATELESS_VP8_FRAME,
209 		},
210 		.codec		= CEDRUS_CODEC_VP8,
211 	},
212 	{
213 		.cfg = {
214 			.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
215 		},
216 		.codec		= CEDRUS_CODEC_H265,
217 	},
218 };
219 
220 #define CEDRUS_CONTROLS_COUNT	ARRAY_SIZE(cedrus_controls)
221 
222 void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
223 {
224 	unsigned int i;
225 
226 	for (i = 0; ctx->ctrls[i]; i++)
227 		if (ctx->ctrls[i]->id == id)
228 			return ctx->ctrls[i]->p_cur.p;
229 
230 	return NULL;
231 }
232 
233 static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
234 {
235 	struct v4l2_ctrl_handler *hdl = &ctx->hdl;
236 	struct v4l2_ctrl *ctrl;
237 	unsigned int ctrl_size;
238 	unsigned int i;
239 
240 	v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
241 	if (hdl->error) {
242 		v4l2_err(&dev->v4l2_dev,
243 			 "Failed to initialize control handler\n");
244 		return hdl->error;
245 	}
246 
247 	ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
248 
249 	ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
250 	if (!ctx->ctrls)
251 		return -ENOMEM;
252 
253 	for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
254 		ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg,
255 					    NULL);
256 		if (hdl->error) {
257 			v4l2_err(&dev->v4l2_dev,
258 				 "Failed to create new custom control\n");
259 
260 			v4l2_ctrl_handler_free(hdl);
261 			kfree(ctx->ctrls);
262 			ctx->ctrls = NULL;
263 			return hdl->error;
264 		}
265 
266 		ctx->ctrls[i] = ctrl;
267 	}
268 
269 	ctx->fh.ctrl_handler = hdl;
270 	v4l2_ctrl_handler_setup(hdl);
271 
272 	return 0;
273 }
274 
275 static int cedrus_request_validate(struct media_request *req)
276 {
277 	struct media_request_object *obj;
278 	struct cedrus_ctx *ctx = NULL;
279 	unsigned int count;
280 
281 	list_for_each_entry(obj, &req->objects, list) {
282 		struct vb2_buffer *vb;
283 
284 		if (vb2_request_object_is_buffer(obj)) {
285 			vb = container_of(obj, struct vb2_buffer, req_obj);
286 			ctx = vb2_get_drv_priv(vb->vb2_queue);
287 
288 			break;
289 		}
290 	}
291 
292 	if (!ctx)
293 		return -ENOENT;
294 
295 	count = vb2_request_buffer_cnt(req);
296 	if (!count) {
297 		v4l2_info(&ctx->dev->v4l2_dev,
298 			  "No buffer was provided with the request\n");
299 		return -ENOENT;
300 	} else if (count > 1) {
301 		v4l2_info(&ctx->dev->v4l2_dev,
302 			  "More than one buffer was provided with the request\n");
303 		return -EINVAL;
304 	}
305 
306 	return vb2_request_validate(req);
307 }
308 
309 static int cedrus_open(struct file *file)
310 {
311 	struct cedrus_dev *dev = video_drvdata(file);
312 	struct cedrus_ctx *ctx = NULL;
313 	int ret;
314 
315 	if (mutex_lock_interruptible(&dev->dev_mutex))
316 		return -ERESTARTSYS;
317 
318 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
319 	if (!ctx) {
320 		mutex_unlock(&dev->dev_mutex);
321 		return -ENOMEM;
322 	}
323 
324 	v4l2_fh_init(&ctx->fh, video_devdata(file));
325 	file->private_data = &ctx->fh;
326 	ctx->dev = dev;
327 
328 	ret = cedrus_init_ctrls(dev, ctx);
329 	if (ret)
330 		goto err_free;
331 
332 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
333 					    &cedrus_queue_init);
334 	if (IS_ERR(ctx->fh.m2m_ctx)) {
335 		ret = PTR_ERR(ctx->fh.m2m_ctx);
336 		goto err_ctrls;
337 	}
338 	ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_NV12_32L32;
339 	cedrus_prepare_format(&ctx->dst_fmt);
340 	ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
341 	/*
342 	 * TILED_NV12 has more strict requirements, so copy the width and
343 	 * height to src_fmt to ensure that is matches the dst_fmt resolution.
344 	 */
345 	ctx->src_fmt.width = ctx->dst_fmt.width;
346 	ctx->src_fmt.height = ctx->dst_fmt.height;
347 	cedrus_prepare_format(&ctx->src_fmt);
348 
349 	v4l2_fh_add(&ctx->fh);
350 
351 	mutex_unlock(&dev->dev_mutex);
352 
353 	return 0;
354 
355 err_ctrls:
356 	v4l2_ctrl_handler_free(&ctx->hdl);
357 err_free:
358 	kfree(ctx);
359 	mutex_unlock(&dev->dev_mutex);
360 
361 	return ret;
362 }
363 
364 static int cedrus_release(struct file *file)
365 {
366 	struct cedrus_dev *dev = video_drvdata(file);
367 	struct cedrus_ctx *ctx = container_of(file->private_data,
368 					      struct cedrus_ctx, fh);
369 
370 	mutex_lock(&dev->dev_mutex);
371 
372 	v4l2_fh_del(&ctx->fh);
373 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
374 
375 	v4l2_ctrl_handler_free(&ctx->hdl);
376 	kfree(ctx->ctrls);
377 
378 	v4l2_fh_exit(&ctx->fh);
379 
380 	kfree(ctx);
381 
382 	mutex_unlock(&dev->dev_mutex);
383 
384 	return 0;
385 }
386 
387 static const struct v4l2_file_operations cedrus_fops = {
388 	.owner		= THIS_MODULE,
389 	.open		= cedrus_open,
390 	.release	= cedrus_release,
391 	.poll		= v4l2_m2m_fop_poll,
392 	.unlocked_ioctl	= video_ioctl2,
393 	.mmap		= v4l2_m2m_fop_mmap,
394 };
395 
396 static const struct video_device cedrus_video_device = {
397 	.name		= CEDRUS_NAME,
398 	.vfl_dir	= VFL_DIR_M2M,
399 	.fops		= &cedrus_fops,
400 	.ioctl_ops	= &cedrus_ioctl_ops,
401 	.minor		= -1,
402 	.release	= video_device_release_empty,
403 	.device_caps	= V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
404 };
405 
406 static const struct v4l2_m2m_ops cedrus_m2m_ops = {
407 	.device_run	= cedrus_device_run,
408 };
409 
410 static const struct media_device_ops cedrus_m2m_media_ops = {
411 	.req_validate	= cedrus_request_validate,
412 	.req_queue	= v4l2_m2m_request_queue,
413 };
414 
415 static int cedrus_probe(struct platform_device *pdev)
416 {
417 	struct cedrus_dev *dev;
418 	struct video_device *vfd;
419 	int ret;
420 
421 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
422 	if (!dev)
423 		return -ENOMEM;
424 
425 	dev->vfd = cedrus_video_device;
426 	dev->dev = &pdev->dev;
427 	dev->pdev = pdev;
428 
429 	ret = cedrus_hw_probe(dev);
430 	if (ret) {
431 		dev_err(&pdev->dev, "Failed to probe hardware\n");
432 		return ret;
433 	}
434 
435 	dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
436 	dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
437 	dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
438 	dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
439 
440 	mutex_init(&dev->dev_mutex);
441 
442 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
443 	if (ret) {
444 		dev_err(&pdev->dev, "Failed to register V4L2 device\n");
445 		return ret;
446 	}
447 
448 	vfd = &dev->vfd;
449 	vfd->lock = &dev->dev_mutex;
450 	vfd->v4l2_dev = &dev->v4l2_dev;
451 
452 	snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
453 	video_set_drvdata(vfd, dev);
454 
455 	dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
456 	if (IS_ERR(dev->m2m_dev)) {
457 		v4l2_err(&dev->v4l2_dev,
458 			 "Failed to initialize V4L2 M2M device\n");
459 		ret = PTR_ERR(dev->m2m_dev);
460 
461 		goto err_v4l2;
462 	}
463 
464 	dev->mdev.dev = &pdev->dev;
465 	strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
466 	strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME,
467 		sizeof(dev->mdev.bus_info));
468 
469 	media_device_init(&dev->mdev);
470 	dev->mdev.ops = &cedrus_m2m_media_ops;
471 	dev->v4l2_dev.mdev = &dev->mdev;
472 
473 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
474 	if (ret) {
475 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
476 		goto err_m2m;
477 	}
478 
479 	v4l2_info(&dev->v4l2_dev,
480 		  "Device registered as /dev/video%d\n", vfd->num);
481 
482 	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
483 						 MEDIA_ENT_F_PROC_VIDEO_DECODER);
484 	if (ret) {
485 		v4l2_err(&dev->v4l2_dev,
486 			 "Failed to initialize V4L2 M2M media controller\n");
487 		goto err_video;
488 	}
489 
490 	ret = media_device_register(&dev->mdev);
491 	if (ret) {
492 		v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
493 		goto err_m2m_mc;
494 	}
495 
496 	platform_set_drvdata(pdev, dev);
497 
498 	return 0;
499 
500 err_m2m_mc:
501 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
502 err_video:
503 	video_unregister_device(&dev->vfd);
504 err_m2m:
505 	v4l2_m2m_release(dev->m2m_dev);
506 err_v4l2:
507 	v4l2_device_unregister(&dev->v4l2_dev);
508 
509 	return ret;
510 }
511 
512 static int cedrus_remove(struct platform_device *pdev)
513 {
514 	struct cedrus_dev *dev = platform_get_drvdata(pdev);
515 
516 	if (media_devnode_is_registered(dev->mdev.devnode)) {
517 		media_device_unregister(&dev->mdev);
518 		v4l2_m2m_unregister_media_controller(dev->m2m_dev);
519 		media_device_cleanup(&dev->mdev);
520 	}
521 
522 	v4l2_m2m_release(dev->m2m_dev);
523 	video_unregister_device(&dev->vfd);
524 	v4l2_device_unregister(&dev->v4l2_dev);
525 
526 	cedrus_hw_remove(dev);
527 
528 	return 0;
529 }
530 
531 static const struct cedrus_variant sun4i_a10_cedrus_variant = {
532 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
533 			  CEDRUS_CAPABILITY_H264_DEC |
534 			  CEDRUS_CAPABILITY_VP8_DEC,
535 	.mod_rate	= 320000000,
536 };
537 
538 static const struct cedrus_variant sun5i_a13_cedrus_variant = {
539 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
540 			  CEDRUS_CAPABILITY_H264_DEC |
541 			  CEDRUS_CAPABILITY_VP8_DEC,
542 	.mod_rate	= 320000000,
543 };
544 
545 static const struct cedrus_variant sun7i_a20_cedrus_variant = {
546 	.capabilities	= CEDRUS_CAPABILITY_MPEG2_DEC |
547 			  CEDRUS_CAPABILITY_H264_DEC |
548 			  CEDRUS_CAPABILITY_VP8_DEC,
549 	.mod_rate	= 320000000,
550 };
551 
552 static const struct cedrus_variant sun8i_a33_cedrus_variant = {
553 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
554 			  CEDRUS_CAPABILITY_MPEG2_DEC |
555 			  CEDRUS_CAPABILITY_H264_DEC |
556 			  CEDRUS_CAPABILITY_VP8_DEC,
557 	.mod_rate	= 320000000,
558 };
559 
560 static const struct cedrus_variant sun8i_h3_cedrus_variant = {
561 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
562 			  CEDRUS_CAPABILITY_MPEG2_DEC |
563 			  CEDRUS_CAPABILITY_H264_DEC |
564 			  CEDRUS_CAPABILITY_H265_DEC |
565 			  CEDRUS_CAPABILITY_VP8_DEC,
566 	.mod_rate	= 402000000,
567 };
568 
569 static const struct cedrus_variant sun8i_v3s_cedrus_variant = {
570 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
571 			  CEDRUS_CAPABILITY_H264_DEC,
572 	.mod_rate	= 297000000,
573 };
574 
575 static const struct cedrus_variant sun8i_r40_cedrus_variant = {
576 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
577 			  CEDRUS_CAPABILITY_MPEG2_DEC |
578 			  CEDRUS_CAPABILITY_H264_DEC |
579 			  CEDRUS_CAPABILITY_VP8_DEC,
580 	.mod_rate	= 297000000,
581 };
582 
583 static const struct cedrus_variant sun20i_d1_cedrus_variant = {
584 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
585 			  CEDRUS_CAPABILITY_MPEG2_DEC |
586 			  CEDRUS_CAPABILITY_H264_DEC |
587 			  CEDRUS_CAPABILITY_H265_DEC,
588 	.mod_rate	= 432000000,
589 };
590 
591 static const struct cedrus_variant sun50i_a64_cedrus_variant = {
592 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
593 			  CEDRUS_CAPABILITY_MPEG2_DEC |
594 			  CEDRUS_CAPABILITY_H264_DEC |
595 			  CEDRUS_CAPABILITY_H265_DEC |
596 			  CEDRUS_CAPABILITY_VP8_DEC,
597 	.mod_rate	= 402000000,
598 };
599 
600 static const struct cedrus_variant sun50i_h5_cedrus_variant = {
601 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
602 			  CEDRUS_CAPABILITY_MPEG2_DEC |
603 			  CEDRUS_CAPABILITY_H264_DEC |
604 			  CEDRUS_CAPABILITY_H265_DEC |
605 			  CEDRUS_CAPABILITY_VP8_DEC,
606 	.mod_rate	= 402000000,
607 };
608 
609 static const struct cedrus_variant sun50i_h6_cedrus_variant = {
610 	.capabilities	= CEDRUS_CAPABILITY_UNTILED |
611 			  CEDRUS_CAPABILITY_MPEG2_DEC |
612 			  CEDRUS_CAPABILITY_H264_DEC |
613 			  CEDRUS_CAPABILITY_H265_DEC |
614 			  CEDRUS_CAPABILITY_H265_10_DEC |
615 			  CEDRUS_CAPABILITY_VP8_DEC,
616 	.mod_rate	= 600000000,
617 };
618 
619 static const struct of_device_id cedrus_dt_match[] = {
620 	{
621 		.compatible = "allwinner,sun4i-a10-video-engine",
622 		.data = &sun4i_a10_cedrus_variant,
623 	},
624 	{
625 		.compatible = "allwinner,sun5i-a13-video-engine",
626 		.data = &sun5i_a13_cedrus_variant,
627 	},
628 	{
629 		.compatible = "allwinner,sun7i-a20-video-engine",
630 		.data = &sun7i_a20_cedrus_variant,
631 	},
632 	{
633 		.compatible = "allwinner,sun8i-a33-video-engine",
634 		.data = &sun8i_a33_cedrus_variant,
635 	},
636 	{
637 		.compatible = "allwinner,sun8i-h3-video-engine",
638 		.data = &sun8i_h3_cedrus_variant,
639 	},
640 	{
641 		.compatible = "allwinner,sun8i-v3s-video-engine",
642 		.data = &sun8i_v3s_cedrus_variant,
643 	},
644 	{
645 		.compatible = "allwinner,sun8i-r40-video-engine",
646 		.data = &sun8i_r40_cedrus_variant,
647 	},
648 	{
649 		.compatible = "allwinner,sun20i-d1-video-engine",
650 		.data = &sun20i_d1_cedrus_variant,
651 	},
652 	{
653 		.compatible = "allwinner,sun50i-a64-video-engine",
654 		.data = &sun50i_a64_cedrus_variant,
655 	},
656 	{
657 		.compatible = "allwinner,sun50i-h5-video-engine",
658 		.data = &sun50i_h5_cedrus_variant,
659 	},
660 	{
661 		.compatible = "allwinner,sun50i-h6-video-engine",
662 		.data = &sun50i_h6_cedrus_variant,
663 	},
664 	{ /* sentinel */ }
665 };
666 MODULE_DEVICE_TABLE(of, cedrus_dt_match);
667 
668 static const struct dev_pm_ops cedrus_dev_pm_ops = {
669 	SET_RUNTIME_PM_OPS(cedrus_hw_suspend,
670 			   cedrus_hw_resume, NULL)
671 };
672 
673 static struct platform_driver cedrus_driver = {
674 	.probe		= cedrus_probe,
675 	.remove		= cedrus_remove,
676 	.driver		= {
677 		.name		= CEDRUS_NAME,
678 		.of_match_table	= of_match_ptr(cedrus_dt_match),
679 		.pm		= &cedrus_dev_pm_ops,
680 	},
681 };
682 module_platform_driver(cedrus_driver);
683 
684 MODULE_LICENSE("GPL v2");
685 MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
686 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
687 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
688 MODULE_DESCRIPTION("Cedrus VPU driver");
689