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