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