1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 Linaro Ltd. 4 * 5 * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org> 6 */ 7 #include <linux/clk.h> 8 #include <linux/interconnect.h> 9 #include <linux/iopoll.h> 10 #include <linux/kernel.h> 11 #include <linux/pm_domain.h> 12 #include <linux/pm_opp.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/types.h> 15 #include <media/v4l2-mem2mem.h> 16 17 #include "core.h" 18 #include "hfi_parser.h" 19 #include "hfi_venus_io.h" 20 #include "pm_helpers.h" 21 #include "hfi_platform.h" 22 23 static bool legacy_binding; 24 25 static int core_clks_get(struct venus_core *core) 26 { 27 const struct venus_resources *res = core->res; 28 struct device *dev = core->dev; 29 unsigned int i; 30 31 for (i = 0; i < res->clks_num; i++) { 32 core->clks[i] = devm_clk_get(dev, res->clks[i]); 33 if (IS_ERR(core->clks[i])) 34 return PTR_ERR(core->clks[i]); 35 } 36 37 return 0; 38 } 39 40 static int core_clks_enable(struct venus_core *core) 41 { 42 const struct venus_resources *res = core->res; 43 unsigned int i; 44 int ret; 45 46 for (i = 0; i < res->clks_num; i++) { 47 ret = clk_prepare_enable(core->clks[i]); 48 if (ret) 49 goto err; 50 } 51 52 return 0; 53 err: 54 while (i--) 55 clk_disable_unprepare(core->clks[i]); 56 57 return ret; 58 } 59 60 static void core_clks_disable(struct venus_core *core) 61 { 62 const struct venus_resources *res = core->res; 63 unsigned int i = res->clks_num; 64 65 while (i--) 66 clk_disable_unprepare(core->clks[i]); 67 } 68 69 static int core_clks_set_rate(struct venus_core *core, unsigned long freq) 70 { 71 int ret; 72 73 ret = dev_pm_opp_set_rate(core->dev, freq); 74 if (ret) 75 return ret; 76 77 ret = clk_set_rate(core->vcodec0_clks[0], freq); 78 if (ret) 79 return ret; 80 81 ret = clk_set_rate(core->vcodec1_clks[0], freq); 82 if (ret) 83 return ret; 84 85 return 0; 86 } 87 88 static int vcodec_clks_get(struct venus_core *core, struct device *dev, 89 struct clk **clks, const char * const *id) 90 { 91 const struct venus_resources *res = core->res; 92 unsigned int i; 93 94 for (i = 0; i < res->vcodec_clks_num; i++) { 95 if (!id[i]) 96 continue; 97 clks[i] = devm_clk_get(dev, id[i]); 98 if (IS_ERR(clks[i])) 99 return PTR_ERR(clks[i]); 100 } 101 102 return 0; 103 } 104 105 static int vcodec_clks_enable(struct venus_core *core, struct clk **clks) 106 { 107 const struct venus_resources *res = core->res; 108 unsigned int i; 109 int ret; 110 111 for (i = 0; i < res->vcodec_clks_num; i++) { 112 ret = clk_prepare_enable(clks[i]); 113 if (ret) 114 goto err; 115 } 116 117 return 0; 118 err: 119 while (i--) 120 clk_disable_unprepare(clks[i]); 121 122 return ret; 123 } 124 125 static void vcodec_clks_disable(struct venus_core *core, struct clk **clks) 126 { 127 const struct venus_resources *res = core->res; 128 unsigned int i = res->vcodec_clks_num; 129 130 while (i--) 131 clk_disable_unprepare(clks[i]); 132 } 133 134 static u32 load_per_instance(struct venus_inst *inst) 135 { 136 u32 mbs; 137 138 if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP)) 139 return 0; 140 141 mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16); 142 143 return mbs * inst->fps; 144 } 145 146 static u32 load_per_type(struct venus_core *core, u32 session_type) 147 { 148 struct venus_inst *inst = NULL; 149 u32 mbs_per_sec = 0; 150 151 mutex_lock(&core->lock); 152 list_for_each_entry(inst, &core->instances, list) { 153 if (inst->session_type != session_type) 154 continue; 155 156 mbs_per_sec += load_per_instance(inst); 157 } 158 mutex_unlock(&core->lock); 159 160 return mbs_per_sec; 161 } 162 163 static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak) 164 { 165 const struct venus_resources *res = inst->core->res; 166 const struct bw_tbl *bw_tbl; 167 unsigned int num_rows, i; 168 169 *avg = 0; 170 *peak = 0; 171 172 if (mbs == 0) 173 return; 174 175 if (inst->session_type == VIDC_SESSION_TYPE_ENC) { 176 num_rows = res->bw_tbl_enc_size; 177 bw_tbl = res->bw_tbl_enc; 178 } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) { 179 num_rows = res->bw_tbl_dec_size; 180 bw_tbl = res->bw_tbl_dec; 181 } else { 182 return; 183 } 184 185 if (!bw_tbl || num_rows == 0) 186 return; 187 188 for (i = 0; i < num_rows; i++) { 189 if (mbs > bw_tbl[i].mbs_per_sec) 190 break; 191 192 if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) { 193 *avg = bw_tbl[i].avg_10bit; 194 *peak = bw_tbl[i].peak_10bit; 195 } else { 196 *avg = bw_tbl[i].avg; 197 *peak = bw_tbl[i].peak; 198 } 199 } 200 } 201 202 static int load_scale_bw(struct venus_core *core) 203 { 204 struct venus_inst *inst = NULL; 205 u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0; 206 207 mutex_lock(&core->lock); 208 list_for_each_entry(inst, &core->instances, list) { 209 mbs_per_sec = load_per_instance(inst); 210 mbs_to_bw(inst, mbs_per_sec, &avg, &peak); 211 total_avg += avg; 212 total_peak += peak; 213 } 214 mutex_unlock(&core->lock); 215 216 /* 217 * keep minimum bandwidth vote for "video-mem" path, 218 * so that clks can be disabled during vdec_session_release(). 219 * Actual bandwidth drop will be done during device supend 220 * so that device can power down without any warnings. 221 */ 222 223 if (!total_avg && !total_peak) 224 total_avg = kbps_to_icc(1000); 225 226 dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n", 227 total_avg, total_peak); 228 229 return icc_set_bw(core->video_path, total_avg, total_peak); 230 } 231 232 static int load_scale_v1(struct venus_inst *inst) 233 { 234 struct venus_core *core = inst->core; 235 const struct freq_tbl *table = core->res->freq_tbl; 236 unsigned int num_rows = core->res->freq_tbl_size; 237 unsigned long freq = table[0].freq; 238 struct device *dev = core->dev; 239 u32 mbs_per_sec; 240 unsigned int i; 241 int ret; 242 243 mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) + 244 load_per_type(core, VIDC_SESSION_TYPE_DEC); 245 246 if (mbs_per_sec > core->res->max_load) 247 dev_warn(dev, "HW is overloaded, needed: %d max: %d\n", 248 mbs_per_sec, core->res->max_load); 249 250 if (!mbs_per_sec && num_rows > 1) { 251 freq = table[num_rows - 1].freq; 252 goto set_freq; 253 } 254 255 for (i = 0; i < num_rows; i++) { 256 if (mbs_per_sec > table[i].load) 257 break; 258 freq = table[i].freq; 259 } 260 261 set_freq: 262 263 ret = core_clks_set_rate(core, freq); 264 if (ret) { 265 dev_err(dev, "failed to set clock rate %lu (%d)\n", 266 freq, ret); 267 return ret; 268 } 269 270 ret = load_scale_bw(core); 271 if (ret) { 272 dev_err(dev, "failed to set bandwidth (%d)\n", 273 ret); 274 return ret; 275 } 276 277 return 0; 278 } 279 280 static int core_get_v1(struct venus_core *core) 281 { 282 return core_clks_get(core); 283 } 284 285 static int core_power_v1(struct venus_core *core, int on) 286 { 287 int ret = 0; 288 289 if (on == POWER_ON) 290 ret = core_clks_enable(core); 291 else 292 core_clks_disable(core); 293 294 return ret; 295 } 296 297 static const struct venus_pm_ops pm_ops_v1 = { 298 .core_get = core_get_v1, 299 .core_power = core_power_v1, 300 .load_scale = load_scale_v1, 301 }; 302 303 static void 304 vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable) 305 { 306 void __iomem *ctrl; 307 308 if (session_type == VIDC_SESSION_TYPE_DEC) 309 ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL; 310 else 311 ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL; 312 313 if (enable) 314 writel(0, ctrl); 315 else 316 writel(1, ctrl); 317 } 318 319 static int vdec_get_v3(struct device *dev) 320 { 321 struct venus_core *core = dev_get_drvdata(dev); 322 323 return vcodec_clks_get(core, dev, core->vcodec0_clks, 324 core->res->vcodec0_clks); 325 } 326 327 static int vdec_power_v3(struct device *dev, int on) 328 { 329 struct venus_core *core = dev_get_drvdata(dev); 330 int ret = 0; 331 332 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true); 333 334 if (on == POWER_ON) 335 ret = vcodec_clks_enable(core, core->vcodec0_clks); 336 else 337 vcodec_clks_disable(core, core->vcodec0_clks); 338 339 vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false); 340 341 return ret; 342 } 343 344 static int venc_get_v3(struct device *dev) 345 { 346 struct venus_core *core = dev_get_drvdata(dev); 347 348 return vcodec_clks_get(core, dev, core->vcodec1_clks, 349 core->res->vcodec1_clks); 350 } 351 352 static int venc_power_v3(struct device *dev, int on) 353 { 354 struct venus_core *core = dev_get_drvdata(dev); 355 int ret = 0; 356 357 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true); 358 359 if (on == POWER_ON) 360 ret = vcodec_clks_enable(core, core->vcodec1_clks); 361 else 362 vcodec_clks_disable(core, core->vcodec1_clks); 363 364 vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false); 365 366 return ret; 367 } 368 369 static const struct venus_pm_ops pm_ops_v3 = { 370 .core_get = core_get_v1, 371 .core_power = core_power_v1, 372 .vdec_get = vdec_get_v3, 373 .vdec_power = vdec_power_v3, 374 .venc_get = venc_get_v3, 375 .venc_power = venc_power_v3, 376 .load_scale = load_scale_v1, 377 }; 378 379 static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable) 380 { 381 void __iomem *ctrl, *stat; 382 u32 val; 383 int ret; 384 385 if (coreid == VIDC_CORE_ID_1) { 386 ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; 387 stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; 388 } else { 389 ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL; 390 stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS; 391 } 392 393 if (enable) { 394 writel(0, ctrl); 395 396 ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100); 397 if (ret) 398 return ret; 399 } else { 400 writel(1, ctrl); 401 402 ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100); 403 if (ret) 404 return ret; 405 } 406 407 return 0; 408 } 409 410 static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) 411 { 412 int ret; 413 414 if (coreid_mask & VIDC_CORE_ID_1) { 415 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); 416 if (ret) 417 return ret; 418 419 vcodec_clks_disable(core, core->vcodec0_clks); 420 421 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); 422 if (ret) 423 return ret; 424 425 ret = pm_runtime_put_sync(core->pmdomains[1]); 426 if (ret < 0) 427 return ret; 428 } 429 430 if (coreid_mask & VIDC_CORE_ID_2) { 431 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); 432 if (ret) 433 return ret; 434 435 vcodec_clks_disable(core, core->vcodec1_clks); 436 437 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); 438 if (ret) 439 return ret; 440 441 ret = pm_runtime_put_sync(core->pmdomains[2]); 442 if (ret < 0) 443 return ret; 444 } 445 446 return 0; 447 } 448 449 static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) 450 { 451 int ret; 452 453 if (coreid_mask & VIDC_CORE_ID_1) { 454 ret = pm_runtime_get_sync(core->pmdomains[1]); 455 if (ret < 0) 456 return ret; 457 458 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); 459 if (ret) 460 return ret; 461 462 ret = vcodec_clks_enable(core, core->vcodec0_clks); 463 if (ret) 464 return ret; 465 466 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); 467 if (ret < 0) 468 return ret; 469 } 470 471 if (coreid_mask & VIDC_CORE_ID_2) { 472 ret = pm_runtime_get_sync(core->pmdomains[2]); 473 if (ret < 0) 474 return ret; 475 476 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); 477 if (ret) 478 return ret; 479 480 ret = vcodec_clks_enable(core, core->vcodec1_clks); 481 if (ret) 482 return ret; 483 484 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); 485 if (ret < 0) 486 return ret; 487 } 488 489 return 0; 490 } 491 492 static void 493 min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load) 494 { 495 u32 mbs_per_sec, load, core1_load = 0, core2_load = 0; 496 u32 cores_max = core_num_max(inst); 497 struct venus_core *core = inst->core; 498 struct venus_inst *inst_pos; 499 unsigned long vpp_freq; 500 u32 coreid; 501 502 mutex_lock(&core->lock); 503 504 list_for_each_entry(inst_pos, &core->instances, list) { 505 if (inst_pos == inst) 506 continue; 507 508 if (inst_pos->state != INST_START) 509 continue; 510 511 vpp_freq = inst_pos->clk_data.vpp_freq; 512 coreid = inst_pos->clk_data.core_id; 513 514 mbs_per_sec = load_per_instance(inst_pos); 515 load = mbs_per_sec * vpp_freq; 516 517 if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) { 518 core1_load += load / 2; 519 core2_load += load / 2; 520 } else if (coreid & VIDC_CORE_ID_1) { 521 core1_load += load; 522 } else if (coreid & VIDC_CORE_ID_2) { 523 core2_load += load; 524 } 525 } 526 527 *min_coreid = core1_load <= core2_load ? 528 VIDC_CORE_ID_1 : VIDC_CORE_ID_2; 529 *min_load = min(core1_load, core2_load); 530 531 if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) { 532 *min_coreid = VIDC_CORE_ID_1; 533 *min_load = core1_load; 534 } 535 536 mutex_unlock(&core->lock); 537 } 538 539 static int decide_core(struct venus_inst *inst) 540 { 541 const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; 542 struct venus_core *core = inst->core; 543 u32 min_coreid, min_load, inst_load; 544 struct hfi_videocores_usage_type cu; 545 unsigned long max_freq; 546 547 if (legacy_binding) { 548 if (inst->session_type == VIDC_SESSION_TYPE_DEC) 549 cu.video_core_enable_mask = VIDC_CORE_ID_1; 550 else 551 cu.video_core_enable_mask = VIDC_CORE_ID_2; 552 553 goto done; 554 } 555 556 if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT) 557 return 0; 558 559 inst_load = load_per_instance(inst); 560 inst_load *= inst->clk_data.vpp_freq; 561 max_freq = core->res->freq_tbl[0].freq; 562 563 min_loaded_core(inst, &min_coreid, &min_load); 564 565 if ((inst_load + min_load) > max_freq) { 566 dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n", 567 inst_load, max_freq); 568 return -EINVAL; 569 } 570 571 inst->clk_data.core_id = min_coreid; 572 cu.video_core_enable_mask = min_coreid; 573 574 done: 575 return hfi_session_set_property(inst, ptype, &cu); 576 } 577 578 static int acquire_core(struct venus_inst *inst) 579 { 580 struct venus_core *core = inst->core; 581 unsigned int coreid_mask = 0; 582 583 if (inst->core_acquired) 584 return 0; 585 586 inst->core_acquired = true; 587 588 if (inst->clk_data.core_id & VIDC_CORE_ID_1) { 589 if (core->core0_usage_count++) 590 return 0; 591 592 coreid_mask = VIDC_CORE_ID_1; 593 } 594 595 if (inst->clk_data.core_id & VIDC_CORE_ID_2) { 596 if (core->core1_usage_count++) 597 return 0; 598 599 coreid_mask |= VIDC_CORE_ID_2; 600 } 601 602 return poweron_coreid(core, coreid_mask); 603 } 604 605 static int release_core(struct venus_inst *inst) 606 { 607 struct venus_core *core = inst->core; 608 unsigned int coreid_mask = 0; 609 int ret; 610 611 if (!inst->core_acquired) 612 return 0; 613 614 if (inst->clk_data.core_id & VIDC_CORE_ID_1) { 615 if (--core->core0_usage_count) 616 goto done; 617 618 coreid_mask = VIDC_CORE_ID_1; 619 } 620 621 if (inst->clk_data.core_id & VIDC_CORE_ID_2) { 622 if (--core->core1_usage_count) 623 goto done; 624 625 coreid_mask |= VIDC_CORE_ID_2; 626 } 627 628 ret = poweroff_coreid(core, coreid_mask); 629 if (ret) 630 return ret; 631 632 done: 633 inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; 634 inst->core_acquired = false; 635 return 0; 636 } 637 638 static int coreid_power_v4(struct venus_inst *inst, int on) 639 { 640 struct venus_core *core = inst->core; 641 int ret; 642 643 if (legacy_binding) 644 return 0; 645 646 if (on == POWER_ON) { 647 ret = decide_core(inst); 648 if (ret) 649 return ret; 650 651 mutex_lock(&core->lock); 652 ret = acquire_core(inst); 653 mutex_unlock(&core->lock); 654 } else { 655 mutex_lock(&core->lock); 656 ret = release_core(inst); 657 mutex_unlock(&core->lock); 658 } 659 660 return ret; 661 } 662 663 static int vdec_get_v4(struct device *dev) 664 { 665 struct venus_core *core = dev_get_drvdata(dev); 666 667 if (!legacy_binding) 668 return 0; 669 670 return vcodec_clks_get(core, dev, core->vcodec0_clks, 671 core->res->vcodec0_clks); 672 } 673 674 static void vdec_put_v4(struct device *dev) 675 { 676 struct venus_core *core = dev_get_drvdata(dev); 677 unsigned int i; 678 679 if (!legacy_binding) 680 return; 681 682 for (i = 0; i < core->res->vcodec_clks_num; i++) 683 core->vcodec0_clks[i] = NULL; 684 } 685 686 static int vdec_power_v4(struct device *dev, int on) 687 { 688 struct venus_core *core = dev_get_drvdata(dev); 689 int ret; 690 691 if (!legacy_binding) 692 return 0; 693 694 ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); 695 if (ret) 696 return ret; 697 698 if (on == POWER_ON) 699 ret = vcodec_clks_enable(core, core->vcodec0_clks); 700 else 701 vcodec_clks_disable(core, core->vcodec0_clks); 702 703 vcodec_control_v4(core, VIDC_CORE_ID_1, false); 704 705 return ret; 706 } 707 708 static int venc_get_v4(struct device *dev) 709 { 710 struct venus_core *core = dev_get_drvdata(dev); 711 712 if (!legacy_binding) 713 return 0; 714 715 return vcodec_clks_get(core, dev, core->vcodec1_clks, 716 core->res->vcodec1_clks); 717 } 718 719 static void venc_put_v4(struct device *dev) 720 { 721 struct venus_core *core = dev_get_drvdata(dev); 722 unsigned int i; 723 724 if (!legacy_binding) 725 return; 726 727 for (i = 0; i < core->res->vcodec_clks_num; i++) 728 core->vcodec1_clks[i] = NULL; 729 } 730 731 static int venc_power_v4(struct device *dev, int on) 732 { 733 struct venus_core *core = dev_get_drvdata(dev); 734 int ret; 735 736 if (!legacy_binding) 737 return 0; 738 739 ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); 740 if (ret) 741 return ret; 742 743 if (on == POWER_ON) 744 ret = vcodec_clks_enable(core, core->vcodec1_clks); 745 else 746 vcodec_clks_disable(core, core->vcodec1_clks); 747 748 vcodec_control_v4(core, VIDC_CORE_ID_2, false); 749 750 return ret; 751 } 752 753 static int vcodec_domains_get(struct venus_core *core) 754 { 755 int ret; 756 struct opp_table *opp_table; 757 struct device **opp_virt_dev; 758 struct device *dev = core->dev; 759 const struct venus_resources *res = core->res; 760 struct device *pd; 761 unsigned int i; 762 763 if (!res->vcodec_pmdomains_num) 764 goto skip_pmdomains; 765 766 for (i = 0; i < res->vcodec_pmdomains_num; i++) { 767 pd = dev_pm_domain_attach_by_name(dev, 768 res->vcodec_pmdomains[i]); 769 if (IS_ERR(pd)) 770 return PTR_ERR(pd); 771 core->pmdomains[i] = pd; 772 } 773 774 skip_pmdomains: 775 if (!core->has_opp_table) 776 return 0; 777 778 /* Attach the power domain for setting performance state */ 779 opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); 780 if (IS_ERR(opp_table)) { 781 ret = PTR_ERR(opp_table); 782 goto opp_attach_err; 783 } 784 785 core->opp_pmdomain = *opp_virt_dev; 786 core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, 787 DL_FLAG_RPM_ACTIVE | 788 DL_FLAG_PM_RUNTIME | 789 DL_FLAG_STATELESS); 790 if (!core->opp_dl_venus) { 791 ret = -ENODEV; 792 goto opp_dl_add_err; 793 } 794 795 return 0; 796 797 opp_dl_add_err: 798 dev_pm_opp_detach_genpd(core->opp_table); 799 opp_attach_err: 800 for (i = 0; i < res->vcodec_pmdomains_num; i++) { 801 if (IS_ERR_OR_NULL(core->pmdomains[i])) 802 continue; 803 dev_pm_domain_detach(core->pmdomains[i], true); 804 } 805 806 return ret; 807 } 808 809 static void vcodec_domains_put(struct venus_core *core) 810 { 811 const struct venus_resources *res = core->res; 812 unsigned int i; 813 814 if (!res->vcodec_pmdomains_num) 815 goto skip_pmdomains; 816 817 for (i = 0; i < res->vcodec_pmdomains_num; i++) { 818 if (IS_ERR_OR_NULL(core->pmdomains[i])) 819 continue; 820 dev_pm_domain_detach(core->pmdomains[i], true); 821 } 822 823 skip_pmdomains: 824 if (!core->has_opp_table) 825 return; 826 827 if (core->opp_dl_venus) 828 device_link_del(core->opp_dl_venus); 829 830 dev_pm_opp_detach_genpd(core->opp_table); 831 } 832 833 static int core_get_v4(struct venus_core *core) 834 { 835 struct device *dev = core->dev; 836 const struct venus_resources *res = core->res; 837 int ret; 838 839 ret = core_clks_get(core); 840 if (ret) 841 return ret; 842 843 if (!res->vcodec_pmdomains_num) 844 legacy_binding = true; 845 846 dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non"); 847 848 ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks); 849 if (ret) 850 return ret; 851 852 ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks); 853 if (ret) 854 return ret; 855 856 if (legacy_binding) 857 return 0; 858 859 core->opp_table = dev_pm_opp_set_clkname(dev, "core"); 860 if (IS_ERR(core->opp_table)) 861 return PTR_ERR(core->opp_table); 862 863 if (core->res->opp_pmdomain) { 864 ret = dev_pm_opp_of_add_table(dev); 865 if (!ret) { 866 core->has_opp_table = true; 867 } else if (ret != -ENODEV) { 868 dev_err(dev, "invalid OPP table in device tree\n"); 869 dev_pm_opp_put_clkname(core->opp_table); 870 return ret; 871 } 872 } 873 874 ret = vcodec_domains_get(core); 875 if (ret) { 876 if (core->has_opp_table) 877 dev_pm_opp_of_remove_table(dev); 878 dev_pm_opp_put_clkname(core->opp_table); 879 return ret; 880 } 881 882 return 0; 883 } 884 885 static void core_put_v4(struct venus_core *core) 886 { 887 struct device *dev = core->dev; 888 889 if (legacy_binding) 890 return; 891 892 vcodec_domains_put(core); 893 894 if (core->has_opp_table) 895 dev_pm_opp_of_remove_table(dev); 896 dev_pm_opp_put_clkname(core->opp_table); 897 898 } 899 900 static int core_power_v4(struct venus_core *core, int on) 901 { 902 struct device *dev = core->dev; 903 struct device *pmctrl = core->pmdomains[0]; 904 int ret = 0; 905 906 if (on == POWER_ON) { 907 if (pmctrl) { 908 ret = pm_runtime_get_sync(pmctrl); 909 if (ret < 0) { 910 pm_runtime_put_noidle(pmctrl); 911 return ret; 912 } 913 } 914 915 ret = core_clks_enable(core); 916 if (ret < 0 && pmctrl) 917 pm_runtime_put_sync(pmctrl); 918 } else { 919 /* Drop the performance state vote */ 920 if (core->opp_pmdomain) 921 dev_pm_opp_set_rate(dev, 0); 922 923 core_clks_disable(core); 924 925 if (pmctrl) 926 pm_runtime_put_sync(pmctrl); 927 } 928 929 return ret; 930 } 931 932 static unsigned long calculate_inst_freq(struct venus_inst *inst, 933 unsigned long filled_len) 934 { 935 unsigned long vpp_freq = 0, vsp_freq = 0; 936 u32 fps = (u32)inst->fps; 937 u32 mbs_per_sec; 938 939 mbs_per_sec = load_per_instance(inst); 940 941 if (inst->state != INST_START) 942 return 0; 943 944 vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq; 945 /* 21 / 20 is overhead factor */ 946 vpp_freq += vpp_freq / 20; 947 vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq; 948 949 /* 10 / 7 is overhead factor */ 950 if (inst->session_type == VIDC_SESSION_TYPE_ENC) 951 vsp_freq += (inst->controls.enc.bitrate * 10) / 7; 952 else 953 vsp_freq += ((fps * filled_len * 8) * 10) / 7; 954 955 return max(vpp_freq, vsp_freq); 956 } 957 958 static int load_scale_v4(struct venus_inst *inst) 959 { 960 struct venus_core *core = inst->core; 961 const struct freq_tbl *table = core->res->freq_tbl; 962 unsigned int num_rows = core->res->freq_tbl_size; 963 struct device *dev = core->dev; 964 unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; 965 unsigned long filled_len = 0; 966 int i, ret; 967 968 for (i = 0; i < inst->num_input_bufs; i++) 969 filled_len = max(filled_len, inst->payloads[i]); 970 971 if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len) 972 return 0; 973 974 freq = calculate_inst_freq(inst, filled_len); 975 inst->clk_data.freq = freq; 976 977 mutex_lock(&core->lock); 978 list_for_each_entry(inst, &core->instances, list) { 979 if (inst->clk_data.core_id == VIDC_CORE_ID_1) { 980 freq_core1 += inst->clk_data.freq; 981 } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) { 982 freq_core2 += inst->clk_data.freq; 983 } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) { 984 freq_core1 += inst->clk_data.freq; 985 freq_core2 += inst->clk_data.freq; 986 } 987 } 988 mutex_unlock(&core->lock); 989 990 freq = max(freq_core1, freq_core2); 991 992 if (freq >= table[0].freq) { 993 freq = table[0].freq; 994 dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", 995 freq, table[0].freq); 996 goto set_freq; 997 } 998 999 for (i = num_rows - 1 ; i >= 0; i--) { 1000 if (freq <= table[i].freq) { 1001 freq = table[i].freq; 1002 break; 1003 } 1004 } 1005 1006 set_freq: 1007 1008 ret = core_clks_set_rate(core, freq); 1009 if (ret) { 1010 dev_err(dev, "failed to set clock rate %lu (%d)\n", 1011 freq, ret); 1012 return ret; 1013 } 1014 1015 ret = load_scale_bw(core); 1016 if (ret) { 1017 dev_err(dev, "failed to set bandwidth (%d)\n", 1018 ret); 1019 return ret; 1020 } 1021 1022 return 0; 1023 } 1024 1025 static const struct venus_pm_ops pm_ops_v4 = { 1026 .core_get = core_get_v4, 1027 .core_put = core_put_v4, 1028 .core_power = core_power_v4, 1029 .vdec_get = vdec_get_v4, 1030 .vdec_put = vdec_put_v4, 1031 .vdec_power = vdec_power_v4, 1032 .venc_get = venc_get_v4, 1033 .venc_put = venc_put_v4, 1034 .venc_power = venc_power_v4, 1035 .coreid_power = coreid_power_v4, 1036 .load_scale = load_scale_v4, 1037 }; 1038 1039 const struct venus_pm_ops *venus_pm_get(enum hfi_version version) 1040 { 1041 switch (version) { 1042 case HFI_VERSION_1XX: 1043 default: 1044 return &pm_ops_v1; 1045 case HFI_VERSION_3XX: 1046 return &pm_ops_v3; 1047 case HFI_VERSION_4XX: 1048 return &pm_ops_v4; 1049 } 1050 1051 return NULL; 1052 } 1053