Commit | Line | Data |
---|---|---|
50e76151 PK |
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 | ||
20 | #include <media/v4l2-device.h> | |
21 | #include <media/v4l2-ioctl.h> | |
22 | #include <media/v4l2-ctrls.h> | |
23 | #include <media/v4l2-mem2mem.h> | |
24 | ||
25 | #include "cedrus.h" | |
26 | #include "cedrus_video.h" | |
27 | #include "cedrus_dec.h" | |
28 | #include "cedrus_hw.h" | |
29 | ||
30 | static const struct cedrus_control cedrus_controls[] = { | |
31 | { | |
3f715c64 EG |
32 | .cfg = { |
33 | .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, | |
34 | }, | |
50e76151 PK |
35 | .codec = CEDRUS_CODEC_MPEG2, |
36 | .required = true, | |
37 | }, | |
38 | { | |
3f715c64 EG |
39 | .cfg = { |
40 | .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, | |
41 | }, | |
50e76151 PK |
42 | .codec = CEDRUS_CODEC_MPEG2, |
43 | .required = false, | |
44 | }, | |
6eb9b758 | 45 | { |
3f715c64 EG |
46 | .cfg = { |
47 | .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, | |
48 | }, | |
6eb9b758 MR |
49 | .codec = CEDRUS_CODEC_H264, |
50 | .required = true, | |
51 | }, | |
52 | { | |
3f715c64 EG |
53 | .cfg = { |
54 | .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, | |
55 | }, | |
6eb9b758 MR |
56 | .codec = CEDRUS_CODEC_H264, |
57 | .required = true, | |
58 | }, | |
59 | { | |
3f715c64 EG |
60 | .cfg = { |
61 | .id = V4L2_CID_MPEG_VIDEO_H264_SPS, | |
62 | }, | |
6eb9b758 MR |
63 | .codec = CEDRUS_CODEC_H264, |
64 | .required = true, | |
65 | }, | |
66 | { | |
3f715c64 EG |
67 | .cfg = { |
68 | .id = V4L2_CID_MPEG_VIDEO_H264_PPS, | |
69 | }, | |
6eb9b758 MR |
70 | .codec = CEDRUS_CODEC_H264, |
71 | .required = true, | |
72 | }, | |
73 | { | |
3f715c64 EG |
74 | .cfg = { |
75 | .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, | |
76 | }, | |
6eb9b758 MR |
77 | .codec = CEDRUS_CODEC_H264, |
78 | .required = true, | |
79 | }, | |
341772b8 EG |
80 | { |
81 | .cfg = { | |
82 | .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, | |
83 | .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, | |
84 | .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, | |
85 | }, | |
86 | .codec = CEDRUS_CODEC_H264, | |
87 | .required = false, | |
88 | }, | |
89 | { | |
90 | .cfg = { | |
91 | .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, | |
92 | .max = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, | |
93 | .def = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, | |
94 | }, | |
95 | .codec = CEDRUS_CODEC_H264, | |
96 | .required = false, | |
97 | }, | |
86caab29 PK |
98 | { |
99 | .cfg = { | |
100 | .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, | |
101 | }, | |
102 | .codec = CEDRUS_CODEC_H265, | |
103 | .required = true, | |
104 | }, | |
105 | { | |
106 | .cfg = { | |
107 | .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, | |
108 | }, | |
109 | .codec = CEDRUS_CODEC_H265, | |
110 | .required = true, | |
111 | }, | |
112 | { | |
113 | .cfg = { | |
114 | .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, | |
115 | }, | |
116 | .codec = CEDRUS_CODEC_H265, | |
117 | .required = true, | |
118 | }, | |
119 | { | |
120 | .cfg = { | |
121 | .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, | |
122 | .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, | |
123 | .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, | |
124 | }, | |
125 | .codec = CEDRUS_CODEC_H265, | |
126 | .required = false, | |
127 | }, | |
128 | { | |
129 | .cfg = { | |
130 | .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, | |
131 | .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, | |
132 | .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, | |
133 | }, | |
134 | .codec = CEDRUS_CODEC_H265, | |
135 | .required = false, | |
136 | }, | |
50e76151 PK |
137 | }; |
138 | ||
139 | #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) | |
140 | ||
141 | void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id) | |
142 | { | |
143 | unsigned int i; | |
144 | ||
145 | for (i = 0; ctx->ctrls[i]; i++) | |
146 | if (ctx->ctrls[i]->id == id) | |
147 | return ctx->ctrls[i]->p_cur.p; | |
148 | ||
149 | return NULL; | |
150 | } | |
151 | ||
152 | static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) | |
153 | { | |
154 | struct v4l2_ctrl_handler *hdl = &ctx->hdl; | |
155 | struct v4l2_ctrl *ctrl; | |
156 | unsigned int ctrl_size; | |
157 | unsigned int i; | |
158 | ||
159 | v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT); | |
160 | if (hdl->error) { | |
161 | v4l2_err(&dev->v4l2_dev, | |
162 | "Failed to initialize control handler\n"); | |
163 | return hdl->error; | |
164 | } | |
165 | ||
166 | ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1; | |
167 | ||
168 | ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL); | |
9ed5d5fb MCC |
169 | if (!ctx->ctrls) |
170 | return -ENOMEM; | |
50e76151 PK |
171 | |
172 | for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { | |
3f715c64 EG |
173 | ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg, |
174 | NULL); | |
50e76151 PK |
175 | if (hdl->error) { |
176 | v4l2_err(&dev->v4l2_dev, | |
177 | "Failed to create new custom control\n"); | |
178 | ||
179 | v4l2_ctrl_handler_free(hdl); | |
180 | kfree(ctx->ctrls); | |
181 | return hdl->error; | |
182 | } | |
183 | ||
184 | ctx->ctrls[i] = ctrl; | |
185 | } | |
186 | ||
187 | ctx->fh.ctrl_handler = hdl; | |
188 | v4l2_ctrl_handler_setup(hdl); | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | static int cedrus_request_validate(struct media_request *req) | |
194 | { | |
195 | struct media_request_object *obj; | |
196 | struct v4l2_ctrl_handler *parent_hdl, *hdl; | |
197 | struct cedrus_ctx *ctx = NULL; | |
198 | struct v4l2_ctrl *ctrl_test; | |
199 | unsigned int count; | |
200 | unsigned int i; | |
201 | ||
50e76151 PK |
202 | list_for_each_entry(obj, &req->objects, list) { |
203 | struct vb2_buffer *vb; | |
204 | ||
205 | if (vb2_request_object_is_buffer(obj)) { | |
206 | vb = container_of(obj, struct vb2_buffer, req_obj); | |
207 | ctx = vb2_get_drv_priv(vb->vb2_queue); | |
208 | ||
209 | break; | |
210 | } | |
211 | } | |
212 | ||
213 | if (!ctx) | |
214 | return -ENOENT; | |
215 | ||
b7c56d7b CIK |
216 | count = vb2_request_buffer_cnt(req); |
217 | if (!count) { | |
218 | v4l2_info(&ctx->dev->v4l2_dev, | |
219 | "No buffer was provided with the request\n"); | |
220 | return -ENOENT; | |
221 | } else if (count > 1) { | |
222 | v4l2_info(&ctx->dev->v4l2_dev, | |
223 | "More than one buffer was provided with the request\n"); | |
224 | return -EINVAL; | |
225 | } | |
226 | ||
50e76151 PK |
227 | parent_hdl = &ctx->hdl; |
228 | ||
229 | hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); | |
230 | if (!hdl) { | |
231 | v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n"); | |
232 | return -ENOENT; | |
233 | } | |
234 | ||
235 | for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { | |
236 | if (cedrus_controls[i].codec != ctx->current_codec || | |
237 | !cedrus_controls[i].required) | |
238 | continue; | |
239 | ||
240 | ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl, | |
3f715c64 | 241 | cedrus_controls[i].cfg.id); |
50e76151 PK |
242 | if (!ctrl_test) { |
243 | v4l2_info(&ctx->dev->v4l2_dev, | |
244 | "Missing required codec control\n"); | |
245 | return -ENOENT; | |
246 | } | |
247 | } | |
248 | ||
249 | v4l2_ctrl_request_hdl_put(hdl); | |
250 | ||
251 | return vb2_request_validate(req); | |
252 | } | |
253 | ||
254 | static int cedrus_open(struct file *file) | |
255 | { | |
256 | struct cedrus_dev *dev = video_drvdata(file); | |
257 | struct cedrus_ctx *ctx = NULL; | |
258 | int ret; | |
259 | ||
260 | if (mutex_lock_interruptible(&dev->dev_mutex)) | |
261 | return -ERESTARTSYS; | |
262 | ||
263 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
264 | if (!ctx) { | |
265 | mutex_unlock(&dev->dev_mutex); | |
266 | return -ENOMEM; | |
267 | } | |
268 | ||
269 | v4l2_fh_init(&ctx->fh, video_devdata(file)); | |
270 | file->private_data = &ctx->fh; | |
271 | ctx->dev = dev; | |
272 | ||
273 | ret = cedrus_init_ctrls(dev, ctx); | |
274 | if (ret) | |
275 | goto err_free; | |
276 | ||
277 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, | |
278 | &cedrus_queue_init); | |
279 | if (IS_ERR(ctx->fh.m2m_ctx)) { | |
280 | ret = PTR_ERR(ctx->fh.m2m_ctx); | |
281 | goto err_ctrls; | |
282 | } | |
965c71e8 HV |
283 | ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; |
284 | cedrus_prepare_format(&ctx->dst_fmt); | |
285 | ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; | |
286 | /* | |
287 | * TILED_NV12 has more strict requirements, so copy the width and | |
288 | * height to src_fmt to ensure that is matches the dst_fmt resolution. | |
289 | */ | |
290 | ctx->src_fmt.width = ctx->dst_fmt.width; | |
291 | ctx->src_fmt.height = ctx->dst_fmt.height; | |
292 | cedrus_prepare_format(&ctx->src_fmt); | |
50e76151 PK |
293 | |
294 | v4l2_fh_add(&ctx->fh); | |
295 | ||
296 | mutex_unlock(&dev->dev_mutex); | |
297 | ||
298 | return 0; | |
299 | ||
300 | err_ctrls: | |
301 | v4l2_ctrl_handler_free(&ctx->hdl); | |
302 | err_free: | |
303 | kfree(ctx); | |
304 | mutex_unlock(&dev->dev_mutex); | |
305 | ||
306 | return ret; | |
307 | } | |
308 | ||
309 | static int cedrus_release(struct file *file) | |
310 | { | |
311 | struct cedrus_dev *dev = video_drvdata(file); | |
312 | struct cedrus_ctx *ctx = container_of(file->private_data, | |
313 | struct cedrus_ctx, fh); | |
314 | ||
315 | mutex_lock(&dev->dev_mutex); | |
316 | ||
317 | v4l2_fh_del(&ctx->fh); | |
318 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | |
319 | ||
320 | v4l2_ctrl_handler_free(&ctx->hdl); | |
321 | kfree(ctx->ctrls); | |
322 | ||
323 | v4l2_fh_exit(&ctx->fh); | |
324 | ||
325 | kfree(ctx); | |
326 | ||
327 | mutex_unlock(&dev->dev_mutex); | |
328 | ||
329 | return 0; | |
330 | } | |
331 | ||
332 | static const struct v4l2_file_operations cedrus_fops = { | |
333 | .owner = THIS_MODULE, | |
334 | .open = cedrus_open, | |
335 | .release = cedrus_release, | |
336 | .poll = v4l2_m2m_fop_poll, | |
337 | .unlocked_ioctl = video_ioctl2, | |
338 | .mmap = v4l2_m2m_fop_mmap, | |
339 | }; | |
340 | ||
341 | static const struct video_device cedrus_video_device = { | |
342 | .name = CEDRUS_NAME, | |
343 | .vfl_dir = VFL_DIR_M2M, | |
344 | .fops = &cedrus_fops, | |
345 | .ioctl_ops = &cedrus_ioctl_ops, | |
346 | .minor = -1, | |
347 | .release = video_device_release_empty, | |
348 | .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, | |
349 | }; | |
350 | ||
351 | static const struct v4l2_m2m_ops cedrus_m2m_ops = { | |
352 | .device_run = cedrus_device_run, | |
353 | }; | |
354 | ||
355 | static const struct media_device_ops cedrus_m2m_media_ops = { | |
356 | .req_validate = cedrus_request_validate, | |
ef86eaf9 | 357 | .req_queue = v4l2_m2m_request_queue, |
50e76151 PK |
358 | }; |
359 | ||
360 | static int cedrus_probe(struct platform_device *pdev) | |
361 | { | |
362 | struct cedrus_dev *dev; | |
363 | struct video_device *vfd; | |
364 | int ret; | |
365 | ||
366 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | |
367 | if (!dev) | |
368 | return -ENOMEM; | |
369 | ||
370 | dev->vfd = cedrus_video_device; | |
371 | dev->dev = &pdev->dev; | |
372 | dev->pdev = pdev; | |
373 | ||
374 | ret = cedrus_hw_probe(dev); | |
375 | if (ret) { | |
376 | dev_err(&pdev->dev, "Failed to probe hardware\n"); | |
377 | return ret; | |
378 | } | |
379 | ||
380 | dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; | |
6eb9b758 | 381 | dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; |
86caab29 | 382 | dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265; |
50e76151 PK |
383 | |
384 | mutex_init(&dev->dev_mutex); | |
50e76151 PK |
385 | |
386 | ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); | |
387 | if (ret) { | |
388 | dev_err(&pdev->dev, "Failed to register V4L2 device\n"); | |
389 | return ret; | |
390 | } | |
391 | ||
392 | vfd = &dev->vfd; | |
393 | vfd->lock = &dev->dev_mutex; | |
394 | vfd->v4l2_dev = &dev->v4l2_dev; | |
395 | ||
396 | snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name); | |
397 | video_set_drvdata(vfd, dev); | |
398 | ||
399 | dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops); | |
400 | if (IS_ERR(dev->m2m_dev)) { | |
401 | v4l2_err(&dev->v4l2_dev, | |
402 | "Failed to initialize V4L2 M2M device\n"); | |
403 | ret = PTR_ERR(dev->m2m_dev); | |
404 | ||
bac87534 | 405 | goto err_v4l2; |
50e76151 PK |
406 | } |
407 | ||
408 | dev->mdev.dev = &pdev->dev; | |
409 | strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model)); | |
ae0688f6 HV |
410 | strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME, |
411 | sizeof(dev->mdev.bus_info)); | |
50e76151 PK |
412 | |
413 | media_device_init(&dev->mdev); | |
414 | dev->mdev.ops = &cedrus_m2m_media_ops; | |
415 | dev->v4l2_dev.mdev = &dev->mdev; | |
416 | ||
0e17c50f | 417 | ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); |
50e76151 PK |
418 | if (ret) { |
419 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | |
bac87534 | 420 | goto err_m2m; |
50e76151 PK |
421 | } |
422 | ||
423 | v4l2_info(&dev->v4l2_dev, | |
424 | "Device registered as /dev/video%d\n", vfd->num); | |
425 | ||
bac87534 JS |
426 | ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, |
427 | MEDIA_ENT_F_PROC_VIDEO_DECODER); | |
428 | if (ret) { | |
429 | v4l2_err(&dev->v4l2_dev, | |
430 | "Failed to initialize V4L2 M2M media controller\n"); | |
431 | goto err_video; | |
432 | } | |
433 | ||
50e76151 PK |
434 | ret = media_device_register(&dev->mdev); |
435 | if (ret) { | |
436 | v4l2_err(&dev->v4l2_dev, "Failed to register media device\n"); | |
437 | goto err_m2m_mc; | |
438 | } | |
439 | ||
440 | platform_set_drvdata(pdev, dev); | |
441 | ||
442 | return 0; | |
443 | ||
444 | err_m2m_mc: | |
445 | v4l2_m2m_unregister_media_controller(dev->m2m_dev); | |
50e76151 PK |
446 | err_video: |
447 | video_unregister_device(&dev->vfd); | |
bac87534 JS |
448 | err_m2m: |
449 | v4l2_m2m_release(dev->m2m_dev); | |
50e76151 PK |
450 | err_v4l2: |
451 | v4l2_device_unregister(&dev->v4l2_dev); | |
452 | ||
453 | return ret; | |
454 | } | |
455 | ||
456 | static int cedrus_remove(struct platform_device *pdev) | |
457 | { | |
458 | struct cedrus_dev *dev = platform_get_drvdata(pdev); | |
459 | ||
460 | if (media_devnode_is_registered(dev->mdev.devnode)) { | |
461 | media_device_unregister(&dev->mdev); | |
462 | v4l2_m2m_unregister_media_controller(dev->m2m_dev); | |
463 | media_device_cleanup(&dev->mdev); | |
464 | } | |
465 | ||
466 | v4l2_m2m_release(dev->m2m_dev); | |
467 | video_unregister_device(&dev->vfd); | |
468 | v4l2_device_unregister(&dev->v4l2_dev); | |
469 | ||
470 | cedrus_hw_remove(dev); | |
471 | ||
472 | return 0; | |
473 | } | |
474 | ||
475 | static const struct cedrus_variant sun4i_a10_cedrus_variant = { | |
9d7a1bed | 476 | .mod_rate = 320000000, |
50e76151 PK |
477 | }; |
478 | ||
479 | static const struct cedrus_variant sun5i_a13_cedrus_variant = { | |
9d7a1bed | 480 | .mod_rate = 320000000, |
50e76151 PK |
481 | }; |
482 | ||
483 | static const struct cedrus_variant sun7i_a20_cedrus_variant = { | |
9d7a1bed | 484 | .mod_rate = 320000000, |
50e76151 PK |
485 | }; |
486 | ||
487 | static const struct cedrus_variant sun8i_a33_cedrus_variant = { | |
488 | .capabilities = CEDRUS_CAPABILITY_UNTILED, | |
9d7a1bed | 489 | .mod_rate = 320000000, |
50e76151 PK |
490 | }; |
491 | ||
492 | static const struct cedrus_variant sun8i_h3_cedrus_variant = { | |
86caab29 PK |
493 | .capabilities = CEDRUS_CAPABILITY_UNTILED | |
494 | CEDRUS_CAPABILITY_H265_DEC, | |
9d7a1bed | 495 | .mod_rate = 402000000, |
50e76151 PK |
496 | }; |
497 | ||
e82a34fa | 498 | static const struct cedrus_variant sun50i_a64_cedrus_variant = { |
86caab29 PK |
499 | .capabilities = CEDRUS_CAPABILITY_UNTILED | |
500 | CEDRUS_CAPABILITY_H265_DEC, | |
9d7a1bed | 501 | .mod_rate = 402000000, |
e82a34fa PK |
502 | }; |
503 | ||
f7fa2b6a | 504 | static const struct cedrus_variant sun50i_h5_cedrus_variant = { |
86caab29 PK |
505 | .capabilities = CEDRUS_CAPABILITY_UNTILED | |
506 | CEDRUS_CAPABILITY_H265_DEC, | |
9d7a1bed | 507 | .mod_rate = 402000000, |
f7fa2b6a PK |
508 | }; |
509 | ||
dea25533 | 510 | static const struct cedrus_variant sun50i_h6_cedrus_variant = { |
86caab29 PK |
511 | .capabilities = CEDRUS_CAPABILITY_UNTILED | |
512 | CEDRUS_CAPABILITY_H265_DEC, | |
dea25533 | 513 | .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, |
9d7a1bed | 514 | .mod_rate = 600000000, |
dea25533 JS |
515 | }; |
516 | ||
50e76151 PK |
517 | static const struct of_device_id cedrus_dt_match[] = { |
518 | { | |
519 | .compatible = "allwinner,sun4i-a10-video-engine", | |
520 | .data = &sun4i_a10_cedrus_variant, | |
521 | }, | |
522 | { | |
523 | .compatible = "allwinner,sun5i-a13-video-engine", | |
524 | .data = &sun5i_a13_cedrus_variant, | |
525 | }, | |
526 | { | |
527 | .compatible = "allwinner,sun7i-a20-video-engine", | |
528 | .data = &sun7i_a20_cedrus_variant, | |
529 | }, | |
530 | { | |
531 | .compatible = "allwinner,sun8i-a33-video-engine", | |
532 | .data = &sun8i_a33_cedrus_variant, | |
533 | }, | |
534 | { | |
535 | .compatible = "allwinner,sun8i-h3-video-engine", | |
536 | .data = &sun8i_h3_cedrus_variant, | |
537 | }, | |
e82a34fa PK |
538 | { |
539 | .compatible = "allwinner,sun50i-a64-video-engine", | |
540 | .data = &sun50i_a64_cedrus_variant, | |
541 | }, | |
f7fa2b6a PK |
542 | { |
543 | .compatible = "allwinner,sun50i-h5-video-engine", | |
544 | .data = &sun50i_h5_cedrus_variant, | |
545 | }, | |
dea25533 JS |
546 | { |
547 | .compatible = "allwinner,sun50i-h6-video-engine", | |
548 | .data = &sun50i_h6_cedrus_variant, | |
549 | }, | |
50e76151 PK |
550 | { /* sentinel */ } |
551 | }; | |
552 | MODULE_DEVICE_TABLE(of, cedrus_dt_match); | |
553 | ||
554 | static struct platform_driver cedrus_driver = { | |
555 | .probe = cedrus_probe, | |
556 | .remove = cedrus_remove, | |
557 | .driver = { | |
558 | .name = CEDRUS_NAME, | |
50e76151 PK |
559 | .of_match_table = of_match_ptr(cedrus_dt_match), |
560 | }, | |
561 | }; | |
562 | module_platform_driver(cedrus_driver); | |
563 | ||
564 | MODULE_LICENSE("GPL v2"); | |
565 | MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>"); | |
566 | MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); | |
567 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); | |
568 | MODULE_DESCRIPTION("Cedrus VPU driver"); |