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_device.h> 15 #include <linux/platform_device.h> 16 #include <linux/slab.h> 17 #include <linux/types.h> 18 #include <linux/pm_runtime.h> 19 #include <media/videobuf2-v4l2.h> 20 #include <media/v4l2-mem2mem.h> 21 #include <media/v4l2-ioctl.h> 22 23 #include "core.h" 24 #include "firmware.h" 25 #include "pm_helpers.h" 26 27 static void venus_coredump(struct venus_core *core) 28 { 29 struct device *dev; 30 phys_addr_t mem_phys; 31 size_t mem_size; 32 void *mem_va; 33 void *data; 34 35 dev = core->dev; 36 mem_phys = core->fw.mem_phys; 37 mem_size = core->fw.mem_size; 38 39 mem_va = memremap(mem_phys, mem_size, MEMREMAP_WC); 40 if (!mem_va) 41 return; 42 43 data = vmalloc(mem_size); 44 if (!data) { 45 memunmap(mem_va); 46 return; 47 } 48 49 memcpy(data, mem_va, mem_size); 50 memunmap(mem_va); 51 dev_coredumpv(dev, data, mem_size, GFP_KERNEL); 52 } 53 54 static void venus_event_notify(struct venus_core *core, u32 event) 55 { 56 struct venus_inst *inst; 57 58 switch (event) { 59 case EVT_SYS_WATCHDOG_TIMEOUT: 60 case EVT_SYS_ERROR: 61 break; 62 default: 63 return; 64 } 65 66 mutex_lock(&core->lock); 67 core->sys_error = true; 68 list_for_each_entry(inst, &core->instances, list) 69 inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL); 70 mutex_unlock(&core->lock); 71 72 disable_irq_nosync(core->irq); 73 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 74 } 75 76 static const struct hfi_core_ops venus_core_ops = { 77 .event_notify = venus_event_notify, 78 }; 79 80 static void venus_sys_error_handler(struct work_struct *work) 81 { 82 struct venus_core *core = 83 container_of(work, struct venus_core, work.work); 84 int ret = 0; 85 86 pm_runtime_get_sync(core->dev); 87 88 hfi_core_deinit(core, true); 89 90 dev_warn(core->dev, "system error has occurred, starting recovery!\n"); 91 92 mutex_lock(&core->lock); 93 94 while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc)) 95 msleep(10); 96 97 venus_shutdown(core); 98 99 venus_coredump(core); 100 101 pm_runtime_put_sync(core->dev); 102 103 while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0])) 104 usleep_range(1000, 1500); 105 106 hfi_reinit(core); 107 108 pm_runtime_get_sync(core->dev); 109 110 ret |= venus_boot(core); 111 ret |= hfi_core_resume(core, true); 112 113 enable_irq(core->irq); 114 115 mutex_unlock(&core->lock); 116 117 ret |= hfi_core_init(core); 118 119 pm_runtime_put_sync(core->dev); 120 121 if (ret) { 122 disable_irq_nosync(core->irq); 123 dev_warn(core->dev, "recovery failed (%d)\n", ret); 124 schedule_delayed_work(&core->work, msecs_to_jiffies(10)); 125 return; 126 } 127 128 mutex_lock(&core->lock); 129 core->sys_error = false; 130 mutex_unlock(&core->lock); 131 } 132 133 static u32 to_v4l2_codec_type(u32 codec) 134 { 135 switch (codec) { 136 case HFI_VIDEO_CODEC_H264: 137 return V4L2_PIX_FMT_H264; 138 case HFI_VIDEO_CODEC_H263: 139 return V4L2_PIX_FMT_H263; 140 case HFI_VIDEO_CODEC_MPEG1: 141 return V4L2_PIX_FMT_MPEG1; 142 case HFI_VIDEO_CODEC_MPEG2: 143 return V4L2_PIX_FMT_MPEG2; 144 case HFI_VIDEO_CODEC_MPEG4: 145 return V4L2_PIX_FMT_MPEG4; 146 case HFI_VIDEO_CODEC_VC1: 147 return V4L2_PIX_FMT_VC1_ANNEX_G; 148 case HFI_VIDEO_CODEC_VP8: 149 return V4L2_PIX_FMT_VP8; 150 case HFI_VIDEO_CODEC_VP9: 151 return V4L2_PIX_FMT_VP9; 152 case HFI_VIDEO_CODEC_DIVX: 153 case HFI_VIDEO_CODEC_DIVX_311: 154 return V4L2_PIX_FMT_XVID; 155 default: 156 return 0; 157 } 158 } 159 160 static int venus_enumerate_codecs(struct venus_core *core, u32 type) 161 { 162 const struct hfi_inst_ops dummy_ops = {}; 163 struct venus_inst *inst; 164 u32 codec, codecs; 165 unsigned int i; 166 int ret; 167 168 if (core->res->hfi_version != HFI_VERSION_1XX) 169 return 0; 170 171 inst = kzalloc(sizeof(*inst), GFP_KERNEL); 172 if (!inst) 173 return -ENOMEM; 174 175 mutex_init(&inst->lock); 176 inst->core = core; 177 inst->session_type = type; 178 if (type == VIDC_SESSION_TYPE_DEC) 179 codecs = core->dec_codecs; 180 else 181 codecs = core->enc_codecs; 182 183 ret = hfi_session_create(inst, &dummy_ops); 184 if (ret) 185 goto err; 186 187 for (i = 0; i < MAX_CODEC_NUM; i++) { 188 codec = (1UL << i) & codecs; 189 if (!codec) 190 continue; 191 192 ret = hfi_session_init(inst, to_v4l2_codec_type(codec)); 193 if (ret) 194 goto done; 195 196 ret = hfi_session_deinit(inst); 197 if (ret) 198 goto done; 199 } 200 201 done: 202 hfi_session_destroy(inst); 203 err: 204 mutex_destroy(&inst->lock); 205 kfree(inst); 206 207 return ret; 208 } 209 210 static int venus_probe(struct platform_device *pdev) 211 { 212 struct device *dev = &pdev->dev; 213 struct venus_core *core; 214 struct resource *r; 215 int ret; 216 217 core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); 218 if (!core) 219 return -ENOMEM; 220 221 core->dev = dev; 222 223 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 224 core->base = devm_ioremap_resource(dev, r); 225 if (IS_ERR(core->base)) 226 return PTR_ERR(core->base); 227 228 core->video_path = devm_of_icc_get(dev, "video-mem"); 229 if (IS_ERR(core->video_path)) 230 return PTR_ERR(core->video_path); 231 232 core->cpucfg_path = devm_of_icc_get(dev, "cpu-cfg"); 233 if (IS_ERR(core->cpucfg_path)) 234 return PTR_ERR(core->cpucfg_path); 235 236 core->irq = platform_get_irq(pdev, 0); 237 if (core->irq < 0) 238 return core->irq; 239 240 core->res = of_device_get_match_data(dev); 241 if (!core->res) 242 return -ENODEV; 243 244 mutex_init(&core->pm_lock); 245 246 core->pm_ops = venus_pm_get(core->res->hfi_version); 247 if (!core->pm_ops) 248 return -ENODEV; 249 250 if (core->pm_ops->core_get) { 251 ret = core->pm_ops->core_get(core); 252 if (ret) 253 return ret; 254 } 255 256 ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); 257 if (ret) 258 goto err_core_put; 259 260 dma_set_max_seg_size(dev, UINT_MAX); 261 262 INIT_LIST_HEAD(&core->instances); 263 mutex_init(&core->lock); 264 INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); 265 266 ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread, 267 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 268 "venus", core); 269 if (ret) 270 goto err_core_put; 271 272 ret = hfi_create(core, &venus_core_ops); 273 if (ret) 274 goto err_core_put; 275 276 ret = v4l2_device_register(dev, &core->v4l2_dev); 277 if (ret) 278 goto err_core_deinit; 279 280 platform_set_drvdata(pdev, core); 281 282 pm_runtime_enable(dev); 283 284 ret = pm_runtime_get_sync(dev); 285 if (ret < 0) 286 goto err_runtime_disable; 287 288 ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 289 if (ret) 290 goto err_runtime_disable; 291 292 ret = venus_firmware_init(core); 293 if (ret) 294 goto err_runtime_disable; 295 296 ret = venus_boot(core); 297 if (ret) 298 goto err_runtime_disable; 299 300 ret = hfi_core_resume(core, true); 301 if (ret) 302 goto err_venus_shutdown; 303 304 ret = hfi_core_init(core); 305 if (ret) 306 goto err_venus_shutdown; 307 308 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); 309 if (ret) 310 goto err_venus_shutdown; 311 312 ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); 313 if (ret) 314 goto err_venus_shutdown; 315 316 ret = pm_runtime_put_sync(dev); 317 if (ret) { 318 pm_runtime_get_noresume(dev); 319 goto err_dev_unregister; 320 } 321 322 venus_dbgfs_init(core); 323 324 return 0; 325 326 err_dev_unregister: 327 v4l2_device_unregister(&core->v4l2_dev); 328 err_venus_shutdown: 329 venus_shutdown(core); 330 err_runtime_disable: 331 pm_runtime_put_noidle(dev); 332 pm_runtime_set_suspended(dev); 333 pm_runtime_disable(dev); 334 hfi_destroy(core); 335 err_core_deinit: 336 hfi_core_deinit(core, false); 337 err_core_put: 338 if (core->pm_ops->core_put) 339 core->pm_ops->core_put(core); 340 return ret; 341 } 342 343 static int venus_remove(struct platform_device *pdev) 344 { 345 struct venus_core *core = platform_get_drvdata(pdev); 346 const struct venus_pm_ops *pm_ops = core->pm_ops; 347 struct device *dev = core->dev; 348 int ret; 349 350 ret = pm_runtime_get_sync(dev); 351 WARN_ON(ret < 0); 352 353 ret = hfi_core_deinit(core, true); 354 WARN_ON(ret); 355 356 venus_shutdown(core); 357 of_platform_depopulate(dev); 358 359 venus_firmware_deinit(core); 360 361 pm_runtime_put_sync(dev); 362 pm_runtime_disable(dev); 363 364 if (pm_ops->core_put) 365 pm_ops->core_put(core); 366 367 v4l2_device_unregister(&core->v4l2_dev); 368 369 hfi_destroy(core); 370 371 v4l2_device_unregister(&core->v4l2_dev); 372 373 mutex_destroy(&core->pm_lock); 374 mutex_destroy(&core->lock); 375 venus_dbgfs_deinit(core); 376 377 return ret; 378 } 379 380 static void venus_core_shutdown(struct platform_device *pdev) 381 { 382 struct venus_core *core = platform_get_drvdata(pdev); 383 384 pm_runtime_get_sync(core->dev); 385 venus_shutdown(core); 386 venus_firmware_deinit(core); 387 pm_runtime_put_sync(core->dev); 388 } 389 390 static __maybe_unused int venus_runtime_suspend(struct device *dev) 391 { 392 struct venus_core *core = dev_get_drvdata(dev); 393 const struct venus_pm_ops *pm_ops = core->pm_ops; 394 int ret; 395 396 ret = hfi_core_suspend(core); 397 if (ret) 398 return ret; 399 400 if (pm_ops->core_power) { 401 ret = pm_ops->core_power(core, POWER_OFF); 402 if (ret) 403 return ret; 404 } 405 406 ret = icc_set_bw(core->cpucfg_path, 0, 0); 407 if (ret) 408 goto err_cpucfg_path; 409 410 ret = icc_set_bw(core->video_path, 0, 0); 411 if (ret) 412 goto err_video_path; 413 414 return ret; 415 416 err_video_path: 417 icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 418 err_cpucfg_path: 419 pm_ops->core_power(core, POWER_ON); 420 421 return ret; 422 } 423 424 static __maybe_unused int venus_runtime_resume(struct device *dev) 425 { 426 struct venus_core *core = dev_get_drvdata(dev); 427 const struct venus_pm_ops *pm_ops = core->pm_ops; 428 int ret; 429 430 ret = icc_set_bw(core->video_path, kbps_to_icc(20000), 0); 431 if (ret) 432 return ret; 433 434 ret = icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); 435 if (ret) 436 return ret; 437 438 if (pm_ops->core_power) { 439 ret = pm_ops->core_power(core, POWER_ON); 440 if (ret) 441 return ret; 442 } 443 444 return hfi_core_resume(core, false); 445 } 446 447 static const struct dev_pm_ops venus_pm_ops = { 448 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 449 pm_runtime_force_resume) 450 SET_RUNTIME_PM_OPS(venus_runtime_suspend, venus_runtime_resume, NULL) 451 }; 452 453 static const struct freq_tbl msm8916_freq_table[] = { 454 { 352800, 228570000 }, /* 1920x1088 @ 30 + 1280x720 @ 30 */ 455 { 244800, 160000000 }, /* 1920x1088 @ 30 */ 456 { 108000, 100000000 }, /* 1280x720 @ 30 */ 457 }; 458 459 static const struct reg_val msm8916_reg_preset[] = { 460 { 0xe0020, 0x05555556 }, 461 { 0xe0024, 0x05555556 }, 462 { 0x80124, 0x00000003 }, 463 }; 464 465 static const struct venus_resources msm8916_res = { 466 .freq_tbl = msm8916_freq_table, 467 .freq_tbl_size = ARRAY_SIZE(msm8916_freq_table), 468 .reg_tbl = msm8916_reg_preset, 469 .reg_tbl_size = ARRAY_SIZE(msm8916_reg_preset), 470 .clks = { "core", "iface", "bus", }, 471 .clks_num = 3, 472 .max_load = 352800, /* 720p@30 + 1080p@30 */ 473 .hfi_version = HFI_VERSION_1XX, 474 .vmem_id = VIDC_RESOURCE_NONE, 475 .vmem_size = 0, 476 .vmem_addr = 0, 477 .dma_mask = 0xddc00000 - 1, 478 .fwname = "qcom/venus-1.8/venus.mdt", 479 }; 480 481 static const struct freq_tbl msm8996_freq_table[] = { 482 { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */ 483 { 972000, 520000000 }, /* 4k UHD @ 30 */ 484 { 489600, 346666667 }, /* 1080p @ 60 */ 485 { 244800, 150000000 }, /* 1080p @ 30 */ 486 { 108000, 75000000 }, /* 720p @ 30 */ 487 }; 488 489 static const struct reg_val msm8996_reg_preset[] = { 490 { 0x80010, 0xffffffff }, 491 { 0x80018, 0x00001556 }, 492 { 0x8001C, 0x00001556 }, 493 }; 494 495 static const struct venus_resources msm8996_res = { 496 .freq_tbl = msm8996_freq_table, 497 .freq_tbl_size = ARRAY_SIZE(msm8996_freq_table), 498 .reg_tbl = msm8996_reg_preset, 499 .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), 500 .clks = {"core", "iface", "bus", "mbus" }, 501 .clks_num = 4, 502 .vcodec0_clks = { "core" }, 503 .vcodec1_clks = { "core" }, 504 .vcodec_clks_num = 1, 505 .max_load = 2563200, 506 .hfi_version = HFI_VERSION_3XX, 507 .vmem_id = VIDC_RESOURCE_NONE, 508 .vmem_size = 0, 509 .vmem_addr = 0, 510 .dma_mask = 0xddc00000 - 1, 511 .fwname = "qcom/venus-4.2/venus.mdt", 512 }; 513 514 static const struct freq_tbl sdm845_freq_table[] = { 515 { 3110400, 533000000 }, /* 4096x2160@90 */ 516 { 2073600, 444000000 }, /* 4096x2160@60 */ 517 { 1944000, 404000000 }, /* 3840x2160@60 */ 518 { 972000, 330000000 }, /* 3840x2160@30 */ 519 { 489600, 200000000 }, /* 1920x1080@60 */ 520 { 244800, 100000000 }, /* 1920x1080@30 */ 521 }; 522 523 static const struct bw_tbl sdm845_bw_table_enc[] = { 524 { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */ 525 { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */ 526 { 489600, 723000, 0, 973000, 0 }, /* 1920x1080@60 */ 527 { 244800, 370000, 0, 495000, 0 }, /* 1920x1080@30 */ 528 }; 529 530 static const struct bw_tbl sdm845_bw_table_dec[] = { 531 { 2073600, 3929000, 0, 5551000, 0 }, /* 4096x2160@60 */ 532 { 1036800, 1987000, 0, 2797000, 0 }, /* 4096x2160@30 */ 533 { 489600, 1040000, 0, 1298000, 0 }, /* 1920x1080@60 */ 534 { 244800, 530000, 0, 659000, 0 }, /* 1920x1080@30 */ 535 }; 536 537 static const struct venus_resources sdm845_res = { 538 .freq_tbl = sdm845_freq_table, 539 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 540 .bw_tbl_enc = sdm845_bw_table_enc, 541 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 542 .bw_tbl_dec = sdm845_bw_table_dec, 543 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 544 .clks = {"core", "iface", "bus" }, 545 .clks_num = 3, 546 .vcodec0_clks = { "core", "bus" }, 547 .vcodec1_clks = { "core", "bus" }, 548 .vcodec_clks_num = 2, 549 .max_load = 3110400, /* 4096x2160@90 */ 550 .hfi_version = HFI_VERSION_4XX, 551 .vmem_id = VIDC_RESOURCE_NONE, 552 .vmem_size = 0, 553 .vmem_addr = 0, 554 .dma_mask = 0xe0000000 - 1, 555 .fwname = "qcom/venus-5.2/venus.mdt", 556 }; 557 558 static const struct venus_resources sdm845_res_v2 = { 559 .freq_tbl = sdm845_freq_table, 560 .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), 561 .bw_tbl_enc = sdm845_bw_table_enc, 562 .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), 563 .bw_tbl_dec = sdm845_bw_table_dec, 564 .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), 565 .clks = {"core", "iface", "bus" }, 566 .clks_num = 3, 567 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 568 .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, 569 .vcodec_clks_num = 2, 570 .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, 571 .vcodec_pmdomains_num = 3, 572 .opp_pmdomain = (const char *[]) { "cx", NULL }, 573 .vcodec_num = 2, 574 .max_load = 3110400, /* 4096x2160@90 */ 575 .hfi_version = HFI_VERSION_4XX, 576 .vmem_id = VIDC_RESOURCE_NONE, 577 .vmem_size = 0, 578 .vmem_addr = 0, 579 .dma_mask = 0xe0000000 - 1, 580 .cp_start = 0, 581 .cp_size = 0x70800000, 582 .cp_nonpixel_start = 0x1000000, 583 .cp_nonpixel_size = 0x24800000, 584 .fwname = "qcom/venus-5.2/venus.mdt", 585 }; 586 587 static const struct freq_tbl sc7180_freq_table[] = { 588 { 0, 500000000 }, 589 { 0, 434000000 }, 590 { 0, 340000000 }, 591 { 0, 270000000 }, 592 { 0, 150000000 }, 593 }; 594 595 static const struct bw_tbl sc7180_bw_table_enc[] = { 596 { 972000, 750000, 0, 0, 0 }, /* 3840x2160@30 */ 597 { 489600, 451000, 0, 0, 0 }, /* 1920x1080@60 */ 598 { 244800, 234000, 0, 0, 0 }, /* 1920x1080@30 */ 599 }; 600 601 static const struct bw_tbl sc7180_bw_table_dec[] = { 602 { 1036800, 1386000, 0, 1875000, 0 }, /* 4096x2160@30 */ 603 { 489600, 865000, 0, 1146000, 0 }, /* 1920x1080@60 */ 604 { 244800, 530000, 0, 583000, 0 }, /* 1920x1080@30 */ 605 }; 606 607 static const struct venus_resources sc7180_res = { 608 .freq_tbl = sc7180_freq_table, 609 .freq_tbl_size = ARRAY_SIZE(sc7180_freq_table), 610 .bw_tbl_enc = sc7180_bw_table_enc, 611 .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc), 612 .bw_tbl_dec = sc7180_bw_table_dec, 613 .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec), 614 .clks = {"core", "iface", "bus" }, 615 .clks_num = 3, 616 .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, 617 .vcodec_clks_num = 2, 618 .vcodec_pmdomains = { "venus", "vcodec0" }, 619 .vcodec_pmdomains_num = 2, 620 .opp_pmdomain = (const char *[]) { "cx", NULL }, 621 .vcodec_num = 1, 622 .hfi_version = HFI_VERSION_4XX, 623 .vmem_id = VIDC_RESOURCE_NONE, 624 .vmem_size = 0, 625 .vmem_addr = 0, 626 .dma_mask = 0xe0000000 - 1, 627 .fwname = "qcom/venus-5.4/venus.mdt", 628 }; 629 630 static const struct of_device_id venus_dt_match[] = { 631 { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, 632 { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, 633 { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, 634 { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, 635 { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, 636 { } 637 }; 638 MODULE_DEVICE_TABLE(of, venus_dt_match); 639 640 static struct platform_driver qcom_venus_driver = { 641 .probe = venus_probe, 642 .remove = venus_remove, 643 .driver = { 644 .name = "qcom-venus", 645 .of_match_table = venus_dt_match, 646 .pm = &venus_pm_ops, 647 }, 648 .shutdown = venus_core_shutdown, 649 }; 650 module_platform_driver(qcom_venus_driver); 651 652 MODULE_ALIAS("platform:qcom-venus"); 653 MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); 654 MODULE_LICENSE("GPL v2"); 655