diff options
author | Rex Zhu <Rex.Zhu@amd.com> | 2018-03-09 06:52:26 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2018-03-15 10:57:21 -0400 |
commit | 8e68627958f2fe9cf2f106656e007b8d3cd7cc47 (patch) | |
tree | 75ba05936bb13d6531b2ada7793a0d2b377c249a /drivers/gpu/drm/amd | |
parent | c425688520990d6cec769faaa97f4af45d361fd1 (diff) |
drm/amd/pp: Move helper functions to smu_help.c
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Signed-off-by: Rex Zhu <Rex.Zhu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 513 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c | 536 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h | 180 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 155 |
5 files changed, 723 insertions, 663 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index 1fa9a97e24c1..455e57266f13 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | |||
@@ -31,7 +31,7 @@ HARDWARE_MGR = hwmgr.o processpptables.o \ | |||
31 | smu7_clockpowergating.o \ | 31 | smu7_clockpowergating.o \ |
32 | vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ | 32 | vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ |
33 | vega10_thermal.o smu10_hwmgr.o pp_psm.o\ | 33 | vega10_thermal.o smu10_hwmgr.o pp_psm.o\ |
34 | pp_overdriver.o | 34 | pp_overdriver.o smu_helper.o |
35 | 35 | ||
36 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) | 36 | AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) |
37 | 37 | ||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 3432dc066fe7..5563b6502c4d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #include <drm/amdgpu_drm.h> | 30 | #include <drm/amdgpu_drm.h> |
31 | #include "power_state.h" | 31 | #include "power_state.h" |
32 | #include "hwmgr.h" | 32 | #include "hwmgr.h" |
33 | #include "pppcielanes.h" | ||
34 | #include "ppatomctrl.h" | ||
35 | #include "ppsmc.h" | 33 | #include "ppsmc.h" |
36 | #include "amd_acpi.h" | 34 | #include "amd_acpi.h" |
37 | #include "pp_psm.h" | 35 | #include "pp_psm.h" |
@@ -45,7 +43,11 @@ extern const struct pp_smumgr_func polaris10_smu_funcs; | |||
45 | extern const struct pp_smumgr_func vega10_smu_funcs; | 43 | extern const struct pp_smumgr_func vega10_smu_funcs; |
46 | extern const struct pp_smumgr_func smu10_smu_funcs; | 44 | extern const struct pp_smumgr_func smu10_smu_funcs; |
47 | 45 | ||
46 | extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); | ||
48 | extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); | 47 | extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); |
48 | extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); | ||
49 | extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); | ||
50 | |||
49 | static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr); | 51 | static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr); |
50 | static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr); | 52 | static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr); |
51 | static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr); | 53 | static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr); |
@@ -54,32 +56,6 @@ static int tonga_set_asic_special_caps(struct pp_hwmgr *hwmgr); | |||
54 | static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr); | 56 | static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr); |
55 | static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr); | 57 | static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr); |
56 | 58 | ||
57 | uint8_t convert_to_vid(uint16_t vddc) | ||
58 | { | ||
59 | return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); | ||
60 | } | ||
61 | |||
62 | uint16_t convert_to_vddc(uint8_t vid) | ||
63 | { | ||
64 | return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); | ||
65 | } | ||
66 | |||
67 | uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size) | ||
68 | { | ||
69 | u32 mask = 0; | ||
70 | u32 shift = 0; | ||
71 | |||
72 | shift = (offset % 4) << 3; | ||
73 | if (size == sizeof(uint8_t)) | ||
74 | mask = 0xFF << shift; | ||
75 | else if (size == sizeof(uint16_t)) | ||
76 | mask = 0xFFFF << shift; | ||
77 | |||
78 | original_data &= ~mask; | ||
79 | original_data |= (field << shift); | ||
80 | return original_data; | ||
81 | } | ||
82 | |||
83 | static int phm_thermal_l2h_irq(void *private_data, | 59 | static int phm_thermal_l2h_irq(void *private_data, |
84 | unsigned src_id, const uint32_t *iv_entry) | 60 | unsigned src_id, const uint32_t *iv_entry) |
85 | { | 61 | { |
@@ -432,468 +408,6 @@ int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, | |||
432 | } | 408 | } |
433 | return ret; | 409 | return ret; |
434 | } | 410 | } |
435 | /** | ||
436 | * Returns once the part of the register indicated by the mask has | ||
437 | * reached the given value. | ||
438 | */ | ||
439 | int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | ||
440 | uint32_t value, uint32_t mask) | ||
441 | { | ||
442 | uint32_t i; | ||
443 | uint32_t cur_value; | ||
444 | |||
445 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
446 | pr_err("Invalid Hardware Manager!"); | ||
447 | return -EINVAL; | ||
448 | } | ||
449 | |||
450 | for (i = 0; i < hwmgr->usec_timeout; i++) { | ||
451 | cur_value = cgs_read_register(hwmgr->device, index); | ||
452 | if ((cur_value & mask) == (value & mask)) | ||
453 | break; | ||
454 | udelay(1); | ||
455 | } | ||
456 | |||
457 | /* timeout means wrong logic*/ | ||
458 | if (i == hwmgr->usec_timeout) | ||
459 | return -1; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | |||
464 | /** | ||
465 | * Returns once the part of the register indicated by the mask has | ||
466 | * reached the given value.The indirect space is described by giving | ||
467 | * the memory-mapped index of the indirect index register. | ||
468 | */ | ||
469 | int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | ||
470 | uint32_t indirect_port, | ||
471 | uint32_t index, | ||
472 | uint32_t value, | ||
473 | uint32_t mask) | ||
474 | { | ||
475 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
476 | pr_err("Invalid Hardware Manager!"); | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | cgs_write_register(hwmgr->device, indirect_port, index); | ||
481 | return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); | ||
482 | } | ||
483 | |||
484 | int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
485 | uint32_t index, | ||
486 | uint32_t value, uint32_t mask) | ||
487 | { | ||
488 | uint32_t i; | ||
489 | uint32_t cur_value; | ||
490 | |||
491 | if (hwmgr == NULL || hwmgr->device == NULL) | ||
492 | return -EINVAL; | ||
493 | |||
494 | for (i = 0; i < hwmgr->usec_timeout; i++) { | ||
495 | cur_value = cgs_read_register(hwmgr->device, | ||
496 | index); | ||
497 | if ((cur_value & mask) != (value & mask)) | ||
498 | break; | ||
499 | udelay(1); | ||
500 | } | ||
501 | |||
502 | /* timeout means wrong logic */ | ||
503 | if (i == hwmgr->usec_timeout) | ||
504 | return -ETIME; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, | ||
509 | uint32_t indirect_port, | ||
510 | uint32_t index, | ||
511 | uint32_t value, | ||
512 | uint32_t mask) | ||
513 | { | ||
514 | if (hwmgr == NULL || hwmgr->device == NULL) | ||
515 | return -EINVAL; | ||
516 | |||
517 | cgs_write_register(hwmgr->device, indirect_port, index); | ||
518 | return phm_wait_for_register_unequal(hwmgr, indirect_port + 1, | ||
519 | value, mask); | ||
520 | } | ||
521 | |||
522 | bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) | ||
523 | { | ||
524 | return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating); | ||
525 | } | ||
526 | |||
527 | bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr) | ||
528 | { | ||
529 | return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); | ||
530 | } | ||
531 | |||
532 | |||
533 | int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) | ||
534 | { | ||
535 | uint32_t i, j; | ||
536 | uint16_t vvalue; | ||
537 | bool found = false; | ||
538 | struct pp_atomctrl_voltage_table *table; | ||
539 | |||
540 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
541 | "Voltage Table empty.", return -EINVAL); | ||
542 | |||
543 | table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), | ||
544 | GFP_KERNEL); | ||
545 | |||
546 | if (NULL == table) | ||
547 | return -EINVAL; | ||
548 | |||
549 | table->mask_low = vol_table->mask_low; | ||
550 | table->phase_delay = vol_table->phase_delay; | ||
551 | |||
552 | for (i = 0; i < vol_table->count; i++) { | ||
553 | vvalue = vol_table->entries[i].value; | ||
554 | found = false; | ||
555 | |||
556 | for (j = 0; j < table->count; j++) { | ||
557 | if (vvalue == table->entries[j].value) { | ||
558 | found = true; | ||
559 | break; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | if (!found) { | ||
564 | table->entries[table->count].value = vvalue; | ||
565 | table->entries[table->count].smio_low = | ||
566 | vol_table->entries[i].smio_low; | ||
567 | table->count++; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); | ||
572 | kfree(table); | ||
573 | table = NULL; | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
578 | phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
579 | { | ||
580 | uint32_t i; | ||
581 | int result; | ||
582 | |||
583 | PP_ASSERT_WITH_CODE((0 != dep_table->count), | ||
584 | "Voltage Dependency Table empty.", return -EINVAL); | ||
585 | |||
586 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
587 | "vol_table empty.", return -EINVAL); | ||
588 | |||
589 | vol_table->mask_low = 0; | ||
590 | vol_table->phase_delay = 0; | ||
591 | vol_table->count = dep_table->count; | ||
592 | |||
593 | for (i = 0; i < dep_table->count; i++) { | ||
594 | vol_table->entries[i].value = dep_table->entries[i].mvdd; | ||
595 | vol_table->entries[i].smio_low = 0; | ||
596 | } | ||
597 | |||
598 | result = phm_trim_voltage_table(vol_table); | ||
599 | PP_ASSERT_WITH_CODE((0 == result), | ||
600 | "Failed to trim MVDD table.", return result); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
606 | phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
607 | { | ||
608 | uint32_t i; | ||
609 | int result; | ||
610 | |||
611 | PP_ASSERT_WITH_CODE((0 != dep_table->count), | ||
612 | "Voltage Dependency Table empty.", return -EINVAL); | ||
613 | |||
614 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
615 | "vol_table empty.", return -EINVAL); | ||
616 | |||
617 | vol_table->mask_low = 0; | ||
618 | vol_table->phase_delay = 0; | ||
619 | vol_table->count = dep_table->count; | ||
620 | |||
621 | for (i = 0; i < dep_table->count; i++) { | ||
622 | vol_table->entries[i].value = dep_table->entries[i].vddci; | ||
623 | vol_table->entries[i].smio_low = 0; | ||
624 | } | ||
625 | |||
626 | result = phm_trim_voltage_table(vol_table); | ||
627 | PP_ASSERT_WITH_CODE((0 == result), | ||
628 | "Failed to trim VDDCI table.", return result); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
634 | phm_ppt_v1_voltage_lookup_table *lookup_table) | ||
635 | { | ||
636 | int i = 0; | ||
637 | |||
638 | PP_ASSERT_WITH_CODE((0 != lookup_table->count), | ||
639 | "Voltage Lookup Table empty.", return -EINVAL); | ||
640 | |||
641 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
642 | "vol_table empty.", return -EINVAL); | ||
643 | |||
644 | vol_table->mask_low = 0; | ||
645 | vol_table->phase_delay = 0; | ||
646 | |||
647 | vol_table->count = lookup_table->count; | ||
648 | |||
649 | for (i = 0; i < vol_table->count; i++) { | ||
650 | vol_table->entries[i].value = lookup_table->entries[i].us_vdd; | ||
651 | vol_table->entries[i].smio_low = 0; | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, | ||
658 | struct pp_atomctrl_voltage_table *vol_table) | ||
659 | { | ||
660 | unsigned int i, diff; | ||
661 | |||
662 | if (vol_table->count <= max_vol_steps) | ||
663 | return; | ||
664 | |||
665 | diff = vol_table->count - max_vol_steps; | ||
666 | |||
667 | for (i = 0; i < max_vol_steps; i++) | ||
668 | vol_table->entries[i] = vol_table->entries[i + diff]; | ||
669 | |||
670 | vol_table->count = max_vol_steps; | ||
671 | |||
672 | return; | ||
673 | } | ||
674 | |||
675 | int phm_reset_single_dpm_table(void *table, | ||
676 | uint32_t count, int max) | ||
677 | { | ||
678 | int i; | ||
679 | |||
680 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
681 | |||
682 | dpm_table->count = count > max ? max : count; | ||
683 | |||
684 | for (i = 0; i < dpm_table->count; i++) | ||
685 | dpm_table->dpm_level[i].enabled = false; | ||
686 | |||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | void phm_setup_pcie_table_entry( | ||
691 | void *table, | ||
692 | uint32_t index, uint32_t pcie_gen, | ||
693 | uint32_t pcie_lanes) | ||
694 | { | ||
695 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
696 | dpm_table->dpm_level[index].value = pcie_gen; | ||
697 | dpm_table->dpm_level[index].param1 = pcie_lanes; | ||
698 | dpm_table->dpm_level[index].enabled = 1; | ||
699 | } | ||
700 | |||
701 | int32_t phm_get_dpm_level_enable_mask_value(void *table) | ||
702 | { | ||
703 | int32_t i; | ||
704 | int32_t mask = 0; | ||
705 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
706 | |||
707 | for (i = dpm_table->count; i > 0; i--) { | ||
708 | mask = mask << 1; | ||
709 | if (dpm_table->dpm_level[i - 1].enabled) | ||
710 | mask |= 0x1; | ||
711 | else | ||
712 | mask &= 0xFFFFFFFE; | ||
713 | } | ||
714 | |||
715 | return mask; | ||
716 | } | ||
717 | |||
718 | uint8_t phm_get_voltage_index( | ||
719 | struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage) | ||
720 | { | ||
721 | uint8_t count = (uint8_t) (lookup_table->count); | ||
722 | uint8_t i; | ||
723 | |||
724 | PP_ASSERT_WITH_CODE((NULL != lookup_table), | ||
725 | "Lookup Table empty.", return 0); | ||
726 | PP_ASSERT_WITH_CODE((0 != count), | ||
727 | "Lookup Table empty.", return 0); | ||
728 | |||
729 | for (i = 0; i < lookup_table->count; i++) { | ||
730 | /* find first voltage equal or bigger than requested */ | ||
731 | if (lookup_table->entries[i].us_vdd >= voltage) | ||
732 | return i; | ||
733 | } | ||
734 | /* voltage is bigger than max voltage in the table */ | ||
735 | return i - 1; | ||
736 | } | ||
737 | |||
738 | uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table, | ||
739 | uint32_t voltage) | ||
740 | { | ||
741 | uint8_t count = (uint8_t) (voltage_table->count); | ||
742 | uint8_t i = 0; | ||
743 | |||
744 | PP_ASSERT_WITH_CODE((NULL != voltage_table), | ||
745 | "Voltage Table empty.", return 0;); | ||
746 | PP_ASSERT_WITH_CODE((0 != count), | ||
747 | "Voltage Table empty.", return 0;); | ||
748 | |||
749 | for (i = 0; i < count; i++) { | ||
750 | /* find first voltage bigger than requested */ | ||
751 | if (voltage_table->entries[i].value >= voltage) | ||
752 | return i; | ||
753 | } | ||
754 | |||
755 | /* voltage is bigger than max voltage in the table */ | ||
756 | return i - 1; | ||
757 | } | ||
758 | |||
759 | uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci) | ||
760 | { | ||
761 | uint32_t i; | ||
762 | |||
763 | for (i = 0; i < vddci_table->count; i++) { | ||
764 | if (vddci_table->entries[i].value >= vddci) | ||
765 | return vddci_table->entries[i].value; | ||
766 | } | ||
767 | |||
768 | pr_debug("vddci is larger than max value in vddci_table\n"); | ||
769 | return vddci_table->entries[i-1].value; | ||
770 | } | ||
771 | |||
772 | int phm_find_boot_level(void *table, | ||
773 | uint32_t value, uint32_t *boot_level) | ||
774 | { | ||
775 | int result = -EINVAL; | ||
776 | uint32_t i; | ||
777 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
778 | |||
779 | for (i = 0; i < dpm_table->count; i++) { | ||
780 | if (value == dpm_table->dpm_level[i].value) { | ||
781 | *boot_level = i; | ||
782 | result = 0; | ||
783 | } | ||
784 | } | ||
785 | |||
786 | return result; | ||
787 | } | ||
788 | |||
789 | int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, | ||
790 | phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
791 | uint16_t virtual_voltage_id, int32_t *sclk) | ||
792 | { | ||
793 | uint8_t entry_id; | ||
794 | uint8_t voltage_id; | ||
795 | struct phm_ppt_v1_information *table_info = | ||
796 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
797 | |||
798 | PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL); | ||
799 | |||
800 | /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ | ||
801 | for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) { | ||
802 | voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd; | ||
803 | if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id) | ||
804 | break; | ||
805 | } | ||
806 | |||
807 | if (entry_id >= table_info->vdd_dep_on_sclk->count) { | ||
808 | pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n"); | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | *sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk; | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | /** | ||
818 | * Initialize Dynamic State Adjustment Rule Settings | ||
819 | * | ||
820 | * @param hwmgr the address of the powerplay hardware manager. | ||
821 | */ | ||
822 | int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) | ||
823 | { | ||
824 | uint32_t table_size; | ||
825 | struct phm_clock_voltage_dependency_table *table_clk_vlt; | ||
826 | struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
827 | |||
828 | /* initialize vddc_dep_on_dal_pwrl table */ | ||
829 | table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); | ||
830 | table_clk_vlt = kzalloc(table_size, GFP_KERNEL); | ||
831 | |||
832 | if (NULL == table_clk_vlt) { | ||
833 | pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); | ||
834 | return -ENOMEM; | ||
835 | } else { | ||
836 | table_clk_vlt->count = 4; | ||
837 | table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; | ||
838 | table_clk_vlt->entries[0].v = 0; | ||
839 | table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; | ||
840 | table_clk_vlt->entries[1].v = 720; | ||
841 | table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; | ||
842 | table_clk_vlt->entries[2].v = 810; | ||
843 | table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; | ||
844 | table_clk_vlt->entries[3].v = 900; | ||
845 | if (pptable_info != NULL) | ||
846 | pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; | ||
847 | hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; | ||
848 | } | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) | ||
854 | { | ||
855 | uint32_t level = 0; | ||
856 | |||
857 | while (0 == (mask & (1 << level))) | ||
858 | level++; | ||
859 | |||
860 | return level; | ||
861 | } | ||
862 | |||
863 | void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) | ||
864 | { | ||
865 | struct phm_ppt_v1_information *table_info = | ||
866 | (struct phm_ppt_v1_information *)hwmgr->pptable; | ||
867 | struct phm_clock_voltage_dependency_table *table = | ||
868 | table_info->vddc_dep_on_dal_pwrl; | ||
869 | struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; | ||
870 | enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; | ||
871 | uint32_t req_vddc = 0, req_volt, i; | ||
872 | |||
873 | if (!table || table->count <= 0 | ||
874 | || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW | ||
875 | || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) | ||
876 | return; | ||
877 | |||
878 | for (i = 0; i < table->count; i++) { | ||
879 | if (dal_power_level == table->entries[i].clk) { | ||
880 | req_vddc = table->entries[i].v; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | |||
885 | vddc_table = table_info->vdd_dep_on_sclk; | ||
886 | for (i = 0; i < vddc_table->count; i++) { | ||
887 | if (req_vddc <= vddc_table->entries[i].vddc) { | ||
888 | req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); | ||
889 | smum_send_msg_to_smc_with_parameter(hwmgr, | ||
890 | PPSMC_MSG_VddC_Request, req_volt); | ||
891 | return; | ||
892 | } | ||
893 | } | ||
894 | pr_err("DAL requested level can not" | ||
895 | " found a available voltage in VDDC DPM Table \n"); | ||
896 | } | ||
897 | 411 | ||
898 | void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr) | 412 | void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr) |
899 | { | 413 | { |
@@ -954,25 +468,6 @@ int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr) | |||
954 | return 0; | 468 | return 0; |
955 | } | 469 | } |
956 | 470 | ||
957 | int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, | ||
958 | uint32_t sclk, uint16_t id, uint16_t *voltage) | ||
959 | { | ||
960 | uint32_t vol; | ||
961 | int ret = 0; | ||
962 | |||
963 | if (hwmgr->chip_id < CHIP_TONGA) { | ||
964 | ret = atomctrl_get_voltage_evv(hwmgr, id, voltage); | ||
965 | } else if (hwmgr->chip_id < CHIP_POLARIS10) { | ||
966 | ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage); | ||
967 | if (*voltage >= 2000 || *voltage == 0) | ||
968 | *voltage = 1150; | ||
969 | } else { | ||
970 | ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol); | ||
971 | *voltage = (uint16_t)(vol/100); | ||
972 | } | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) | 471 | int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) |
977 | { | 472 | { |
978 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, | 473 | phm_cap_set(hwmgr->platform_descriptor.platformCaps, |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c new file mode 100644 index 000000000000..e11daf5cbf80 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c | |||
@@ -0,0 +1,536 @@ | |||
1 | /* | ||
2 | * Copyright 2018 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #include "hwmgr.h" | ||
24 | #include "pp_debug.h" | ||
25 | #include "ppatomctrl.h" | ||
26 | #include "ppsmc.h" | ||
27 | |||
28 | uint8_t convert_to_vid(uint16_t vddc) | ||
29 | { | ||
30 | return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); | ||
31 | } | ||
32 | |||
33 | uint16_t convert_to_vddc(uint8_t vid) | ||
34 | { | ||
35 | return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); | ||
36 | } | ||
37 | |||
38 | uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size) | ||
39 | { | ||
40 | u32 mask = 0; | ||
41 | u32 shift = 0; | ||
42 | |||
43 | shift = (offset % 4) << 3; | ||
44 | if (size == sizeof(uint8_t)) | ||
45 | mask = 0xFF << shift; | ||
46 | else if (size == sizeof(uint16_t)) | ||
47 | mask = 0xFFFF << shift; | ||
48 | |||
49 | original_data &= ~mask; | ||
50 | original_data |= (field << shift); | ||
51 | return original_data; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * Returns once the part of the register indicated by the mask has | ||
56 | * reached the given value. | ||
57 | */ | ||
58 | int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | ||
59 | uint32_t value, uint32_t mask) | ||
60 | { | ||
61 | uint32_t i; | ||
62 | uint32_t cur_value; | ||
63 | |||
64 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
65 | pr_err("Invalid Hardware Manager!"); | ||
66 | return -EINVAL; | ||
67 | } | ||
68 | |||
69 | for (i = 0; i < hwmgr->usec_timeout; i++) { | ||
70 | cur_value = cgs_read_register(hwmgr->device, index); | ||
71 | if ((cur_value & mask) == (value & mask)) | ||
72 | break; | ||
73 | udelay(1); | ||
74 | } | ||
75 | |||
76 | /* timeout means wrong logic*/ | ||
77 | if (i == hwmgr->usec_timeout) | ||
78 | return -1; | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Returns once the part of the register indicated by the mask has | ||
85 | * reached the given value.The indirect space is described by giving | ||
86 | * the memory-mapped index of the indirect index register. | ||
87 | */ | ||
88 | int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | ||
89 | uint32_t indirect_port, | ||
90 | uint32_t index, | ||
91 | uint32_t value, | ||
92 | uint32_t mask) | ||
93 | { | ||
94 | if (hwmgr == NULL || hwmgr->device == NULL) { | ||
95 | pr_err("Invalid Hardware Manager!"); | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | cgs_write_register(hwmgr->device, indirect_port, index); | ||
100 | return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); | ||
101 | } | ||
102 | |||
103 | int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
104 | uint32_t index, | ||
105 | uint32_t value, uint32_t mask) | ||
106 | { | ||
107 | uint32_t i; | ||
108 | uint32_t cur_value; | ||
109 | |||
110 | if (hwmgr == NULL || hwmgr->device == NULL) | ||
111 | return -EINVAL; | ||
112 | |||
113 | for (i = 0; i < hwmgr->usec_timeout; i++) { | ||
114 | cur_value = cgs_read_register(hwmgr->device, | ||
115 | index); | ||
116 | if ((cur_value & mask) != (value & mask)) | ||
117 | break; | ||
118 | udelay(1); | ||
119 | } | ||
120 | |||
121 | /* timeout means wrong logic */ | ||
122 | if (i == hwmgr->usec_timeout) | ||
123 | return -ETIME; | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr, | ||
128 | uint32_t indirect_port, | ||
129 | uint32_t index, | ||
130 | uint32_t value, | ||
131 | uint32_t mask) | ||
132 | { | ||
133 | if (hwmgr == NULL || hwmgr->device == NULL) | ||
134 | return -EINVAL; | ||
135 | |||
136 | cgs_write_register(hwmgr->device, indirect_port, index); | ||
137 | return phm_wait_for_register_unequal(hwmgr, indirect_port + 1, | ||
138 | value, mask); | ||
139 | } | ||
140 | |||
141 | bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr) | ||
142 | { | ||
143 | return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating); | ||
144 | } | ||
145 | |||
146 | bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr) | ||
147 | { | ||
148 | return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); | ||
149 | } | ||
150 | |||
151 | |||
152 | int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) | ||
153 | { | ||
154 | uint32_t i, j; | ||
155 | uint16_t vvalue; | ||
156 | bool found = false; | ||
157 | struct pp_atomctrl_voltage_table *table; | ||
158 | |||
159 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
160 | "Voltage Table empty.", return -EINVAL); | ||
161 | |||
162 | table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), | ||
163 | GFP_KERNEL); | ||
164 | |||
165 | if (NULL == table) | ||
166 | return -EINVAL; | ||
167 | |||
168 | table->mask_low = vol_table->mask_low; | ||
169 | table->phase_delay = vol_table->phase_delay; | ||
170 | |||
171 | for (i = 0; i < vol_table->count; i++) { | ||
172 | vvalue = vol_table->entries[i].value; | ||
173 | found = false; | ||
174 | |||
175 | for (j = 0; j < table->count; j++) { | ||
176 | if (vvalue == table->entries[j].value) { | ||
177 | found = true; | ||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if (!found) { | ||
183 | table->entries[table->count].value = vvalue; | ||
184 | table->entries[table->count].smio_low = | ||
185 | vol_table->entries[i].smio_low; | ||
186 | table->count++; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); | ||
191 | kfree(table); | ||
192 | table = NULL; | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
197 | phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
198 | { | ||
199 | uint32_t i; | ||
200 | int result; | ||
201 | |||
202 | PP_ASSERT_WITH_CODE((0 != dep_table->count), | ||
203 | "Voltage Dependency Table empty.", return -EINVAL); | ||
204 | |||
205 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
206 | "vol_table empty.", return -EINVAL); | ||
207 | |||
208 | vol_table->mask_low = 0; | ||
209 | vol_table->phase_delay = 0; | ||
210 | vol_table->count = dep_table->count; | ||
211 | |||
212 | for (i = 0; i < dep_table->count; i++) { | ||
213 | vol_table->entries[i].value = dep_table->entries[i].mvdd; | ||
214 | vol_table->entries[i].smio_low = 0; | ||
215 | } | ||
216 | |||
217 | result = phm_trim_voltage_table(vol_table); | ||
218 | PP_ASSERT_WITH_CODE((0 == result), | ||
219 | "Failed to trim MVDD table.", return result); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
225 | phm_ppt_v1_clock_voltage_dependency_table *dep_table) | ||
226 | { | ||
227 | uint32_t i; | ||
228 | int result; | ||
229 | |||
230 | PP_ASSERT_WITH_CODE((0 != dep_table->count), | ||
231 | "Voltage Dependency Table empty.", return -EINVAL); | ||
232 | |||
233 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
234 | "vol_table empty.", return -EINVAL); | ||
235 | |||
236 | vol_table->mask_low = 0; | ||
237 | vol_table->phase_delay = 0; | ||
238 | vol_table->count = dep_table->count; | ||
239 | |||
240 | for (i = 0; i < dep_table->count; i++) { | ||
241 | vol_table->entries[i].value = dep_table->entries[i].vddci; | ||
242 | vol_table->entries[i].smio_low = 0; | ||
243 | } | ||
244 | |||
245 | result = phm_trim_voltage_table(vol_table); | ||
246 | PP_ASSERT_WITH_CODE((0 == result), | ||
247 | "Failed to trim VDDCI table.", return result); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, | ||
253 | phm_ppt_v1_voltage_lookup_table *lookup_table) | ||
254 | { | ||
255 | int i = 0; | ||
256 | |||
257 | PP_ASSERT_WITH_CODE((0 != lookup_table->count), | ||
258 | "Voltage Lookup Table empty.", return -EINVAL); | ||
259 | |||
260 | PP_ASSERT_WITH_CODE((NULL != vol_table), | ||
261 | "vol_table empty.", return -EINVAL); | ||
262 | |||
263 | vol_table->mask_low = 0; | ||
264 | vol_table->phase_delay = 0; | ||
265 | |||
266 | vol_table->count = lookup_table->count; | ||
267 | |||
268 | for (i = 0; i < vol_table->count; i++) { | ||
269 | vol_table->entries[i].value = lookup_table->entries[i].us_vdd; | ||
270 | vol_table->entries[i].smio_low = 0; | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, | ||
277 | struct pp_atomctrl_voltage_table *vol_table) | ||
278 | { | ||
279 | unsigned int i, diff; | ||
280 | |||
281 | if (vol_table->count <= max_vol_steps) | ||
282 | return; | ||
283 | |||
284 | diff = vol_table->count - max_vol_steps; | ||
285 | |||
286 | for (i = 0; i < max_vol_steps; i++) | ||
287 | vol_table->entries[i] = vol_table->entries[i + diff]; | ||
288 | |||
289 | vol_table->count = max_vol_steps; | ||
290 | |||
291 | return; | ||
292 | } | ||
293 | |||
294 | int phm_reset_single_dpm_table(void *table, | ||
295 | uint32_t count, int max) | ||
296 | { | ||
297 | int i; | ||
298 | |||
299 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
300 | |||
301 | dpm_table->count = count > max ? max : count; | ||
302 | |||
303 | for (i = 0; i < dpm_table->count; i++) | ||
304 | dpm_table->dpm_level[i].enabled = false; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | void phm_setup_pcie_table_entry( | ||
310 | void *table, | ||
311 | uint32_t index, uint32_t pcie_gen, | ||
312 | uint32_t pcie_lanes) | ||
313 | { | ||
314 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
315 | dpm_table->dpm_level[index].value = pcie_gen; | ||
316 | dpm_table->dpm_level[index].param1 = pcie_lanes; | ||
317 | dpm_table->dpm_level[index].enabled = 1; | ||
318 | } | ||
319 | |||
320 | int32_t phm_get_dpm_level_enable_mask_value(void *table) | ||
321 | { | ||
322 | int32_t i; | ||
323 | int32_t mask = 0; | ||
324 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
325 | |||
326 | for (i = dpm_table->count; i > 0; i--) { | ||
327 | mask = mask << 1; | ||
328 | if (dpm_table->dpm_level[i - 1].enabled) | ||
329 | mask |= 0x1; | ||
330 | else | ||
331 | mask &= 0xFFFFFFFE; | ||
332 | } | ||
333 | |||
334 | return mask; | ||
335 | } | ||
336 | |||
337 | uint8_t phm_get_voltage_index( | ||
338 | struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage) | ||
339 | { | ||
340 | uint8_t count = (uint8_t) (lookup_table->count); | ||
341 | uint8_t i; | ||
342 | |||
343 | PP_ASSERT_WITH_CODE((NULL != lookup_table), | ||
344 | "Lookup Table empty.", return 0); | ||
345 | PP_ASSERT_WITH_CODE((0 != count), | ||
346 | "Lookup Table empty.", return 0); | ||
347 | |||
348 | for (i = 0; i < lookup_table->count; i++) { | ||
349 | /* find first voltage equal or bigger than requested */ | ||
350 | if (lookup_table->entries[i].us_vdd >= voltage) | ||
351 | return i; | ||
352 | } | ||
353 | /* voltage is bigger than max voltage in the table */ | ||
354 | return i - 1; | ||
355 | } | ||
356 | |||
357 | uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table, | ||
358 | uint32_t voltage) | ||
359 | { | ||
360 | uint8_t count = (uint8_t) (voltage_table->count); | ||
361 | uint8_t i = 0; | ||
362 | |||
363 | PP_ASSERT_WITH_CODE((NULL != voltage_table), | ||
364 | "Voltage Table empty.", return 0;); | ||
365 | PP_ASSERT_WITH_CODE((0 != count), | ||
366 | "Voltage Table empty.", return 0;); | ||
367 | |||
368 | for (i = 0; i < count; i++) { | ||
369 | /* find first voltage bigger than requested */ | ||
370 | if (voltage_table->entries[i].value >= voltage) | ||
371 | return i; | ||
372 | } | ||
373 | |||
374 | /* voltage is bigger than max voltage in the table */ | ||
375 | return i - 1; | ||
376 | } | ||
377 | |||
378 | uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci) | ||
379 | { | ||
380 | uint32_t i; | ||
381 | |||
382 | for (i = 0; i < vddci_table->count; i++) { | ||
383 | if (vddci_table->entries[i].value >= vddci) | ||
384 | return vddci_table->entries[i].value; | ||
385 | } | ||
386 | |||
387 | pr_debug("vddci is larger than max value in vddci_table\n"); | ||
388 | return vddci_table->entries[i-1].value; | ||
389 | } | ||
390 | |||
391 | int phm_find_boot_level(void *table, | ||
392 | uint32_t value, uint32_t *boot_level) | ||
393 | { | ||
394 | int result = -EINVAL; | ||
395 | uint32_t i; | ||
396 | struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; | ||
397 | |||
398 | for (i = 0; i < dpm_table->count; i++) { | ||
399 | if (value == dpm_table->dpm_level[i].value) { | ||
400 | *boot_level = i; | ||
401 | result = 0; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | return result; | ||
406 | } | ||
407 | |||
408 | int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, | ||
409 | phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
410 | uint16_t virtual_voltage_id, int32_t *sclk) | ||
411 | { | ||
412 | uint8_t entry_id; | ||
413 | uint8_t voltage_id; | ||
414 | struct phm_ppt_v1_information *table_info = | ||
415 | (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
416 | |||
417 | PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL); | ||
418 | |||
419 | /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ | ||
420 | for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) { | ||
421 | voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd; | ||
422 | if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id) | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | if (entry_id >= table_info->vdd_dep_on_sclk->count) { | ||
427 | pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n"); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | *sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * Initialize Dynamic State Adjustment Rule Settings | ||
438 | * | ||
439 | * @param hwmgr the address of the powerplay hardware manager. | ||
440 | */ | ||
441 | int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) | ||
442 | { | ||
443 | uint32_t table_size; | ||
444 | struct phm_clock_voltage_dependency_table *table_clk_vlt; | ||
445 | struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); | ||
446 | |||
447 | /* initialize vddc_dep_on_dal_pwrl table */ | ||
448 | table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); | ||
449 | table_clk_vlt = kzalloc(table_size, GFP_KERNEL); | ||
450 | |||
451 | if (NULL == table_clk_vlt) { | ||
452 | pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); | ||
453 | return -ENOMEM; | ||
454 | } else { | ||
455 | table_clk_vlt->count = 4; | ||
456 | table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; | ||
457 | table_clk_vlt->entries[0].v = 0; | ||
458 | table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; | ||
459 | table_clk_vlt->entries[1].v = 720; | ||
460 | table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; | ||
461 | table_clk_vlt->entries[2].v = 810; | ||
462 | table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; | ||
463 | table_clk_vlt->entries[3].v = 900; | ||
464 | if (pptable_info != NULL) | ||
465 | pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; | ||
466 | hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) | ||
473 | { | ||
474 | uint32_t level = 0; | ||
475 | |||
476 | while (0 == (mask & (1 << level))) | ||
477 | level++; | ||
478 | |||
479 | return level; | ||
480 | } | ||
481 | |||
482 | void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) | ||
483 | { | ||
484 | struct phm_ppt_v1_information *table_info = | ||
485 | (struct phm_ppt_v1_information *)hwmgr->pptable; | ||
486 | struct phm_clock_voltage_dependency_table *table = | ||
487 | table_info->vddc_dep_on_dal_pwrl; | ||
488 | struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; | ||
489 | enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; | ||
490 | uint32_t req_vddc = 0, req_volt, i; | ||
491 | |||
492 | if (!table || table->count <= 0 | ||
493 | || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW | ||
494 | || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) | ||
495 | return; | ||
496 | |||
497 | for (i = 0; i < table->count; i++) { | ||
498 | if (dal_power_level == table->entries[i].clk) { | ||
499 | req_vddc = table->entries[i].v; | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | vddc_table = table_info->vdd_dep_on_sclk; | ||
505 | for (i = 0; i < vddc_table->count; i++) { | ||
506 | if (req_vddc <= vddc_table->entries[i].vddc) { | ||
507 | req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); | ||
508 | smum_send_msg_to_smc_with_parameter(hwmgr, | ||
509 | PPSMC_MSG_VddC_Request, req_volt); | ||
510 | return; | ||
511 | } | ||
512 | } | ||
513 | pr_err("DAL requested level can not" | ||
514 | " found a available voltage in VDDC DPM Table \n"); | ||
515 | } | ||
516 | |||
517 | int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, | ||
518 | uint32_t sclk, uint16_t id, uint16_t *voltage) | ||
519 | { | ||
520 | uint32_t vol; | ||
521 | int ret = 0; | ||
522 | |||
523 | if (hwmgr->chip_id < CHIP_TONGA) { | ||
524 | ret = atomctrl_get_voltage_evv(hwmgr, id, voltage); | ||
525 | } else if (hwmgr->chip_id < CHIP_POLARIS10) { | ||
526 | ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage); | ||
527 | if (*voltage >= 2000 || *voltage == 0) | ||
528 | *voltage = 1150; | ||
529 | } else { | ||
530 | ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol); | ||
531 | *voltage = (uint16_t)(vol/100); | ||
532 | } | ||
533 | return ret; | ||
534 | } | ||
535 | |||
536 | |||
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h new file mode 100644 index 000000000000..a1a491300348 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright 2018 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | #ifndef _SMU_HELPER_H_ | ||
24 | #define _SMU_HELPER_H_ | ||
25 | |||
26 | struct pp_atomctrl_voltage_table; | ||
27 | struct pp_hwmgr; | ||
28 | struct phm_ppt_v1_voltage_lookup_table; | ||
29 | |||
30 | extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
31 | uint32_t index, | ||
32 | uint32_t value, uint32_t mask); | ||
33 | extern int phm_wait_for_indirect_register_unequal( | ||
34 | struct pp_hwmgr *hwmgr, | ||
35 | uint32_t indirect_port, uint32_t index, | ||
36 | uint32_t value, uint32_t mask); | ||
37 | |||
38 | |||
39 | extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); | ||
40 | extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); | ||
41 | extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); | ||
42 | |||
43 | extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table); | ||
44 | extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); | ||
45 | extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); | ||
46 | extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table); | ||
47 | extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table); | ||
48 | extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max); | ||
49 | extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes); | ||
50 | extern int32_t phm_get_dpm_level_enable_mask_value(void *table); | ||
51 | extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table, | ||
52 | uint32_t voltage); | ||
53 | extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage); | ||
54 | extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci); | ||
55 | extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); | ||
56 | extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
57 | uint16_t virtual_voltage_id, int32_t *sclk); | ||
58 | extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); | ||
59 | extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); | ||
60 | extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); | ||
61 | |||
62 | extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, | ||
63 | uint32_t sclk, uint16_t id, uint16_t *voltage); | ||
64 | |||
65 | extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size); | ||
66 | |||
67 | extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | ||
68 | uint32_t value, uint32_t mask); | ||
69 | |||
70 | extern int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | ||
71 | uint32_t indirect_port, | ||
72 | uint32_t index, | ||
73 | uint32_t value, | ||
74 | uint32_t mask); | ||
75 | |||
76 | #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT | ||
77 | #define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK | ||
78 | |||
79 | #define PHM_SET_FIELD(origval, reg, field, fieldval) \ | ||
80 | (((origval) & ~PHM_FIELD_MASK(reg, field)) | \ | ||
81 | (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field)))) | ||
82 | |||
83 | #define PHM_GET_FIELD(value, reg, field) \ | ||
84 | (((value) & PHM_FIELD_MASK(reg, field)) >> \ | ||
85 | PHM_FIELD_SHIFT(reg, field)) | ||
86 | |||
87 | |||
88 | /* Operations on named fields. */ | ||
89 | |||
90 | #define PHM_READ_FIELD(device, reg, field) \ | ||
91 | PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field) | ||
92 | |||
93 | #define PHM_READ_INDIRECT_FIELD(device, port, reg, field) \ | ||
94 | PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
95 | reg, field) | ||
96 | |||
97 | #define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \ | ||
98 | PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
99 | reg, field) | ||
100 | |||
101 | #define PHM_WRITE_FIELD(device, reg, field, fieldval) \ | ||
102 | cgs_write_register(device, mm##reg, PHM_SET_FIELD( \ | ||
103 | cgs_read_register(device, mm##reg), reg, field, fieldval)) | ||
104 | |||
105 | #define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval) \ | ||
106 | cgs_write_ind_register(device, port, ix##reg, \ | ||
107 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
108 | reg, field, fieldval)) | ||
109 | |||
110 | #define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \ | ||
111 | cgs_write_ind_register(device, port, ix##reg, \ | ||
112 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
113 | reg, field, fieldval)) | ||
114 | |||
115 | #define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
116 | phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) | ||
117 | |||
118 | |||
119 | #define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
120 | PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
121 | |||
122 | #define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | ||
123 | PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ | ||
124 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
125 | |||
126 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
127 | phm_wait_for_indirect_register_unequal(hwmgr, \ | ||
128 | mm##port##_INDEX, index, value, mask) | ||
129 | |||
130 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
131 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
132 | |||
133 | #define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
134 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ | ||
135 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
136 | PHM_FIELD_MASK(reg, field) ) | ||
137 | |||
138 | |||
139 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
140 | port, index, value, mask) \ | ||
141 | phm_wait_for_indirect_register_unequal(hwmgr, \ | ||
142 | mm##port##_INDEX_11, index, value, mask) | ||
143 | |||
144 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
145 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
146 | |||
147 | #define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
148 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ | ||
149 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
150 | PHM_FIELD_MASK(reg, field)) | ||
151 | |||
152 | |||
153 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, \ | ||
154 | port, index, value, mask) \ | ||
155 | phm_wait_on_indirect_register(hwmgr, \ | ||
156 | mm##port##_INDEX_11, index, value, mask) | ||
157 | |||
158 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
159 | PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
160 | |||
161 | #define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | ||
162 | PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, \ | ||
163 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
164 | PHM_FIELD_MASK(reg, field)) | ||
165 | |||
166 | #define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
167 | index, value, mask) \ | ||
168 | phm_wait_for_register_unequal(hwmgr, \ | ||
169 | index, value, mask) | ||
170 | |||
171 | #define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \ | ||
172 | PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
173 | mm##reg, value, mask) | ||
174 | |||
175 | #define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \ | ||
176 | PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, \ | ||
177 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
178 | PHM_FIELD_MASK(reg, field)) | ||
179 | |||
180 | #endif /* _SMU_HELPER_H_ */ | ||
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 9bdad4875fc4..2e2e4d062134 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | |||
@@ -32,7 +32,7 @@ | |||
32 | #include "ppatomctrl.h" | 32 | #include "ppatomctrl.h" |
33 | #include "hwmgr_ppt.h" | 33 | #include "hwmgr_ppt.h" |
34 | #include "power_state.h" | 34 | #include "power_state.h" |
35 | #include "cgs_linux.h" | 35 | #include "smu_helper.h" |
36 | 36 | ||
37 | struct pp_instance; | 37 | struct pp_instance; |
38 | struct pp_hwmgr; | 38 | struct pp_hwmgr; |
@@ -777,160 +777,9 @@ extern int hwmgr_hw_resume(struct pp_instance *handle); | |||
777 | extern int hwmgr_handle_task(struct pp_instance *handle, | 777 | extern int hwmgr_handle_task(struct pp_instance *handle, |
778 | enum amd_pp_task task_id, | 778 | enum amd_pp_task task_id, |
779 | enum amd_pm_state_type *user_state); | 779 | enum amd_pm_state_type *user_state); |
780 | extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, | ||
781 | uint32_t value, uint32_t mask); | ||
782 | |||
783 | extern int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, | ||
784 | uint32_t indirect_port, | ||
785 | uint32_t index, | ||
786 | uint32_t value, | ||
787 | uint32_t mask); | ||
788 | |||
789 | extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, | ||
790 | uint32_t index, | ||
791 | uint32_t value, uint32_t mask); | ||
792 | extern int phm_wait_for_indirect_register_unequal( | ||
793 | struct pp_hwmgr *hwmgr, | ||
794 | uint32_t indirect_port, uint32_t index, | ||
795 | uint32_t value, uint32_t mask); | ||
796 | |||
797 | |||
798 | extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); | ||
799 | extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); | ||
800 | extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); | ||
801 | |||
802 | extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table); | ||
803 | extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); | ||
804 | extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); | ||
805 | extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table); | ||
806 | extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table); | ||
807 | extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max); | ||
808 | extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes); | ||
809 | extern int32_t phm_get_dpm_level_enable_mask_value(void *table); | ||
810 | extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table, | ||
811 | uint32_t voltage); | ||
812 | extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage); | ||
813 | extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci); | ||
814 | extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); | ||
815 | extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, | ||
816 | uint16_t virtual_voltage_id, int32_t *sclk); | ||
817 | extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); | ||
818 | extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); | ||
819 | extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); | ||
820 | |||
821 | extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); | ||
822 | extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); | ||
823 | extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); | ||
824 | |||
825 | extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, | ||
826 | uint32_t sclk, uint16_t id, uint16_t *voltage); | ||
827 | |||
828 | extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size); | ||
829 | 780 | ||
830 | #define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU | ||
831 | |||
832 | #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT | ||
833 | #define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK | ||
834 | |||
835 | #define PHM_SET_FIELD(origval, reg, field, fieldval) \ | ||
836 | (((origval) & ~PHM_FIELD_MASK(reg, field)) | \ | ||
837 | (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field)))) | ||
838 | |||
839 | #define PHM_GET_FIELD(value, reg, field) \ | ||
840 | (((value) & PHM_FIELD_MASK(reg, field)) >> \ | ||
841 | PHM_FIELD_SHIFT(reg, field)) | ||
842 | |||
843 | |||
844 | /* Operations on named fields. */ | ||
845 | |||
846 | #define PHM_READ_FIELD(device, reg, field) \ | ||
847 | PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field) | ||
848 | |||
849 | #define PHM_READ_INDIRECT_FIELD(device, port, reg, field) \ | ||
850 | PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
851 | reg, field) | ||
852 | |||
853 | #define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \ | ||
854 | PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
855 | reg, field) | ||
856 | |||
857 | #define PHM_WRITE_FIELD(device, reg, field, fieldval) \ | ||
858 | cgs_write_register(device, mm##reg, PHM_SET_FIELD( \ | ||
859 | cgs_read_register(device, mm##reg), reg, field, fieldval)) | ||
860 | |||
861 | #define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval) \ | ||
862 | cgs_write_ind_register(device, port, ix##reg, \ | ||
863 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
864 | reg, field, fieldval)) | ||
865 | |||
866 | #define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \ | ||
867 | cgs_write_ind_register(device, port, ix##reg, \ | ||
868 | PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \ | ||
869 | reg, field, fieldval)) | ||
870 | |||
871 | #define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
872 | phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask) | ||
873 | |||
874 | |||
875 | #define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
876 | PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
877 | 781 | ||
878 | #define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | 782 | #define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU |
879 | PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \ | ||
880 | << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field)) | ||
881 | |||
882 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \ | ||
883 | phm_wait_for_indirect_register_unequal(hwmgr, \ | ||
884 | mm##port##_INDEX, index, value, mask) | ||
885 | |||
886 | #define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
887 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
888 | |||
889 | #define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
890 | PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ | ||
891 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
892 | PHM_FIELD_MASK(reg, field) ) | ||
893 | |||
894 | |||
895 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
896 | port, index, value, mask) \ | ||
897 | phm_wait_for_indirect_register_unequal(hwmgr, \ | ||
898 | mm##port##_INDEX_11, index, value, mask) | ||
899 | |||
900 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \ | ||
901 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
902 | |||
903 | #define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \ | ||
904 | PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, \ | ||
905 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
906 | PHM_FIELD_MASK(reg, field)) | ||
907 | |||
908 | |||
909 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, \ | ||
910 | port, index, value, mask) \ | ||
911 | phm_wait_on_indirect_register(hwmgr, \ | ||
912 | mm##port##_INDEX_11, index, value, mask) | ||
913 | |||
914 | #define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \ | ||
915 | PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask) | ||
916 | |||
917 | #define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \ | ||
918 | PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, \ | ||
919 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
920 | PHM_FIELD_MASK(reg, field)) | ||
921 | |||
922 | #define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
923 | index, value, mask) \ | ||
924 | phm_wait_for_register_unequal(hwmgr, \ | ||
925 | index, value, mask) | ||
926 | |||
927 | #define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \ | ||
928 | PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, \ | ||
929 | mm##reg, value, mask) | ||
930 | 783 | ||
931 | #define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \ | ||
932 | PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, \ | ||
933 | (fieldval) << PHM_FIELD_SHIFT(reg, field), \ | ||
934 | PHM_FIELD_MASK(reg, field)) | ||
935 | 784 | ||
936 | #endif /* _HWMGR_H_ */ | 785 | #endif /* _HWMGR_H_ */ |