FILE
core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/qcom/venus/core.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. 4 * Copyright (C) 2017 Linaro Ltd. 5 */ 6#include <linux/init.h> 7#include <linux/interconnect.h> 8#include <linux/io.h> 9#include <linux/ioctl.h> 10#include <linux/delay.h> 11#include <linux/devcoredump.h> 12#include <linux/list.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/of_platform.h> 16#include <linux/platform_device.h> 17#include <linux/slab.h> 18#include <linux/types.h> 19#include <linux/pm_domain.h> 20#include <linux/pm_runtime.h> 21#include <media/videobuf2-v4l2.h> 22#include <media/v4l2-ctrls.h> 23#include <media/v4l2-mem2mem.h> 24#include <media/v4l2-ioctl.h> 25 26#include "core.h" 27#include "firmware.h" 28#include "pm_helpers.h" 29#include "hfi_venus_io.h" 30 31static void venus_coredump(struct venus_core *core) 32{ 33 struct device *dev; 34 phys_addr_t mem_phys; 35 size_t mem_size; 36 void *mem_va; 37 void *data; 38 39 dev = core->dev; 40 mem_phys = core->fw.mem_phys; 41 mem_size = core->fw.mem_size; 42 43 mem_va = memremap(mem_phys, mem_size, MEMREMAP_WC); 44 if (!mem_va) 45 return; 46 47 data = vmalloc(mem_size); 48 if (!data) { 49 memunmap(mem_va); 50 return; 51 } 52 53 memcpy(data, mem_va, mem_size); 54 memunmap(mem_va); 55 dev_coredumpv(dev, data, mem_size, GFP_KERNEL); 56} 57 58static void venus_event_notify(struct venus_core *core, u32 event) 59{ 60 struct venus_inst *inst; 61 62 switch (event) { 63 case EVT_SYS_WATCHDOG_TIMEOUT: 64 case EVT_SYS_ERROR: 65 break; 66 default: 67 return; 68 } 69 70 mutex_lock(&core->lock); 71 set_bit(0, &core->sys_error); 72 set_bit(0, &core->dump_core); 73 list_for_each_entry(inst, &core->instances, list) 74 inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); 75 mutex_unlock(&core->lock); 76 77 disable_irq_nosync(core->irq); 78 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 79} 80 81static const struct hfi_core_ops venus_core_ops = { 82 .event_notify = venus_event_notify, 83}; 84 85#define RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS 10 86 87static void venus_sys_error_handler(struct work_struct *work) 88{ 89 struct venus_core *core = 90 container_of(work, struct venus_core, work.work); 91 int ret, i, max_attempts = RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS; 92 const char *err_msg = ""; 93 bool failed = false; 94 95 ret = pm_runtime_get_sync(core->dev); 96 if (ret < 0) { 97 err_msg = "resume runtime PM"; 98 max_attempts = 0; 99 failed = true; 100 } 101 102 core->ops->core_deinit(core); 103 core->state = CORE_UNINIT; 104 105 for (i = 0; i < max_attempts; i++) { 106 if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc)) 107 break; 108 msleep(10); 109 } 110 111 mutex_lock(&core->lock); 112 113 venus_shutdown(core); 114 115 if (test_bit(0, &core->dump_core)) { 116 venus_coredump(core); 117 clear_bit(0, &core->dump_core); 118 } 119 120 pm_runtime_put_sync(core->dev); 121 122 for (i = 0; i < max_attempts; i++) { 123 if (!core->pmdomains || 124 !pm_runtime_active(core->pmdomains->pd_devs[0])) 125 break; 126 usleep_range(1000, 1500); 127 } 128 129 hfi_reinit(core); 130 131 ret = pm_runtime_get_sync(core->dev); 132 if (ret < 0) { 133 err_msg = "resume runtime PM"; 134 failed = true; 135 } 136 137 ret = venus_boot(core); 138 if (ret && !failed) { 139 err_msg = "boot Venus"; 140 failed = true; 141 } 142 143 ret = hfi_core_resume(core, true); 144 if (ret && !failed) { 145 err_msg = "resume HFI"; 146 failed = true; 147 } 148 149 enable_irq(core->irq); 150 151 mutex_unlock(&core->lock); 152 153 ret = hfi_core_init(core); 154 if (ret && !failed) { 155 err_msg = "init HFI"; 156 failed = true; 157 } 158 159 pm_runtime_put_sync(core->dev); 160 161 if (failed) { 162 disable_irq_nosync(core->irq); 163 dev_warn_ratelimited(core->dev, 164 "System error has occurred, recovery failed to %s\n", 165 err_msg); 166 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 167 return; 168 } 169 170 dev_warn(core->dev, "system error has occurred (recovered)\n"); 171 172 mutex_lock(&core->lock); 173 clear_bit(0, &core->sys_error); 174 wake_up_all(&core->sys_err_done); 175 mutex_unlock(&core->lock); 176} 177 178static u32 to_v4l2_codec_type(u32 codec) 179{ 180 switch (codec) { 181 case HFI_VIDEO_CODEC_H264: 182 return V4L2_PIX_FMT_H264; 183 case HFI_VIDEO_CODEC_H263: 184 return V4L2_PIX_FMT_H263; 185 case HFI_VIDEO_CODEC_MPEG1: 186 return V4L2_PIX_FMT_MPEG1; 187 case HFI_VIDEO_CODEC_MPEG2: 188 return V4L2_PIX_FMT_MPEG2; 189 case HFI_VIDEO_CODEC_MPEG4: 190 return V4L2_PIX_FMT_MPEG4; 191 case HFI_VIDEO_CODEC_VC1: 192 return V4L2_PIX_FMT_VC1_ANNEX_G; 193 case HFI_VIDEO_CODEC_VP8: 194 return V4L2_PIX_FMT_VP8; 195 case HFI_VIDEO_CODEC_VP9: 196 return V4L2_PIX_FMT_VP9; 197 case HFI_VIDEO_CODEC_DIVX: 198 case HFI_VIDEO_CODEC_DIVX_311: 199 return V4L2_PIX_FMT_XVID; 200 default: 201 return 0; 202 } 203} 204 205static int venus_enumerate_codecs(struct venus_core *core, u32 type) 206{ 207 const struct hfi_inst_ops dummy_ops = {}; 208 struct venus_inst *inst; 209 u32 codec, codecs; 210 unsigned int i; 211 int ret; 212 213 if (core->res->hfi_version != HFI_VERSION_1XX) 214 return 0; 215 216 inst = kzalloc(sizeof(*inst), GFP_KERNEL); 217 if (!inst) 218 return -ENOMEM; 219 220 mutex_init(&inst->lock); 221 inst->core = core; 222 inst->session_type = type; 223 if (type == VIDC_SESSION_TYPE_DEC) 224 codecs = core->dec_codecs; 225 else 226 codecs = core->enc_codecs; 227 228 ret = hfi_session_create(inst, &dummy_ops); 229 if (ret) 230 goto err; 231 232 for (i = 0; i < MAX_CODEC_NUM; i++) { 233 codec = (1UL << i) & codecs; 234 if (!codec) 235 continue; 236 237 ret = hfi_session_init(inst, to_v4l2_codec_type(codec)); 238 if (ret) 239 goto done; 240 241 ret = hfi_session_deinit(inst); 242 if (ret) 243 goto done; 244 } 245 246done: 247 hfi_session_destroy(inst); 248err: 249 mutex_destroy(&inst->lock); 250 kfree(inst); 251 252 return ret; 253} 254 255static void venus_assign_register_offsets(struct venus_core *core) 256{ 257 if (IS_IRIS2(core) || IS_IRIS2_1(core) || IS_AR50_LITE(core)) { 258 core->cpu_base = core->base + CPU_BASE_V6; 259 core->cpu_cs_base = core->base + CPU_CS_BASE_V6; 260 core->cpu_ic_base = core->base + CPU_IC_BASE_V6; 261 core->wrapper_base = core->base + WRAPPER_BASE_V6; 262 core->wrapper_tz_base = core->base + WRAPPER_TZ_BASE_V6; 263 if (IS_AR50_LITE(core)) { 264 core->vbif_base = NULL; 265 core->aon_base = NULL; 266 } else { 267 core->vbif_base = core->base + VBIF_BASE; 268 core->aon_base = core->base + AON_BASE_V6; 269 } 270 } else { 271 core->vbif_base = core->base + VBIF_BASE; 272 core->cpu_base = core->base + CPU_BASE; 273 core->cpu_cs_base = core->base + CPU_CS_BASE; 274 core->cpu_ic_base = core->base + CPU_IC_BASE; 275 core->wrapper_base = core->base + WRAPPER_BASE; 276 core->wrapper_tz_base = NULL; 277 core->aon_base = NULL; 278 } 279} 280 281static irqreturn_t venus_isr_thread(int irq, void *dev_id) 282{ 283 struct venus_core *core = dev_id; 284 irqreturn_t ret; 285 286 ret = hfi_isr_thread(irq, dev_id); 287 288 if (ret == IRQ_HANDLED && venus_fault_inject_ssr()) 289 hfi_core_trigger_ssr(core, HFI_TEST_SSR_SW_ERR_FATAL); 290 291 return ret; 292} 293 294#if defined(CONFIG_OF_DYNAMIC) 295static int venus_add_video_core(struct venus_core *core, const char *node_name, 296 const char *compat) 297{ 298 struct of_changeset *ocs = core->ocs; 299 struct device *dev = core->dev; 300 struct device_node *np, *enp; 301 int ret; 302 303 if (!node_name) 304 return 0; 305 306 enp = of_find_node_by_name(dev->of_node, node_name); 307 if (enp) { 308 of_node_put(enp); 309 return 0; 310 } 311 312 np = of_changeset_create_node(ocs, dev->of_node, node_name); 313 if (!np) { 314 dev_err(dev, "Unable to create new node\n"); 315 return -ENODEV; 316 } 317 318 ret = of_changeset_add_prop_string(ocs, np, "compatible", compat); 319 if (ret) 320 dev_err(dev, "unable to add %s\n", compat); 321 322 of_node_put(np); 323 324 return ret; 325} 326 327static int venus_add_dynamic_nodes(struct venus_core *core) 328{ 329 struct device *dev = core->dev; 330 int ret; 331 332 core->ocs = kmalloc(sizeof(*core->ocs), GFP_KERNEL); 333 if (!core->ocs) 334 return -ENOMEM; 335 336 of_changeset_init(core->ocs); 337 338 ret = venus_add_video_core(core, core->res->dec_nodename, "venus-decoder"); 339 if (ret) 340 goto err; 341 342 ret = venus_add_video_core(core, core->res->enc_nodename, "venus-encoder"); 343 if (ret) 344 goto err; 345 346 ret = of_changeset_apply(core->ocs); 347 if (ret) { 348 dev_err(dev, "applying changeset fail ret %d\n", ret); 349 goto err; 350 } 351 352 return 0; 353err: 354 of_changeset_destroy(core->ocs); 355 kfree(core->ocs); 356 core->ocs = NULL; 357 return ret; 358} 359 360static void venus_remove_dynamic_nodes(struct venus_core *core) 361{ 362 if (core->ocs) { 363 of_changeset_revert(core->ocs); 364 of_changeset_destroy(core->ocs); 365 kfree(core->ocs); 366 } 367} 368#else 369static int venus_add_dynamic_nodes(struct venus_core *core) 370{ 371 return 0; 372} 373 374static void venus_remove_dynamic_nodes(struct venus_core *core) {} 375#endif 376 377static int venus_probe(struct platform_device *pdev) 378{ 379 struct device *dev = &pdev->dev; 380 struct venus_core *core; 381 int ret; 382 383 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); 384 if (!core) 385 return -ENOMEM; 386 387 core->dev = dev; 388 389 core->base = devm_platform_ioremap_resource(pdev, 0); 390 if (IS_ERR(core->base)) 391 return PTR_ERR(core->base); 392 393 core->video_path = devm_of_icc_get(dev, "video-mem"); 394 if (IS_ERR(core->video_path)) 395 return PTR_ERR(core->video_path); 396 397 core->cpucfg_path = devm_of_icc_get(dev, "cpu-cfg"); 398 if (IS_ERR(core->cpucfg_path)) 399 return PTR_ERR(core->cpucfg_path); 400 401 core->irq = platform_get_irq(pdev, 0); 402 if (core->irq < 0) 403 return core->irq; 404 405 core->res = of_device_get_match_data(dev); 406 if (!core->res) 407 return -ENODEV; 408 409 mutex_init(&core->pm_lock); 410 411 core->pm_ops = venus_pm_get(core->res->hfi_version); 412 if (!core->pm_ops) 413 return -ENODEV; 414 415 if (core->pm_ops->core_get) { 416 ret = core->pm_ops->core_get(core); 417 if (ret) 418 return ret; 419 } 420 421 ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); 422 if (ret) 423 goto err_core_put; 424 425 dma_set_max_seg_size(dev, UINT_MAX); 426 427 INIT_LIST_HEAD(&core->instances); 428 mutex_init(&core->lock); 429 INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); 430 init_waitqueue_head(&core->sys_err_done); 431 432 ret = hfi_create(core, &venus_core_ops); 433 if (ret) 434 goto err_core_put; 435 436 ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, 437 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 438 "venus", core); 439 if (ret) 440 goto err_core_put; 441 442 venus_assign_register_offsets(core); 443 444 ret = v4l2_device_register(dev, &core->v4l2_dev); 445 if (ret) 446 goto err_hfi_destroy; 447 448 platform_set_drvdata(pdev, core); 449 450 pm_runtime_enable(dev); 451 452 ret = pm_runtime_get_sync(dev); 453 if (ret < 0) 454 goto err_runtime_disable; 455 456 ret = venus_firmware_init(core); 457 if (ret) 458 goto err_runtime_disable; 459 460 ret = venus_boot(core); 461 if (ret) 462 goto err_firmware_deinit; 463 464 ret = venus_firmware_cfg(core); 465 if (ret) 466 goto err_venus_shutdown; 467 468 ret = hfi_core_resume(core, true); 469 if (ret) 470 goto err_venus_shutdown; 471 472 ret = hfi_core_init(core); 473 if (ret) 474 goto err_venus_shutdown; 475 476 ret = venus_firmware_check(core); 477 if (ret) 478 goto err_core_deinit; 479 480 if (core->res->dec_nodename || core->res->enc_nodename) { 481 ret = venus_add_dynamic_nodes(core); 482 if (ret) 483 goto err_core_deinit; 484 } 485 486 ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 487 if (ret) 488 goto err_remove_dynamic_nodes; 489 490 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); 491 if (ret) 492 goto err_of_depopulate; 493 494 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); 495 if (ret) 496 goto err_of_depopulate; 497 498 ret = pm_runtime_put_sync(dev); 499 if (ret) { 500 pm_runtime_get_noresume(dev); 501 goto err_of_depopulate; 502 } 503 504 venus_dbgfs_init(core); 505 506 return 0; 507 508err_of_depopulate: 509 of_platform_depopulate(dev); 510err_remove_dynamic_nodes: 511 venus_remove_dynamic_nodes(core); 512err_core_deinit: 513 hfi_core_deinit(core, false); 514err_venus_shutdown: 515 venus_shutdown(core); 516err_firmware_deinit: 517 venus_firmware_deinit(core); 518err_runtime_disable: 519 pm_runtime_put_noidle(dev); 520 pm_runtime_disable(dev); 521 pm_runtime_set_suspended(dev); 522 v4l2_device_unregister(&core->v4l2_dev); 523err_hfi_destroy: 524 hfi_destroy(core); 525err_core_put: 526 if (core->pm_ops->core_put) 527 core->pm_ops->core_put(core); 528 return ret; 529} 530 531static void venus_remove(struct platform_device *pdev) 532{ 533 struct venus_core *core = platform_get_drvdata(pdev); 534 const struct venus_pm_ops *pm_ops = core->pm_ops; 535 struct device *dev = core->dev; 536 int ret; 537 538 cancel_delayed_work_sync(&core->work); 539 ret = pm_runtime_get_sync(dev); 540 WARN_ON(ret < 0); 541 542 ret = hfi_core_deinit(core, true); 543 WARN_ON(ret); 544 545 venus_shutdown(core); 546 of_platform_depopulate(dev); 547 548 venus_firmware_deinit(core); 549 550 venus_remove_dynamic_nodes(core); 551 552 pm_runtime_put_sync(dev); 553 pm_runtime_disable(dev); 554 555 if (pm_ops->core_put) 556 pm_ops->core_put(core); 557 558 v4l2_device_unregister(&core->v4l2_dev); 559 560 hfi_destroy(core); 561 562 mutex_destroy(&core->pm_lock); 563 mutex_destroy(&core->lock); 564 venus_dbgfs_deinit(core); 565} 566 567static void venus_core_shutdown(struct platform_device *pdev) 568{ 569 struct venus_core *core = platform_get_drvdata(pdev); 570 571 pm_runtime_get_sync(core->dev); 572 venus_shutdown(core); 573 venus_firmware_deinit(core); 574 pm_runtime_put_sync(core->dev); 575} 576 577static __maybe_unused int venus_runtime_suspend(struct device *dev) 578{ 579 struct venus_core *core = dev_get_drvdata(dev); 580 const struct venus_pm_ops *pm_ops = core->pm_ops; 581 int ret; 582 583 ret = hfi_core_suspend(core); 584 if (ret) 585 return ret; 586 587 if (pm_ops->core_power) { 588 ret = pm_ops->core_power(core, POWER_OFF); 589 if (ret) 590 return ret; 591 } 592 593 ret = icc_set_bw(core->cpucfg_path, 0, 0); 594 if (ret) 595 goto err_cpucfg_path; 596 597 ret = icc_set_bw(core->video_path, 0, 0); 598 if (ret) 599 goto err_video_path; 600 601 return ret; 602 603err_video_path: 604 icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 605err_cpucfg_path: 606 if (pm_ops->core_power) 607 pm_ops->core_power(core, POWER_ON); 608 609 return ret; 610} 611 612void venus_close_common(struct venus_inst *inst, struct file *filp) 613{ 614 /* 615 * Make sure we don't have IRQ/IRQ-thread currently running 616 * or pending execution, which would race with the inst destruction. 617 */ 618 synchronize_irq(inst->core->irq); 619 620 v4l2_m2m_ctx_release(inst->m2m_ctx); 621 v4l2_m2m_release(inst->m2m_dev); 622 hfi_session_destroy(inst); 623 v4l2_fh_del(&inst->fh, filp); 624 v4l2_fh_exit(&inst->fh); 625 v4l2_ctrl_handler_free(&inst->ctrl_handler); 626 627 mutex_destroy(&inst->lock); 628 mutex_destroy(&inst->ctx_q_lock); 629} 630EXPORT_SYMBOL_GPL(venus_close_common); 631 632static __maybe_unused int venus_runtime_resume(struct device *dev) 633{ 634 struct venus_core *core = dev_get_drvdata(dev); 635 const struct venus_pm_ops *pm_ops = core->pm_ops; 636 int ret; 637 638 ret = icc_set_bw(core->video_path, kbps_to_icc(20000), 0); 639 if (ret) 640 return ret; 641 642 ret = icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 643 if (ret) 644 return ret; 645 646 if (pm_ops->core_power) { 647 ret = pm_ops->core_power(core, POWER_ON); 648 if (ret) 649 return ret; 650 } 651 652 return hfi_core_resume(core, false); 653} 654 655static const struct dev_pm_ops venus_pm_ops = { 656 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 657 pm_runtime_force_resume) 658 SET_RUNTIME_PM_OPS(venus_runtime_suspend, venus_runtime_resume, NULL) 659}; 660 661static const struct freq_tbl msm8916_freq_table[] = { 662 { 352800, 228570000 }, /* 1920x1088 @ 30 + 1280x720 @ 30 */ 663 { 244800, 160000000 }, /* 1920x1088 @ 30 */ 664 { 108000, 100000000 }, /* 1280x720 @ 30 */ 665}; 666 667static const struct reg_val msm8916_reg_preset[] = { 668 { 0xe0020, 0x05555556 }, 669 { 0xe0024, 0x05555556 }, 670 { 0x80124, 0x00000003 }, 671}; 672 673static const struct venus_resources msm8916_res = { 674 .freq_tbl = msm8916_freq_table, 675 .freq_tbl_size = ARRAY_SIZE(msm8916_freq_table), 676 .reg_tbl = msm8916_reg_preset, 677 .reg_tbl_size = ARRAY_SIZE(msm8916_reg_preset), 678 .clks = { "core", "iface", "bus", }, 679 .clks_num = 3, 680 .max_load = 352800, /* 720p@30 + 1080p@30 */ 681 .hfi_version = HFI_VERSION_1XX, 682 .vmem_id = VIDC_RESOURCE_NONE, 683 .vmem_size = 0, 684 .vmem_addr = 0, 685 .dma_mask = 0xddc00000 - 1, 686 .fwname = "qcom/venus-1.8/venus.mbn", 687 .dec_nodename = "video-decoder", 688 .enc_nodename = "video-encoder", 689}; 690 691static const struct freq_tbl msm8996_freq_table[] = { 692 { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */ 693 { 972000, 520000000 }, /* 4k UHD @ 30 */ 694 { 489600, 346666667 }, /* 1080p @ 60 */ 695 { 244800, 150000000 }, /* 1080p @ 30 */ 696 { 108000, 75000000 }, /* 720p @ 30 */ 697}; 698 699static const struct reg_val msm8996_reg_preset[] = { 700 { 0x80010, 0xffffffff }, 701 { 0x80018, 0x00001556 }, 702 { 0x8001C, 0x00001556 }, 703}; 704 705static const struct venus_resources msm8996_res = { 706 .freq_tbl = msm8996_freq_table, 707 .freq_tbl_size = ARRAY_SIZE(msm8996_freq_table), 708 .reg_tbl = msm8996_reg_preset, 709 .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), 710 .clks = {"core", "iface", "bus", "mbus" }, 711 .clks_num = 4, 712 .vcodec0_clks = { "core" }, 713 .vcodec1_clks = { "core" }, 714 .vcodec_clks_num = 1, 715 .max_load = 2563200, 716 .hfi_version = HFI_VERSION_3XX, 717 .vmem_id = VIDC_RESOURCE_NONE, 718 .vmem_size = 0, 719 .vmem_addr = 0, 720 .dma_mask = 0xddc00000 - 1, 721 .fwname = "qcom/venus-4.2/venus.mbn", 722}; 723 724static const struct freq_tbl msm8998_freq_table[] = { 725 { 1728000, 533000000 }, /* 4k UHD @ 60 (decode only) */ 726 { 1036800, 444000000 }, /* 2k @ 120 */ 727 { 829440, 355200000 }, /* 4k @ 44 */ 728 { 489600, 269330000 },/* 4k @ 30 */ 729 { 108000, 200000000 }, /* 1080p @ 60 */ 730}; 731 732static const struct reg_val msm8998_reg_preset[] = { 733 { 0x80124, 0x00000003 }, 734 { 0x80550, 0x01111111 }, 735 { 0x80560, 0x01111111 }, 736 { 0x80568, 0x01111111 }, 737 { 0x80570, 0x01111111 }, 738 { 0x80580, 0x01111111 }, 739 { 0x80588, 0x01111111 }, 740 { 0xe2010, 0x00000000 }, 741}; 742 743static const struct venus_resources msm8998_res = { 744 .freq_tbl = msm8998_freq_table, 745 .freq_tbl_size = ARRAY_SIZE(msm8998_freq_table), 746 .reg_tbl = msm8998_reg_preset, 747 .reg_tbl_size = ARRAY_SIZE(msm8998_reg_preset), 748 .clks = { "core", "iface", "bus", "mbus" }, 749 .clks_num = 4, 750 .vcodec0_clks = { "core" }, 751 .vcodec1_clks = { "core" }, 752 .vcodec_clks_num = 1, 753 .max_load = 2563200, 754 .hfi_version = HFI_VERSION_3XX, 755 .vmem_id = VIDC_RESOURCE_NONE, 756 .vmem_size = 0, 757 .vmem_addr = 0, 758 .dma_mask = 0xddc00000 - 1, 759 .fwname = "qcom/venus-4.4/venus.mbn", 760}; 761 762static const struct freq_tbl sdm660_freq_table[] = { 763 { 979200, 518400000 }, 764 { 489600, 441600000 }, 765 { 432000, 404000000 }, 766 { 244800, 320000000 }, 767 { 216000, 269330000 }, 768 { 108000, 133330000 }, 769}; 770 771static const struct reg_val sdm660_reg_preset[] = { 772 { 0x80010, 0x001f001f }, 773 { 0x80018, 0x00000156 }, 774 { 0x8001c, 0x00000156 }, 775}; 776 777static const struct bw_tbl sdm660_bw_table_enc[] = { 778 { 979200, 1044000, 0, 2446336, 0 }, /* 4k UHD @ 30 */ 779 { 864000, 887000, 0, 2108416, 0 }, /* 720p @ 240 */ 780 { 489600, 666000, 0, 1207296, 0 }, /* 1080p @ 60 */ 781 { 432000, 578000, 0, 1058816, 0 }, /* 720p @ 120 */ 782 { 244800, 346000, 0, 616448, 0 }, /* 1080p @ 30 */ 783 { 216000, 293000, 0, 534528, 0 }, /* 720p @ 60 */ 784 { 108000, 151000, 0, 271360, 0 }, /* 720p @ 30 */ 785}; 786 787static const struct bw_tbl sdm660_bw_table_dec[] = { 788 { 979200, 2365000, 0, 1892000, 0 }, /* 4k UHD @ 30 */ 789 { 864000, 1978000, 0, 1554000, 0 }, /* 720p @ 240 */ 790 { 489600, 1133000, 0, 895000, 0 }, /* 1080p @ 60 */ 791 { 432000, 994000, 0, 781000, 0 }, /* 720p @ 120 */ 792 { 244800, 580000, 0, 460000, 0 }, /* 1080p @ 30 */ 793 { 216000, 501000, 0, 301000, 0 }, /* 720p @ 60 */ 794 { 108000, 255000, 0, 202000, 0 }, /* 720p @ 30 */ 795}; 796 797static const struct venus_resources sdm660_res = { 798 .freq_tbl = sdm660_freq_table, 799 .freq_tbl_size = ARRAY_SIZE(sdm660_freq_table), 800 .reg_tbl = sdm660_reg_preset, 801 .reg_tbl_size = ARRAY_SIZE(sdm660_reg_preset), 802 .bw_tbl_enc = sdm660_bw_table_enc, 803 .bw_tbl_enc_size = ARRAY_SIZE(sdm660_bw_table_enc), 804 .bw_tbl_dec = sdm660_bw_table_dec, 805 .bw_tbl_dec_size = ARRAY_SIZE(sdm660_bw_table_dec), 806 .clks = {"core", "iface", "bus", "bus_throttle" }, 807 .clks_num = 4, 808 .vcodec0_clks = { "vcodec0_core" }, 809 .vcodec1_clks = { "vcodec0_core" }, 810 .vcodec_clks_num = 1, 811 .vcodec_num = 1, 812 .max_load = 1036800, 813 .hfi_version = HFI_VERSION_3XX, 814 .vmem_id = VIDC_RESOURCE_NONE, 815 .vmem_size = 0, 816 .vmem_addr = 0, 817 .cp_start = 0, 818 .cp_size = 0x79000000, 819 .cp_nonpixel_start = 0x1000000, 820 .cp_nonpixel_size = 0x28000000, 821 .dma_mask = 0xd9000000 - 1, 822 .fwname = "qcom/venus-4.4/venus.mdt", 823}; 824 825static const struct freq_tbl sdm845_freq_table[] = { 826 { 3110400, 533000000 }, /* 4096x2160@90 */ 827 { 2073600, 444000000 }, /* 4096x2160@60 */ 828 { 1944000, 404000000 }, /* 3840x2160@60 */ 829 { 972000, 330000000 }, /* 3840x2160@30 */ 830 { 489600, 200000000 }, /* 1920x1080@60 */ 831 { 244800, 100000000 }, /* 1920x1080@30 */ 832}; 833 834static const struct bw_tbl sdm845_bw_table_enc[] = { 835 { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */ 836 { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */ 837 { 489600, 723000, 0, 973000, 0 }, /* 1920x1080@60 */ 838 { 244800, 370000, 0, 495000, 0 }, /* 1920x1080@30 */ 839}; 840 841static const struct bw_tbl sdm845_bw_table_dec[] = { 842 { 2073600, 3929000, 0, 5551000, 0 }, /* 4096x2160@60 */ 843 { 1036800, 1987000, 0, 2797000, 0 }, /* 4096x2160@30 */ 844 { 489600, 1040000, 0, 1298000, 0 }, /* 1920x1080@60 */ 845 { 244800, 530000, 0, 659000, 0 }, /* 1920x1080@30 */ 846}; 847 848static const struct venus_resources sdm845_res = { 849 .freq_tbl = sdm845_freq_table, 850 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 851 .bw_tbl_enc = sdm845_bw_table_enc, 852 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 853 .bw_tbl_dec = sdm845_bw_table_dec, 854 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 855 .clks = {"core", "iface", "bus" }, 856 .clks_num = 3, 857 .vcodec0_clks = { "core", "bus" }, 858 .vcodec1_clks = { "core", "bus" }, 859 .vcodec_clks_num = 2, 860 .max_load = 3110400, /* 4096x2160@90 */ 861 .hfi_version = HFI_VERSION_4XX, 862 .vpu_version = VPU_VERSION_AR50, 863 .vmem_id = VIDC_RESOURCE_NONE, 864 .vmem_size = 0, 865 .vmem_addr = 0, 866 .dma_mask = 0xe0000000 - 1, 867 .fwname = "qcom/venus-5.2/venus.mbn", 868}; 869 870static const struct venus_resources sdm845_res_v2 = { 871 .freq_tbl = sdm845_freq_table, 872 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 873 .bw_tbl_enc = sdm845_bw_table_enc, 874 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 875 .bw_tbl_dec = sdm845_bw_table_dec, 876 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 877 .clks = {"core", "iface", "bus" }, 878 .clks_num = 3, 879 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 880 .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, 881 .vcodec_clks_num = 2, 882 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, 883 .vcodec_pmdomains_num = 3, 884 .opp_pmdomain = (const char *[]) { "cx" }, 885 .vcodec_num = 2, 886 .max_load = 3110400, /* 4096x2160@90 */ 887 .hfi_version = HFI_VERSION_4XX, 888 .vpu_version = VPU_VERSION_AR50, 889 .vmem_id = VIDC_RESOURCE_NONE, 890 .vmem_size = 0, 891 .vmem_addr = 0, 892 .dma_mask = 0xe0000000 - 1, 893 .cp_start = 0, 894 .cp_size = 0x70800000, 895 .cp_nonpixel_start = 0x1000000, 896 .cp_nonpixel_size = 0x24800000, 897 .fwname = "qcom/venus-5.2/venus.mbn", 898 .dec_nodename = "video-core0", 899 .enc_nodename = "video-core1", 900}; 901 902static const struct freq_tbl sc7180_freq_table[] = { 903 { 0, 500000000 }, 904 { 0, 434000000 }, 905 { 0, 340000000 }, 906 { 0, 270000000 }, 907 { 0, 150000000 }, 908}; 909 910static const struct bw_tbl sc7180_bw_table_enc[] = { 911 { 972000, 750000, 0, 0, 0 }, /* 3840x2160@30 */ 912 { 489600, 451000, 0, 0, 0 }, /* 1920x1080@60 */ 913 { 244800, 234000, 0, 0, 0 }, /* 1920x1080@30 */ 914}; 915 916static const struct bw_tbl sc7180_bw_table_dec[] = { 917 { 1036800, 1386000, 0, 1875000, 0 }, /* 4096x2160@30 */ 918 { 489600, 865000, 0, 1146000, 0 }, /* 1920x1080@60 */ 919 { 244800, 530000, 0, 583000, 0 }, /* 1920x1080@30 */ 920}; 921 922static const struct venus_resources sc7180_res = { 923 .freq_tbl = sc7180_freq_table, 924 .freq_tbl_size = ARRAY_SIZE(sc7180_freq_table), 925 .bw_tbl_enc = sc7180_bw_table_enc, 926 .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc), 927 .bw_tbl_dec = sc7180_bw_table_dec, 928 .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec), 929 .clks = {"core", "iface", "bus" }, 930 .clks_num = 3, 931 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 932 .vcodec_clks_num = 2, 933 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 934 .vcodec_pmdomains_num = 2, 935 .opp_pmdomain = (const char *[]) { "cx" }, 936 .vcodec_num = 1, 937 .hfi_version = HFI_VERSION_4XX, 938 .vpu_version = VPU_VERSION_AR50, 939 .vmem_id = VIDC_RESOURCE_NONE, 940 .vmem_size = 0, 941 .vmem_addr = 0, 942 .dma_mask = 0xe0000000 - 1, 943 .cp_start = 0, 944 .cp_size = 0x70800000, 945 .cp_nonpixel_start = 0x1000000, 946 .cp_nonpixel_size = 0x24800000, 947 .fwname = "qcom/venus-5.4/venus.mbn", 948 .dec_nodename = "video-decoder", 949 .enc_nodename = "video-encoder", 950}; 951 952static const struct freq_tbl sm8250_freq_table[] = { 953 { 0, 444000000 }, 954 { 0, 366000000 }, 955 { 0, 338000000 }, 956 { 0, 240000000 }, 957}; 958 959static const struct bw_tbl sm8250_bw_table_enc[] = { 960 { 1944000, 1954000, 0, 3711000, 0 }, /* 3840x2160@60 */ 961 { 972000, 996000, 0, 1905000, 0 }, /* 3840x2160@30 */ 962 { 489600, 645000, 0, 977000, 0 }, /* 1920x1080@60 */ 963 { 244800, 332000, 0, 498000, 0 }, /* 1920x1080@30 */ 964}; 965 966static const struct bw_tbl sm8250_bw_table_dec[] = { 967 { 2073600, 2403000, 0, 4113000, 0 }, /* 4096x2160@60 */ 968 { 1036800, 1224000, 0, 2079000, 0 }, /* 4096x2160@30 */ 969 { 489600, 812000, 0, 998000, 0 }, /* 1920x1080@60 */ 970 { 244800, 416000, 0, 509000, 0 }, /* 1920x1080@30 */ 971}; 972 973static const struct reg_val sm8250_reg_preset[] = { 974 { 0xb0088, 0 }, 975}; 976 977static const struct venus_resources sm8250_res = { 978 .freq_tbl = sm8250_freq_table, 979 .freq_tbl_size = ARRAY_SIZE(sm8250_freq_table), 980 .reg_tbl = sm8250_reg_preset, 981 .reg_tbl_size = ARRAY_SIZE(sm8250_reg_preset), 982 .bw_tbl_enc = sm8250_bw_table_enc, 983 .bw_tbl_enc_size = ARRAY_SIZE(sm8250_bw_table_enc), 984 .bw_tbl_dec = sm8250_bw_table_dec, 985 .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), 986 .clks = {"core", "iface"}, 987 .clks_num = 2, 988 .resets = { "bus", "core" }, 989 .resets_num = 2, 990 .vcodec0_clks = { "vcodec0_core" }, 991 .vcodec_clks_num = 1, 992 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 993 .vcodec_pmdomains_num = 2, 994 .opp_pmdomain = (const char *[]) { "mx" }, 995 .vcodec_num = 1, 996 .max_load = 7833600, 997 .hfi_version = HFI_VERSION_6XX, 998 .vpu_version = VPU_VERSION_IRIS2, 999 .num_vpp_pipes = 4, 1000 .vmem_id = VIDC_RESOURCE_NONE, 1001 .vmem_size = 0, 1002 .vmem_addr = 0, 1003 .dma_mask = 0xe0000000 - 1, 1004 .fwname = "qcom/vpu-1.0/venus.mbn", 1005 .dec_nodename = "video-decoder", 1006 .enc_nodename = "video-encoder", 1007}; 1008 1009static const struct freq_tbl sc7280_freq_table[] = { 1010 { 0, 460000000 }, 1011 { 0, 424000000 }, 1012 { 0, 335000000 }, 1013 { 0, 240000000 }, 1014 { 0, 133333333 }, 1015}; 1016 1017static const struct bw_tbl sc7280_bw_table_enc[] = { 1018 { 1944000, 1896000, 0, 3657000, 0 }, /* 3840x2160@60 */ 1019 { 972000, 968000, 0, 1848000, 0 }, /* 3840x2160@30 */ 1020 { 489600, 618000, 0, 941000, 0 }, /* 1920x1080@60 */ 1021 { 244800, 318000, 0, 480000, 0 }, /* 1920x1080@30 */ 1022}; 1023 1024static const struct bw_tbl sc7280_bw_table_dec[] = { 1025 { 2073600, 2128000, 0, 3831000, 0 }, /* 4096x2160@60 */ 1026 { 1036800, 1085000, 0, 1937000, 0 }, /* 4096x2160@30 */ 1027 { 489600, 779000, 0, 998000, 0 }, /* 1920x1080@60 */ 1028 { 244800, 400000, 0, 509000, 0 }, /* 1920x1080@30 */ 1029}; 1030 1031static const struct reg_val sm7280_reg_preset[] = { 1032 { 0xb0088, 0 }, 1033}; 1034 1035static const struct hfi_ubwc_config sc7280_ubwc_config = { 1036 0, 0, {1, 1, 1, 0, 0, 0}, 8, 32, 14, 0, 0, {0, 0} 1037}; 1038 1039static const struct venus_resources sc7280_res = { 1040 .freq_tbl = sc7280_freq_table, 1041 .freq_tbl_size = ARRAY_SIZE(sc7280_freq_table), 1042 .reg_tbl = sm7280_reg_preset, 1043 .reg_tbl_size = ARRAY_SIZE(sm7280_reg_preset), 1044 .bw_tbl_enc = sc7280_bw_table_enc, 1045 .bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc), 1046 .bw_tbl_dec = sc7280_bw_table_dec, 1047 .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), 1048 .ubwc_conf = &sc7280_ubwc_config, 1049 .clks = {"core", "bus", "iface"}, 1050 .clks_num = 3, 1051 .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, 1052 .vcodec_clks_num = 2, 1053 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 1054 .vcodec_pmdomains_num = 2, 1055 .opp_pmdomain = (const char *[]) { "cx" }, 1056 .vcodec_num = 1, 1057 .hfi_version = HFI_VERSION_6XX, 1058 .vpu_version = VPU_VERSION_IRIS2_1, 1059 .num_vpp_pipes = 1, 1060 .vmem_id = VIDC_RESOURCE_NONE, 1061 .vmem_size = 0, 1062 .vmem_addr = 0, 1063 .dma_mask = 0xe0000000 - 1, 1064 .cp_start = 0, 1065 .cp_size = 0x25800000, 1066 .cp_nonpixel_start = 0x1000000, 1067 .cp_nonpixel_size = 0x24800000, 1068 .fwname = "qcom/vpu-2.0/venus.mbn", 1069 .dec_nodename = "video-decoder", 1070 .enc_nodename = "video-encoder", 1071}; 1072 1073static const struct bw_tbl qcm2290_bw_table_dec[] = { 1074 { 352800, 597000, 0, 746000, 0 }, /* 1080p@30 + 720p@30 */ 1075 { 244800, 413000, 0, 516000, 0 }, /* 1080p@30 */ 1076 { 216000, 364000, 0, 454000, 0 }, /* 720p@60 */ 1077 { 108000, 182000, 0, 227000, 0 }, /* 720p@30 */ 1078}; 1079 1080static const struct bw_tbl qcm2290_bw_table_enc[] = { 1081 { 352800, 396000, 0, 0, 0 }, /* 1080p@30 + 720p@30 */ 1082 { 244800, 275000, 0, 0, 0 }, /* 1080p@30 */ 1083 { 216000, 242000, 0, 0, 0 }, /* 720p@60 */ 1084 { 108000, 121000, 0, 0, 0 }, /* 720p@30 */ 1085}; 1086 1087static const struct firmware_version min_fw = { 1088 .major = 6, .minor = 0, .rev = 55, 1089}; 1090 1091static const struct venus_resources qcm2290_res = { 1092 .bw_tbl_dec = qcm2290_bw_table_dec, 1093 .bw_tbl_dec_size = ARRAY_SIZE(qcm2290_bw_table_dec), 1094 .bw_tbl_enc = qcm2290_bw_table_enc, 1095 .bw_tbl_enc_size = ARRAY_SIZE(qcm2290_bw_table_enc), 1096 .clks = { "core", "iface", "bus", "throttle" }, 1097 .clks_num = 4, 1098 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 1099 .vcodec_clks_num = 2, 1100 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 1101 .vcodec_pmdomains_num = 2, 1102 .opp_pmdomain = (const char *[]) { "cx" }, 1103 .vcodec_num = 1, 1104 .hfi_version = HFI_VERSION_4XX, 1105 .vpu_version = VPU_VERSION_AR50_LITE, 1106 .max_load = 352800, 1107 .num_vpp_pipes = 1, 1108 .vmem_id = VIDC_RESOURCE_NONE, 1109 .vmem_size = 0, 1110 .vmem_addr = 0, 1111 .cp_start = 0, 1112 .cp_size = 0x70800000, 1113 .cp_nonpixel_start = 0x1000000, 1114 .cp_nonpixel_size = 0x24800000, 1115 .dma_mask = 0xe0000000 - 1, 1116 .fwname = "qcom/venus-6.0/venus.mbn", 1117 .dec_nodename = "video-decoder", 1118 .enc_nodename = "video-encoder", 1119 .min_fw = &min_fw, 1120}; 1121 1122static const struct of_device_id venus_dt_match[] = { 1123 { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, 1124 { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, 1125 { .compatible = "qcom,msm8998-venus", .data = &msm8998_res, }, 1126 { .compatible = "qcom,qcm2290-venus", .data = &qcm2290_res, }, 1127 { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, 1128 { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, 1129 { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, 1130 { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, 1131 { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, 1132 { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, 1133 { } 1134}; 1135MODULE_DEVICE_TABLE(of, venus_dt_match); 1136 1137static struct platform_driver qcom_venus_driver = { 1138 .probe = venus_probe, 1139 .remove = venus_remove, 1140 .driver = { 1141 .name = "qcom-venus", 1142 .of_match_table = venus_dt_match, 1143 .pm = &venus_pm_ops, 1144 }, 1145 .shutdown = venus_core_shutdown, 1146}; 1147module_platform_driver(qcom_venus_driver); 1148 1149MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); 1150MODULE_LICENSE("GPL v2");
~/
Read-only file preview.