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(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 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 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 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