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-mem2mem.h> 23#include <media/v4l2-ioctl.h> 24 25#include "core.h" 26#include "firmware.h" 27#include "pm_helpers.h" 28#include "hfi_venus_io.h" 29 30static void venus_coredump(struct venus_core *core) 31{ 32 struct device *dev; 33 phys_addr_t mem_phys; 34 size_t mem_size; 35 void *mem_va; 36 void *data; 37 38 dev = core->dev; 39 mem_phys = core->fw.mem_phys; 40 mem_size = core->fw.mem_size; 41 42 mem_va = memremap(mem_phys, mem_size, MEMREMAP_WC); 43 if (!mem_va) 44 return; 45 46 data = vmalloc(mem_size); 47 if (!data) { 48 memunmap(mem_va); 49 return; 50 } 51 52 memcpy(data, mem_va, mem_size); 53 memunmap(mem_va); 54 dev_coredumpv(dev, data, mem_size, GFP_KERNEL); 55} 56 57static void venus_event_notify(struct venus_core *core, u32 event) 58{ 59 struct venus_inst *inst; 60 61 switch (event) { 62 case EVT_SYS_WATCHDOG_TIMEOUT: 63 case EVT_SYS_ERROR: 64 break; 65 default: 66 return; 67 } 68 69 mutex_lock(&core->lock); 70 set_bit(0, &core->sys_error); 71 list_for_each_entry(inst, &core->instances, list) 72 inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); 73 mutex_unlock(&core->lock); 74 75 disable_irq_nosync(core->irq); 76 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 77} 78 79static const struct hfi_core_ops venus_core_ops = { 80 .event_notify = venus_event_notify, 81}; 82 83#define RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS 10 84 85static void venus_sys_error_handler(struct work_struct *work) 86{ 87 struct venus_core *core = 88 container_of(work, struct venus_core, work.work); 89 int ret, i, max_attempts = RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS; 90 const char *err_msg = ""; 91 bool failed = false; 92 93 ret = pm_runtime_get_sync(core->dev); 94 if (ret < 0) { 95 err_msg = "resume runtime PM"; 96 max_attempts = 0; 97 failed = true; 98 } 99 100 core->ops->core_deinit(core); 101 core->state = CORE_UNINIT; 102 103 for (i = 0; i < max_attempts; i++) { 104 if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc)) 105 break; 106 msleep(10); 107 } 108 109 mutex_lock(&core->lock); 110 111 venus_shutdown(core); 112 113 venus_coredump(core); 114 115 pm_runtime_put_sync(core->dev); 116 117 for (i = 0; i < max_attempts; i++) { 118 if (!core->pmdomains || 119 !pm_runtime_active(core->pmdomains->pd_devs[0])) 120 break; 121 usleep_range(1000, 1500); 122 } 123 124 hfi_reinit(core); 125 126 ret = pm_runtime_get_sync(core->dev); 127 if (ret < 0) { 128 err_msg = "resume runtime PM"; 129 failed = true; 130 } 131 132 ret = venus_boot(core); 133 if (ret && !failed) { 134 err_msg = "boot Venus"; 135 failed = true; 136 } 137 138 ret = hfi_core_resume(core, true); 139 if (ret && !failed) { 140 err_msg = "resume HFI"; 141 failed = true; 142 } 143 144 enable_irq(core->irq); 145 146 mutex_unlock(&core->lock); 147 148 ret = hfi_core_init(core); 149 if (ret && !failed) { 150 err_msg = "init HFI"; 151 failed = true; 152 } 153 154 pm_runtime_put_sync(core->dev); 155 156 if (failed) { 157 disable_irq_nosync(core->irq); 158 dev_warn_ratelimited(core->dev, 159 "System error has occurred, recovery failed to %s\n", 160 err_msg); 161 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 162 return; 163 } 164 165 dev_warn(core->dev, "system error has occurred (recovered)\n"); 166 167 mutex_lock(&core->lock); 168 clear_bit(0, &core->sys_error); 169 wake_up_all(&core->sys_err_done); 170 mutex_unlock(&core->lock); 171} 172 173static u32 to_v4l2_codec_type(u32 codec) 174{ 175 switch (codec) { 176 case HFI_VIDEO_CODEC_H264: 177 return V4L2_PIX_FMT_H264; 178 case HFI_VIDEO_CODEC_H263: 179 return V4L2_PIX_FMT_H263; 180 case HFI_VIDEO_CODEC_MPEG1: 181 return V4L2_PIX_FMT_MPEG1; 182 case HFI_VIDEO_CODEC_MPEG2: 183 return V4L2_PIX_FMT_MPEG2; 184 case HFI_VIDEO_CODEC_MPEG4: 185 return V4L2_PIX_FMT_MPEG4; 186 case HFI_VIDEO_CODEC_VC1: 187 return V4L2_PIX_FMT_VC1_ANNEX_G; 188 case HFI_VIDEO_CODEC_VP8: 189 return V4L2_PIX_FMT_VP8; 190 case HFI_VIDEO_CODEC_VP9: 191 return V4L2_PIX_FMT_VP9; 192 case HFI_VIDEO_CODEC_DIVX: 193 case HFI_VIDEO_CODEC_DIVX_311: 194 return V4L2_PIX_FMT_XVID; 195 default: 196 return 0; 197 } 198} 199 200static int venus_enumerate_codecs(struct venus_core *core, u32 type) 201{ 202 const struct hfi_inst_ops dummy_ops = {}; 203 struct venus_inst *inst; 204 u32 codec, codecs; 205 unsigned int i; 206 int ret; 207 208 if (core->res->hfi_version != HFI_VERSION_1XX) 209 return 0; 210 211 inst = kzalloc(sizeof(*inst), GFP_KERNEL); 212 if (!inst) 213 return -ENOMEM; 214 215 mutex_init(&inst->lock); 216 inst->core = core; 217 inst->session_type = type; 218 if (type == VIDC_SESSION_TYPE_DEC) 219 codecs = core->dec_codecs; 220 else 221 codecs = core->enc_codecs; 222 223 ret = hfi_session_create(inst, &dummy_ops); 224 if (ret) 225 goto err; 226 227 for (i = 0; i < MAX_CODEC_NUM; i++) { 228 codec = (1UL << i) & codecs; 229 if (!codec) 230 continue; 231 232 ret = hfi_session_init(inst, to_v4l2_codec_type(codec)); 233 if (ret) 234 goto done; 235 236 ret = hfi_session_deinit(inst); 237 if (ret) 238 goto done; 239 } 240 241done: 242 hfi_session_destroy(inst); 243err: 244 mutex_destroy(&inst->lock); 245 kfree(inst); 246 247 return ret; 248} 249 250static void venus_assign_register_offsets(struct venus_core *core) 251{ 252 if (IS_IRIS2(core) || IS_IRIS2_1(core)) { 253 core->vbif_base = core->base + VBIF_BASE; 254 core->cpu_base = core->base + CPU_BASE_V6; 255 core->cpu_cs_base = core->base + CPU_CS_BASE_V6; 256 core->cpu_ic_base = core->base + CPU_IC_BASE_V6; 257 core->wrapper_base = core->base + WRAPPER_BASE_V6; 258 core->wrapper_tz_base = core->base + WRAPPER_TZ_BASE_V6; 259 core->aon_base = core->base + AON_BASE_V6; 260 } else { 261 core->vbif_base = core->base + VBIF_BASE; 262 core->cpu_base = core->base + CPU_BASE; 263 core->cpu_cs_base = core->base + CPU_CS_BASE; 264 core->cpu_ic_base = core->base + CPU_IC_BASE; 265 core->wrapper_base = core->base + WRAPPER_BASE; 266 core->wrapper_tz_base = NULL; 267 core->aon_base = NULL; 268 } 269} 270 271static irqreturn_t venus_isr_thread(int irq, void *dev_id) 272{ 273 struct venus_core *core = dev_id; 274 irqreturn_t ret; 275 276 ret = hfi_isr_thread(irq, dev_id); 277 278 if (ret == IRQ_HANDLED && venus_fault_inject_ssr()) 279 hfi_core_trigger_ssr(core, HFI_TEST_SSR_SW_ERR_FATAL); 280 281 return ret; 282} 283 284static int venus_probe(struct platform_device *pdev) 285{ 286 struct device *dev = &pdev->dev; 287 struct venus_core *core; 288 int ret; 289 290 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); 291 if (!core) 292 return -ENOMEM; 293 294 core->dev = dev; 295 296 core->base = devm_platform_ioremap_resource(pdev, 0); 297 if (IS_ERR(core->base)) 298 return PTR_ERR(core->base); 299 300 core->video_path = devm_of_icc_get(dev, "video-mem"); 301 if (IS_ERR(core->video_path)) 302 return PTR_ERR(core->video_path); 303 304 core->cpucfg_path = devm_of_icc_get(dev, "cpu-cfg"); 305 if (IS_ERR(core->cpucfg_path)) 306 return PTR_ERR(core->cpucfg_path); 307 308 core->irq = platform_get_irq(pdev, 0); 309 if (core->irq < 0) 310 return core->irq; 311 312 core->res = of_device_get_match_data(dev); 313 if (!core->res) 314 return -ENODEV; 315 316 mutex_init(&core->pm_lock); 317 318 core->pm_ops = venus_pm_get(core->res->hfi_version); 319 if (!core->pm_ops) 320 return -ENODEV; 321 322 if (core->pm_ops->core_get) { 323 ret = core->pm_ops->core_get(core); 324 if (ret) 325 return ret; 326 } 327 328 ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); 329 if (ret) 330 goto err_core_put; 331 332 dma_set_max_seg_size(dev, UINT_MAX); 333 334 INIT_LIST_HEAD(&core->instances); 335 mutex_init(&core->lock); 336 INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); 337 init_waitqueue_head(&core->sys_err_done); 338 339 ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, 340 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 341 "venus", core); 342 if (ret) 343 goto err_core_put; 344 345 ret = hfi_create(core, &venus_core_ops); 346 if (ret) 347 goto err_core_put; 348 349 venus_assign_register_offsets(core); 350 351 ret = v4l2_device_register(dev, &core->v4l2_dev); 352 if (ret) 353 goto err_core_deinit; 354 355 platform_set_drvdata(pdev, core); 356 357 pm_runtime_enable(dev); 358 359 ret = pm_runtime_get_sync(dev); 360 if (ret < 0) 361 goto err_runtime_disable; 362 363 ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 364 if (ret) 365 goto err_runtime_disable; 366 367 ret = venus_firmware_init(core); 368 if (ret) 369 goto err_of_depopulate; 370 371 ret = venus_boot(core); 372 if (ret) 373 goto err_firmware_deinit; 374 375 ret = hfi_core_resume(core, true); 376 if (ret) 377 goto err_venus_shutdown; 378 379 ret = hfi_core_init(core); 380 if (ret) 381 goto err_venus_shutdown; 382 383 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); 384 if (ret) 385 goto err_venus_shutdown; 386 387 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); 388 if (ret) 389 goto err_venus_shutdown; 390 391 ret = pm_runtime_put_sync(dev); 392 if (ret) { 393 pm_runtime_get_noresume(dev); 394 goto err_dev_unregister; 395 } 396 397 venus_dbgfs_init(core); 398 399 return 0; 400 401err_dev_unregister: 402 v4l2_device_unregister(&core->v4l2_dev); 403err_venus_shutdown: 404 venus_shutdown(core); 405err_firmware_deinit: 406 venus_firmware_deinit(core); 407err_of_depopulate: 408 of_platform_depopulate(dev); 409err_runtime_disable: 410 pm_runtime_put_noidle(dev); 411 pm_runtime_set_suspended(dev); 412 pm_runtime_disable(dev); 413 hfi_destroy(core); 414err_core_deinit: 415 hfi_core_deinit(core, false); 416err_core_put: 417 if (core->pm_ops->core_put) 418 core->pm_ops->core_put(core); 419 return ret; 420} 421 422static void venus_remove(struct platform_device *pdev) 423{ 424 struct venus_core *core = platform_get_drvdata(pdev); 425 const struct venus_pm_ops *pm_ops = core->pm_ops; 426 struct device *dev = core->dev; 427 int ret; 428 429 ret = pm_runtime_get_sync(dev); 430 WARN_ON(ret < 0); 431 432 ret = hfi_core_deinit(core, true); 433 WARN_ON(ret); 434 435 venus_shutdown(core); 436 of_platform_depopulate(dev); 437 438 venus_firmware_deinit(core); 439 440 pm_runtime_put_sync(dev); 441 pm_runtime_disable(dev); 442 443 if (pm_ops->core_put) 444 pm_ops->core_put(core); 445 446 v4l2_device_unregister(&core->v4l2_dev); 447 448 hfi_destroy(core); 449 450 mutex_destroy(&core->pm_lock); 451 mutex_destroy(&core->lock); 452 venus_dbgfs_deinit(core); 453} 454 455static void venus_core_shutdown(struct platform_device *pdev) 456{ 457 struct venus_core *core = platform_get_drvdata(pdev); 458 459 pm_runtime_get_sync(core->dev); 460 venus_shutdown(core); 461 venus_firmware_deinit(core); 462 pm_runtime_put_sync(core->dev); 463} 464 465static __maybe_unused int venus_runtime_suspend(struct device *dev) 466{ 467 struct venus_core *core = dev_get_drvdata(dev); 468 const struct venus_pm_ops *pm_ops = core->pm_ops; 469 int ret; 470 471 ret = hfi_core_suspend(core); 472 if (ret) 473 return ret; 474 475 if (pm_ops->core_power) { 476 ret = pm_ops->core_power(core, POWER_OFF); 477 if (ret) 478 return ret; 479 } 480 481 ret = icc_set_bw(core->cpucfg_path, 0, 0); 482 if (ret) 483 goto err_cpucfg_path; 484 485 ret = icc_set_bw(core->video_path, 0, 0); 486 if (ret) 487 goto err_video_path; 488 489 return ret; 490 491err_video_path: 492 icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 493err_cpucfg_path: 494 if (pm_ops->core_power) 495 pm_ops->core_power(core, POWER_ON); 496 497 return ret; 498} 499 500static __maybe_unused int venus_runtime_resume(struct device *dev) 501{ 502 struct venus_core *core = dev_get_drvdata(dev); 503 const struct venus_pm_ops *pm_ops = core->pm_ops; 504 int ret; 505 506 ret = icc_set_bw(core->video_path, kbps_to_icc(20000), 0); 507 if (ret) 508 return ret; 509 510 ret = icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 511 if (ret) 512 return ret; 513 514 if (pm_ops->core_power) { 515 ret = pm_ops->core_power(core, POWER_ON); 516 if (ret) 517 return ret; 518 } 519 520 return hfi_core_resume(core, false); 521} 522 523static const struct dev_pm_ops venus_pm_ops = { 524 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 525 pm_runtime_force_resume) 526 SET_RUNTIME_PM_OPS(venus_runtime_suspend, venus_runtime_resume, NULL) 527}; 528 529static const struct freq_tbl msm8916_freq_table[] = { 530 { 352800, 228570000 }, /* 1920x1088 @ 30 + 1280x720 @ 30 */ 531 { 244800, 160000000 }, /* 1920x1088 @ 30 */ 532 { 108000, 100000000 }, /* 1280x720 @ 30 */ 533}; 534 535static const struct reg_val msm8916_reg_preset[] = { 536 { 0xe0020, 0x05555556 }, 537 { 0xe0024, 0x05555556 }, 538 { 0x80124, 0x00000003 }, 539}; 540 541static const struct venus_resources msm8916_res = { 542 .freq_tbl = msm8916_freq_table, 543 .freq_tbl_size = ARRAY_SIZE(msm8916_freq_table), 544 .reg_tbl = msm8916_reg_preset, 545 .reg_tbl_size = ARRAY_SIZE(msm8916_reg_preset), 546 .clks = { "core", "iface", "bus", }, 547 .clks_num = 3, 548 .max_load = 352800, /* 720p@30 + 1080p@30 */ 549 .hfi_version = HFI_VERSION_1XX, 550 .vmem_id = VIDC_RESOURCE_NONE, 551 .vmem_size = 0, 552 .vmem_addr = 0, 553 .dma_mask = 0xddc00000 - 1, 554 .fwname = "qcom/venus-1.8/venus.mbn", 555}; 556 557static const struct freq_tbl msm8996_freq_table[] = { 558 { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */ 559 { 972000, 520000000 }, /* 4k UHD @ 30 */ 560 { 489600, 346666667 }, /* 1080p @ 60 */ 561 { 244800, 150000000 }, /* 1080p @ 30 */ 562 { 108000, 75000000 }, /* 720p @ 30 */ 563}; 564 565static const struct reg_val msm8996_reg_preset[] = { 566 { 0x80010, 0xffffffff }, 567 { 0x80018, 0x00001556 }, 568 { 0x8001C, 0x00001556 }, 569}; 570 571static const struct venus_resources msm8996_res = { 572 .freq_tbl = msm8996_freq_table, 573 .freq_tbl_size = ARRAY_SIZE(msm8996_freq_table), 574 .reg_tbl = msm8996_reg_preset, 575 .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), 576 .clks = {"core", "iface", "bus", "mbus" }, 577 .clks_num = 4, 578 .vcodec0_clks = { "core" }, 579 .vcodec1_clks = { "core" }, 580 .vcodec_clks_num = 1, 581 .max_load = 2563200, 582 .hfi_version = HFI_VERSION_3XX, 583 .vmem_id = VIDC_RESOURCE_NONE, 584 .vmem_size = 0, 585 .vmem_addr = 0, 586 .dma_mask = 0xddc00000 - 1, 587 .fwname = "qcom/venus-4.2/venus.mbn", 588}; 589 590static const struct freq_tbl sdm660_freq_table[] = { 591 { 979200, 518400000 }, 592 { 489600, 441600000 }, 593 { 432000, 404000000 }, 594 { 244800, 320000000 }, 595 { 216000, 269330000 }, 596 { 108000, 133330000 }, 597}; 598 599static const struct reg_val sdm660_reg_preset[] = { 600 { 0x80010, 0x001f001f }, 601 { 0x80018, 0x00000156 }, 602 { 0x8001c, 0x00000156 }, 603}; 604 605static const struct bw_tbl sdm660_bw_table_enc[] = { 606 { 979200, 1044000, 0, 2446336, 0 }, /* 4k UHD @ 30 */ 607 { 864000, 887000, 0, 2108416, 0 }, /* 720p @ 240 */ 608 { 489600, 666000, 0, 1207296, 0 }, /* 1080p @ 60 */ 609 { 432000, 578000, 0, 1058816, 0 }, /* 720p @ 120 */ 610 { 244800, 346000, 0, 616448, 0 }, /* 1080p @ 30 */ 611 { 216000, 293000, 0, 534528, 0 }, /* 720p @ 60 */ 612 { 108000, 151000, 0, 271360, 0 }, /* 720p @ 30 */ 613}; 614 615static const struct bw_tbl sdm660_bw_table_dec[] = { 616 { 979200, 2365000, 0, 1892000, 0 }, /* 4k UHD @ 30 */ 617 { 864000, 1978000, 0, 1554000, 0 }, /* 720p @ 240 */ 618 { 489600, 1133000, 0, 895000, 0 }, /* 1080p @ 60 */ 619 { 432000, 994000, 0, 781000, 0 }, /* 720p @ 120 */ 620 { 244800, 580000, 0, 460000, 0 }, /* 1080p @ 30 */ 621 { 216000, 501000, 0, 301000, 0 }, /* 720p @ 60 */ 622 { 108000, 255000, 0, 202000, 0 }, /* 720p @ 30 */ 623}; 624 625static const struct venus_resources sdm660_res = { 626 .freq_tbl = sdm660_freq_table, 627 .freq_tbl_size = ARRAY_SIZE(sdm660_freq_table), 628 .reg_tbl = sdm660_reg_preset, 629 .reg_tbl_size = ARRAY_SIZE(sdm660_reg_preset), 630 .bw_tbl_enc = sdm660_bw_table_enc, 631 .bw_tbl_enc_size = ARRAY_SIZE(sdm660_bw_table_enc), 632 .bw_tbl_dec = sdm660_bw_table_dec, 633 .bw_tbl_dec_size = ARRAY_SIZE(sdm660_bw_table_dec), 634 .clks = {"core", "iface", "bus", "bus_throttle" }, 635 .clks_num = 4, 636 .vcodec0_clks = { "vcodec0_core" }, 637 .vcodec1_clks = { "vcodec0_core" }, 638 .vcodec_clks_num = 1, 639 .vcodec_num = 1, 640 .max_load = 1036800, 641 .hfi_version = HFI_VERSION_3XX, 642 .vmem_id = VIDC_RESOURCE_NONE, 643 .vmem_size = 0, 644 .vmem_addr = 0, 645 .cp_start = 0, 646 .cp_size = 0x79000000, 647 .cp_nonpixel_start = 0x1000000, 648 .cp_nonpixel_size = 0x28000000, 649 .dma_mask = 0xd9000000 - 1, 650 .fwname = "qcom/venus-4.4/venus.mdt", 651}; 652 653static const struct freq_tbl sdm845_freq_table[] = { 654 { 3110400, 533000000 }, /* 4096x2160@90 */ 655 { 2073600, 444000000 }, /* 4096x2160@60 */ 656 { 1944000, 404000000 }, /* 3840x2160@60 */ 657 { 972000, 330000000 }, /* 3840x2160@30 */ 658 { 489600, 200000000 }, /* 1920x1080@60 */ 659 { 244800, 100000000 }, /* 1920x1080@30 */ 660}; 661 662static const struct bw_tbl sdm845_bw_table_enc[] = { 663 { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */ 664 { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */ 665 { 489600, 723000, 0, 973000, 0 }, /* 1920x1080@60 */ 666 { 244800, 370000, 0, 495000, 0 }, /* 1920x1080@30 */ 667}; 668 669static const struct bw_tbl sdm845_bw_table_dec[] = { 670 { 2073600, 3929000, 0, 5551000, 0 }, /* 4096x2160@60 */ 671 { 1036800, 1987000, 0, 2797000, 0 }, /* 4096x2160@30 */ 672 { 489600, 1040000, 0, 1298000, 0 }, /* 1920x1080@60 */ 673 { 244800, 530000, 0, 659000, 0 }, /* 1920x1080@30 */ 674}; 675 676static const struct venus_resources sdm845_res = { 677 .freq_tbl = sdm845_freq_table, 678 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 679 .bw_tbl_enc = sdm845_bw_table_enc, 680 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 681 .bw_tbl_dec = sdm845_bw_table_dec, 682 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 683 .clks = {"core", "iface", "bus" }, 684 .clks_num = 3, 685 .vcodec0_clks = { "core", "bus" }, 686 .vcodec1_clks = { "core", "bus" }, 687 .vcodec_clks_num = 2, 688 .max_load = 3110400, /* 4096x2160@90 */ 689 .hfi_version = HFI_VERSION_4XX, 690 .vpu_version = VPU_VERSION_AR50, 691 .vmem_id = VIDC_RESOURCE_NONE, 692 .vmem_size = 0, 693 .vmem_addr = 0, 694 .dma_mask = 0xe0000000 - 1, 695 .fwname = "qcom/venus-5.2/venus.mbn", 696}; 697 698static const struct venus_resources sdm845_res_v2 = { 699 .freq_tbl = sdm845_freq_table, 700 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 701 .bw_tbl_enc = sdm845_bw_table_enc, 702 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 703 .bw_tbl_dec = sdm845_bw_table_dec, 704 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 705 .clks = {"core", "iface", "bus" }, 706 .clks_num = 3, 707 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 708 .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, 709 .vcodec_clks_num = 2, 710 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, 711 .vcodec_pmdomains_num = 3, 712 .opp_pmdomain = (const char *[]) { "cx", NULL }, 713 .vcodec_num = 2, 714 .max_load = 3110400, /* 4096x2160@90 */ 715 .hfi_version = HFI_VERSION_4XX, 716 .vpu_version = VPU_VERSION_AR50, 717 .vmem_id = VIDC_RESOURCE_NONE, 718 .vmem_size = 0, 719 .vmem_addr = 0, 720 .dma_mask = 0xe0000000 - 1, 721 .cp_start = 0, 722 .cp_size = 0x70800000, 723 .cp_nonpixel_start = 0x1000000, 724 .cp_nonpixel_size = 0x24800000, 725 .fwname = "qcom/venus-5.2/venus.mbn", 726}; 727 728static const struct freq_tbl sc7180_freq_table[] = { 729 { 0, 500000000 }, 730 { 0, 434000000 }, 731 { 0, 340000000 }, 732 { 0, 270000000 }, 733 { 0, 150000000 }, 734}; 735 736static const struct bw_tbl sc7180_bw_table_enc[] = { 737 { 972000, 750000, 0, 0, 0 }, /* 3840x2160@30 */ 738 { 489600, 451000, 0, 0, 0 }, /* 1920x1080@60 */ 739 { 244800, 234000, 0, 0, 0 }, /* 1920x1080@30 */ 740}; 741 742static const struct bw_tbl sc7180_bw_table_dec[] = { 743 { 1036800, 1386000, 0, 1875000, 0 }, /* 4096x2160@30 */ 744 { 489600, 865000, 0, 1146000, 0 }, /* 1920x1080@60 */ 745 { 244800, 530000, 0, 583000, 0 }, /* 1920x1080@30 */ 746}; 747 748static const struct venus_resources sc7180_res = { 749 .freq_tbl = sc7180_freq_table, 750 .freq_tbl_size = ARRAY_SIZE(sc7180_freq_table), 751 .bw_tbl_enc = sc7180_bw_table_enc, 752 .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc), 753 .bw_tbl_dec = sc7180_bw_table_dec, 754 .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec), 755 .clks = {"core", "iface", "bus" }, 756 .clks_num = 3, 757 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 758 .vcodec_clks_num = 2, 759 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 760 .vcodec_pmdomains_num = 2, 761 .opp_pmdomain = (const char *[]) { "cx", NULL }, 762 .vcodec_num = 1, 763 .hfi_version = HFI_VERSION_4XX, 764 .vpu_version = VPU_VERSION_AR50, 765 .vmem_id = VIDC_RESOURCE_NONE, 766 .vmem_size = 0, 767 .vmem_addr = 0, 768 .dma_mask = 0xe0000000 - 1, 769 .cp_start = 0, 770 .cp_size = 0x70800000, 771 .cp_nonpixel_start = 0x1000000, 772 .cp_nonpixel_size = 0x24800000, 773 .fwname = "qcom/venus-5.4/venus.mbn", 774}; 775 776static const struct freq_tbl sm8250_freq_table[] = { 777 { 0, 444000000 }, 778 { 0, 366000000 }, 779 { 0, 338000000 }, 780 { 0, 240000000 }, 781}; 782 783static const struct bw_tbl sm8250_bw_table_enc[] = { 784 { 1944000, 1954000, 0, 3711000, 0 }, /* 3840x2160@60 */ 785 { 972000, 996000, 0, 1905000, 0 }, /* 3840x2160@30 */ 786 { 489600, 645000, 0, 977000, 0 }, /* 1920x1080@60 */ 787 { 244800, 332000, 0, 498000, 0 }, /* 1920x1080@30 */ 788}; 789 790static const struct bw_tbl sm8250_bw_table_dec[] = { 791 { 2073600, 2403000, 0, 4113000, 0 }, /* 4096x2160@60 */ 792 { 1036800, 1224000, 0, 2079000, 0 }, /* 4096x2160@30 */ 793 { 489600, 812000, 0, 998000, 0 }, /* 1920x1080@60 */ 794 { 244800, 416000, 0, 509000, 0 }, /* 1920x1080@30 */ 795}; 796 797static const struct reg_val sm8250_reg_preset[] = { 798 { 0xb0088, 0 }, 799}; 800 801static const struct venus_resources sm8250_res = { 802 .freq_tbl = sm8250_freq_table, 803 .freq_tbl_size = ARRAY_SIZE(sm8250_freq_table), 804 .reg_tbl = sm8250_reg_preset, 805 .reg_tbl_size = ARRAY_SIZE(sm8250_reg_preset), 806 .bw_tbl_enc = sm8250_bw_table_enc, 807 .bw_tbl_enc_size = ARRAY_SIZE(sm8250_bw_table_enc), 808 .bw_tbl_dec = sm8250_bw_table_dec, 809 .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), 810 .clks = {"core", "iface"}, 811 .clks_num = 2, 812 .resets = { "bus", "core" }, 813 .resets_num = 2, 814 .vcodec0_clks = { "vcodec0_core" }, 815 .vcodec_clks_num = 1, 816 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 817 .vcodec_pmdomains_num = 2, 818 .opp_pmdomain = (const char *[]) { "mx", NULL }, 819 .vcodec_num = 1, 820 .max_load = 7833600, 821 .hfi_version = HFI_VERSION_6XX, 822 .vpu_version = VPU_VERSION_IRIS2, 823 .num_vpp_pipes = 4, 824 .vmem_id = VIDC_RESOURCE_NONE, 825 .vmem_size = 0, 826 .vmem_addr = 0, 827 .dma_mask = 0xe0000000 - 1, 828 .fwname = "qcom/vpu-1.0/venus.mbn", 829}; 830 831static const struct freq_tbl sc7280_freq_table[] = { 832 { 0, 460000000 }, 833 { 0, 424000000 }, 834 { 0, 335000000 }, 835 { 0, 240000000 }, 836 { 0, 133333333 }, 837}; 838 839static const struct bw_tbl sc7280_bw_table_enc[] = { 840 { 1944000, 1896000, 0, 3657000, 0 }, /* 3840x2160@60 */ 841 { 972000, 968000, 0, 1848000, 0 }, /* 3840x2160@30 */ 842 { 489600, 618000, 0, 941000, 0 }, /* 1920x1080@60 */ 843 { 244800, 318000, 0, 480000, 0 }, /* 1920x1080@30 */ 844}; 845 846static const struct bw_tbl sc7280_bw_table_dec[] = { 847 { 2073600, 2128000, 0, 3831000, 0 }, /* 4096x2160@60 */ 848 { 1036800, 1085000, 0, 1937000, 0 }, /* 4096x2160@30 */ 849 { 489600, 779000, 0, 998000, 0 }, /* 1920x1080@60 */ 850 { 244800, 400000, 0, 509000, 0 }, /* 1920x1080@30 */ 851}; 852 853static const struct reg_val sm7280_reg_preset[] = { 854 { 0xb0088, 0 }, 855}; 856 857static const struct hfi_ubwc_config sc7280_ubwc_config = { 858 0, 0, {1, 1, 1, 0, 0, 0}, 8, 32, 14, 0, 0, {0, 0} 859}; 860 861static const struct venus_resources sc7280_res = { 862 .freq_tbl = sc7280_freq_table, 863 .freq_tbl_size = ARRAY_SIZE(sc7280_freq_table), 864 .reg_tbl = sm7280_reg_preset, 865 .reg_tbl_size = ARRAY_SIZE(sm7280_reg_preset), 866 .bw_tbl_enc = sc7280_bw_table_enc, 867 .bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc), 868 .bw_tbl_dec = sc7280_bw_table_dec, 869 .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), 870 .ubwc_conf = &sc7280_ubwc_config, 871 .clks = {"core", "bus", "iface"}, 872 .clks_num = 3, 873 .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, 874 .vcodec_clks_num = 2, 875 .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, 876 .vcodec_pmdomains_num = 2, 877 .opp_pmdomain = (const char *[]) { "cx", NULL }, 878 .vcodec_num = 1, 879 .hfi_version = HFI_VERSION_6XX, 880 .vpu_version = VPU_VERSION_IRIS2_1, 881 .num_vpp_pipes = 1, 882 .vmem_id = VIDC_RESOURCE_NONE, 883 .vmem_size = 0, 884 .vmem_addr = 0, 885 .dma_mask = 0xe0000000 - 1, 886 .cp_start = 0, 887 .cp_size = 0x25800000, 888 .cp_nonpixel_start = 0x1000000, 889 .cp_nonpixel_size = 0x24800000, 890 .fwname = "qcom/vpu-2.0/venus.mbn", 891}; 892 893static const struct of_device_id venus_dt_match[] = { 894 { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, 895 { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, 896 { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, 897 { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, 898 { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, 899 { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, 900 { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, 901 { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, 902 { } 903}; 904MODULE_DEVICE_TABLE(of, venus_dt_match); 905 906static struct platform_driver qcom_venus_driver = { 907 .probe = venus_probe, 908 .remove_new = venus_remove, 909 .driver = { 910 .name = "qcom-venus", 911 .of_match_table = venus_dt_match, 912 .pm = &venus_pm_ops, 913 }, 914 .shutdown = venus_core_shutdown, 915}; 916module_platform_driver(qcom_venus_driver); 917 918MODULE_ALIAS("platform:qcom-venus"); 919MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); 920MODULE_LICENSE("GPL v2"); 921