FILE
cedrus.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/media/sunxi/cedrus/cedrus.c
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 31static 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 85static const struct v4l2_ctrl_ops cedrus_ctrl_ops = { 86 .try_ctrl = cedrus_try_ctrl, 87}; 88 89static 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 248void *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 259u32 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 270static 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 319static 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 353static 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 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 391err_m2m_release: 392 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 393err_free: 394 kfree(ctx); 395 mutex_unlock(&dev->dev_mutex); 396 397 return ret; 398} 399 400static int cedrus_release(struct file *file) 401{ 402 struct cedrus_dev *dev = video_drvdata(file); 403 struct cedrus_ctx *ctx = cedrus_file2ctx(file); 404 405 mutex_lock(&dev->dev_mutex); 406 407 v4l2_fh_del(&ctx->fh, file); 408 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 409 410 v4l2_ctrl_handler_free(&ctx->hdl); 411 kfree(ctx->ctrls); 412 413 v4l2_fh_exit(&ctx->fh); 414 415 kfree(ctx); 416 417 mutex_unlock(&dev->dev_mutex); 418 419 return 0; 420} 421 422static const struct v4l2_file_operations cedrus_fops = { 423 .owner = THIS_MODULE, 424 .open = cedrus_open, 425 .release = cedrus_release, 426 .poll = v4l2_m2m_fop_poll, 427 .unlocked_ioctl = video_ioctl2, 428 .mmap = v4l2_m2m_fop_mmap, 429}; 430 431static const struct video_device cedrus_video_device = { 432 .name = CEDRUS_NAME, 433 .vfl_dir = VFL_DIR_M2M, 434 .fops = &cedrus_fops, 435 .ioctl_ops = &cedrus_ioctl_ops, 436 .minor = -1, 437 .release = video_device_release_empty, 438 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, 439}; 440 441static const struct v4l2_m2m_ops cedrus_m2m_ops = { 442 .device_run = cedrus_device_run, 443}; 444 445static const struct media_device_ops cedrus_m2m_media_ops = { 446 .req_validate = cedrus_request_validate, 447 .req_queue = v4l2_m2m_request_queue, 448}; 449 450static int cedrus_probe(struct platform_device *pdev) 451{ 452 struct cedrus_dev *dev; 453 struct video_device *vfd; 454 int ret; 455 456 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 457 if (!dev) 458 return -ENOMEM; 459 460 platform_set_drvdata(pdev, dev); 461 462 dev->vfd = cedrus_video_device; 463 dev->dev = &pdev->dev; 464 dev->pdev = pdev; 465 466 ret = cedrus_hw_probe(dev); 467 if (ret) { 468 dev_err(&pdev->dev, "Failed to probe hardware\n"); 469 return ret; 470 } 471 472 mutex_init(&dev->dev_mutex); 473 474 INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog); 475 476 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 477 if (ret) { 478 dev_err(&pdev->dev, "Failed to register V4L2 device\n"); 479 return ret; 480 } 481 482 vfd = &dev->vfd; 483 vfd->lock = &dev->dev_mutex; 484 vfd->v4l2_dev = &dev->v4l2_dev; 485 486 snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name); 487 video_set_drvdata(vfd, dev); 488 489 dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops); 490 if (IS_ERR(dev->m2m_dev)) { 491 v4l2_err(&dev->v4l2_dev, 492 "Failed to initialize V4L2 M2M device\n"); 493 ret = PTR_ERR(dev->m2m_dev); 494 495 goto err_v4l2; 496 } 497 498 dev->mdev.dev = &pdev->dev; 499 strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model)); 500 strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME, 501 sizeof(dev->mdev.bus_info)); 502 503 media_device_init(&dev->mdev); 504 dev->mdev.ops = &cedrus_m2m_media_ops; 505 dev->v4l2_dev.mdev = &dev->mdev; 506 507 ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); 508 if (ret) { 509 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); 510 goto err_m2m; 511 } 512 513 v4l2_info(&dev->v4l2_dev, 514 "Device registered as /dev/video%d\n", vfd->num); 515 516 ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, 517 MEDIA_ENT_F_PROC_VIDEO_DECODER); 518 if (ret) { 519 v4l2_err(&dev->v4l2_dev, 520 "Failed to initialize V4L2 M2M media controller\n"); 521 goto err_video; 522 } 523 524 ret = media_device_register(&dev->mdev); 525 if (ret) { 526 v4l2_err(&dev->v4l2_dev, "Failed to register media device\n"); 527 goto err_m2m_mc; 528 } 529 530 return 0; 531 532err_m2m_mc: 533 v4l2_m2m_unregister_media_controller(dev->m2m_dev); 534err_video: 535 video_unregister_device(&dev->vfd); 536err_m2m: 537 v4l2_m2m_release(dev->m2m_dev); 538err_v4l2: 539 v4l2_device_unregister(&dev->v4l2_dev); 540 541 return ret; 542} 543 544static void cedrus_remove(struct platform_device *pdev) 545{ 546 struct cedrus_dev *dev = platform_get_drvdata(pdev); 547 548 cancel_delayed_work_sync(&dev->watchdog_work); 549 if (media_devnode_is_registered(dev->mdev.devnode)) { 550 media_device_unregister(&dev->mdev); 551 v4l2_m2m_unregister_media_controller(dev->m2m_dev); 552 media_device_cleanup(&dev->mdev); 553 } 554 555 v4l2_m2m_release(dev->m2m_dev); 556 video_unregister_device(&dev->vfd); 557 v4l2_device_unregister(&dev->v4l2_dev); 558 559 cedrus_hw_remove(dev); 560} 561 562static const struct cedrus_variant sun4i_a10_cedrus_variant = { 563 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | 564 CEDRUS_CAPABILITY_H264_DEC | 565 CEDRUS_CAPABILITY_VP8_DEC, 566 .mod_rate = 320000000, 567}; 568 569static const struct cedrus_variant sun5i_a13_cedrus_variant = { 570 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | 571 CEDRUS_CAPABILITY_H264_DEC | 572 CEDRUS_CAPABILITY_VP8_DEC, 573 .mod_rate = 320000000, 574}; 575 576static const struct cedrus_variant sun7i_a20_cedrus_variant = { 577 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | 578 CEDRUS_CAPABILITY_H264_DEC | 579 CEDRUS_CAPABILITY_VP8_DEC, 580 .mod_rate = 320000000, 581}; 582 583static const struct cedrus_variant sun8i_a33_cedrus_variant = { 584 .capabilities = CEDRUS_CAPABILITY_UNTILED | 585 CEDRUS_CAPABILITY_MPEG2_DEC | 586 CEDRUS_CAPABILITY_H264_DEC | 587 CEDRUS_CAPABILITY_VP8_DEC, 588 .mod_rate = 320000000, 589}; 590 591static const struct cedrus_variant sun8i_h3_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 600static const struct cedrus_variant sun8i_v3s_cedrus_variant = { 601 .capabilities = CEDRUS_CAPABILITY_UNTILED | 602 CEDRUS_CAPABILITY_H264_DEC, 603 .mod_rate = 297000000, 604}; 605 606static const struct cedrus_variant sun8i_r40_cedrus_variant = { 607 .capabilities = CEDRUS_CAPABILITY_UNTILED | 608 CEDRUS_CAPABILITY_MPEG2_DEC | 609 CEDRUS_CAPABILITY_H264_DEC | 610 CEDRUS_CAPABILITY_VP8_DEC, 611 .mod_rate = 297000000, 612}; 613 614static const struct cedrus_variant sun20i_d1_cedrus_variant = { 615 .capabilities = CEDRUS_CAPABILITY_UNTILED | 616 CEDRUS_CAPABILITY_MPEG2_DEC | 617 CEDRUS_CAPABILITY_H264_DEC | 618 CEDRUS_CAPABILITY_H265_DEC, 619 .mod_rate = 432000000, 620}; 621 622static const struct cedrus_variant sun50i_a64_cedrus_variant = { 623 .capabilities = CEDRUS_CAPABILITY_UNTILED | 624 CEDRUS_CAPABILITY_MPEG2_DEC | 625 CEDRUS_CAPABILITY_H264_DEC | 626 CEDRUS_CAPABILITY_H265_DEC | 627 CEDRUS_CAPABILITY_VP8_DEC, 628 .mod_rate = 402000000, 629}; 630 631static const struct cedrus_variant sun50i_h5_cedrus_variant = { 632 .capabilities = CEDRUS_CAPABILITY_UNTILED | 633 CEDRUS_CAPABILITY_MPEG2_DEC | 634 CEDRUS_CAPABILITY_H264_DEC | 635 CEDRUS_CAPABILITY_H265_DEC | 636 CEDRUS_CAPABILITY_VP8_DEC, 637 .mod_rate = 402000000, 638}; 639 640static const struct cedrus_variant sun50i_h6_cedrus_variant = { 641 .capabilities = CEDRUS_CAPABILITY_UNTILED | 642 CEDRUS_CAPABILITY_MPEG2_DEC | 643 CEDRUS_CAPABILITY_H264_DEC | 644 CEDRUS_CAPABILITY_H265_DEC | 645 CEDRUS_CAPABILITY_H265_10_DEC | 646 CEDRUS_CAPABILITY_VP8_DEC, 647 .mod_rate = 600000000, 648}; 649 650static const struct of_device_id cedrus_dt_match[] = { 651 { 652 .compatible = "allwinner,sun4i-a10-video-engine", 653 .data = &sun4i_a10_cedrus_variant, 654 }, 655 { 656 .compatible = "allwinner,sun5i-a13-video-engine", 657 .data = &sun5i_a13_cedrus_variant, 658 }, 659 { 660 .compatible = "allwinner,sun7i-a20-video-engine", 661 .data = &sun7i_a20_cedrus_variant, 662 }, 663 { 664 .compatible = "allwinner,sun8i-a33-video-engine", 665 .data = &sun8i_a33_cedrus_variant, 666 }, 667 { 668 .compatible = "allwinner,sun8i-h3-video-engine", 669 .data = &sun8i_h3_cedrus_variant, 670 }, 671 { 672 .compatible = "allwinner,sun8i-v3s-video-engine", 673 .data = &sun8i_v3s_cedrus_variant, 674 }, 675 { 676 .compatible = "allwinner,sun8i-r40-video-engine", 677 .data = &sun8i_r40_cedrus_variant, 678 }, 679 { 680 .compatible = "allwinner,sun20i-d1-video-engine", 681 .data = &sun20i_d1_cedrus_variant, 682 }, 683 { 684 .compatible = "allwinner,sun50i-a64-video-engine", 685 .data = &sun50i_a64_cedrus_variant, 686 }, 687 { 688 .compatible = "allwinner,sun50i-h5-video-engine", 689 .data = &sun50i_h5_cedrus_variant, 690 }, 691 { 692 .compatible = "allwinner,sun50i-h6-video-engine", 693 .data = &sun50i_h6_cedrus_variant, 694 }, 695 { /* sentinel */ } 696}; 697MODULE_DEVICE_TABLE(of, cedrus_dt_match); 698 699static const struct dev_pm_ops cedrus_dev_pm_ops = { 700 SET_RUNTIME_PM_OPS(cedrus_hw_suspend, 701 cedrus_hw_resume, NULL) 702}; 703 704static struct platform_driver cedrus_driver = { 705 .probe = cedrus_probe, 706 .remove = cedrus_remove, 707 .driver = { 708 .name = CEDRUS_NAME, 709 .of_match_table = cedrus_dt_match, 710 .pm = &cedrus_dev_pm_ops, 711 }, 712}; 713module_platform_driver(cedrus_driver); 714 715MODULE_LICENSE("GPL v2"); 716MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>"); 717MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 718MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); 719MODULE_DESCRIPTION("Cedrus VPU driver");
~/
Read-only file preview.