aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd
diff options
context:
space:
mode:
authorRex Zhu <Rex.Zhu@amd.com>2018-03-09 06:52:26 -0500
committerAlex Deucher <alexander.deucher@amd.com>2018-03-15 10:57:21 -0400
commit8e68627958f2fe9cf2f106656e007b8d3cd7cc47 (patch)
tree75ba05936bb13d6531b2ada7793a0d2b377c249a /drivers/gpu/drm/amd
parentc425688520990d6cec769faaa97f4af45d361fd1 (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/Makefile2
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c513
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c536
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h180
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h155
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
36AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) 36AMD_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;
45extern const struct pp_smumgr_func vega10_smu_funcs; 43extern const struct pp_smumgr_func vega10_smu_funcs;
46extern const struct pp_smumgr_func smu10_smu_funcs; 44extern const struct pp_smumgr_func smu10_smu_funcs;
47 45
46extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr);
48extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); 47extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr);
48extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr);
49extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr);
50
49static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr); 51static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr);
50static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr); 52static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr);
51static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr); 53static 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);
54static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr); 56static int topaz_set_asic_special_caps(struct pp_hwmgr *hwmgr);
55static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr); 57static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr);
56 58
57uint8_t convert_to_vid(uint16_t vddc)
58{
59 return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
60}
61
62uint16_t convert_to_vddc(uint8_t vid)
63{
64 return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE);
65}
66
67uint32_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
83static int phm_thermal_l2h_irq(void *private_data, 59static 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 */
439int 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 */
469int 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
484int 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
508int 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
522bool 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
527bool 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
533int 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
577int 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
605int 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
633int 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
657void 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
675int 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
690void 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
701int32_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
718uint8_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
738uint8_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
759uint16_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
772int 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
789int 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 */
822int 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
853uint32_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
863void 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
898void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr) 412void 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
957int 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
976int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) 471int 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
28uint8_t convert_to_vid(uint16_t vddc)
29{
30 return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
31}
32
33uint16_t convert_to_vddc(uint8_t vid)
34{
35 return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE);
36}
37
38uint32_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 */
58int 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 */
88int 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
103int 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
127int 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
141bool 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
146bool 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
152int 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
196int 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
224int 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
252int 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
276void 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
294int 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
309void 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
320int32_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
337uint8_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
357uint8_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
378uint16_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
391int 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
408int 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 */
441int 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
472uint32_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
482void 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
517int 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
26struct pp_atomctrl_voltage_table;
27struct pp_hwmgr;
28struct phm_ppt_v1_voltage_lookup_table;
29
30extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
31 uint32_t index,
32 uint32_t value, uint32_t mask);
33extern 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
39extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr);
40extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr);
41extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr);
42
43extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table);
44extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
45extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
46extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table);
47extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table);
48extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max);
49extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes);
50extern int32_t phm_get_dpm_level_enable_mask_value(void *table);
51extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table,
52 uint32_t voltage);
53extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage);
54extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci);
55extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
56extern 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);
58extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
59extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
60extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
61
62extern 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
65extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size);
66
67extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
68 uint32_t value, uint32_t mask);
69
70extern 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
37struct pp_instance; 37struct pp_instance;
38struct pp_hwmgr; 38struct pp_hwmgr;
@@ -777,160 +777,9 @@ extern int hwmgr_hw_resume(struct pp_instance *handle);
777extern int hwmgr_handle_task(struct pp_instance *handle, 777extern 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);
780extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
781 uint32_t value, uint32_t mask);
782
783extern 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
789extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
790 uint32_t index,
791 uint32_t value, uint32_t mask);
792extern 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
798extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr);
799extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr);
800extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr);
801
802extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table);
803extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
804extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
805extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table);
806extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table);
807extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max);
808extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes);
809extern int32_t phm_get_dpm_level_enable_mask_value(void *table);
810extern uint8_t phm_get_voltage_id(struct pp_atomctrl_voltage_table *voltage_table,
811 uint32_t voltage);
812extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage);
813extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci);
814extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
815extern 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);
817extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
818extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
819extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr);
820
821extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr);
822extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr);
823extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr);
824
825extern 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
828extern 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_ */