diff options
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 252 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/ci_dpm.h | 7 |
2 files changed, 259 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index f97ecb49972e..578878d1d4c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c | |||
@@ -3681,6 +3681,40 @@ static int ci_find_boot_level(struct ci_single_dpm_table *table, | |||
3681 | return ret; | 3681 | return ret; |
3682 | } | 3682 | } |
3683 | 3683 | ||
3684 | static void ci_save_default_power_profile(struct amdgpu_device *adev) | ||
3685 | { | ||
3686 | struct ci_power_info *pi = ci_get_pi(adev); | ||
3687 | struct SMU7_Discrete_GraphicsLevel *levels = | ||
3688 | pi->smc_state_table.GraphicsLevel; | ||
3689 | uint32_t min_level = 0; | ||
3690 | |||
3691 | pi->default_gfx_power_profile.activity_threshold = | ||
3692 | be16_to_cpu(levels[0].ActivityLevel); | ||
3693 | pi->default_gfx_power_profile.up_hyst = levels[0].UpH; | ||
3694 | pi->default_gfx_power_profile.down_hyst = levels[0].DownH; | ||
3695 | pi->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; | ||
3696 | |||
3697 | pi->default_compute_power_profile = pi->default_gfx_power_profile; | ||
3698 | pi->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; | ||
3699 | |||
3700 | /* Optimize compute power profile: Use only highest | ||
3701 | * 2 power levels (if more than 2 are available), Hysteresis: | ||
3702 | * 0ms up, 5ms down | ||
3703 | */ | ||
3704 | if (pi->smc_state_table.GraphicsDpmLevelCount > 2) | ||
3705 | min_level = pi->smc_state_table.GraphicsDpmLevelCount - 2; | ||
3706 | else if (pi->smc_state_table.GraphicsDpmLevelCount == 2) | ||
3707 | min_level = 1; | ||
3708 | pi->default_compute_power_profile.min_sclk = | ||
3709 | be32_to_cpu(levels[min_level].SclkFrequency); | ||
3710 | |||
3711 | pi->default_compute_power_profile.up_hyst = 0; | ||
3712 | pi->default_compute_power_profile.down_hyst = 5; | ||
3713 | |||
3714 | pi->gfx_power_profile = pi->default_gfx_power_profile; | ||
3715 | pi->compute_power_profile = pi->default_compute_power_profile; | ||
3716 | } | ||
3717 | |||
3684 | static int ci_init_smc_table(struct amdgpu_device *adev) | 3718 | static int ci_init_smc_table(struct amdgpu_device *adev) |
3685 | { | 3719 | { |
3686 | struct ci_power_info *pi = ci_get_pi(adev); | 3720 | struct ci_power_info *pi = ci_get_pi(adev); |
@@ -3826,6 +3860,8 @@ static int ci_init_smc_table(struct amdgpu_device *adev) | |||
3826 | if (ret) | 3860 | if (ret) |
3827 | return ret; | 3861 | return ret; |
3828 | 3862 | ||
3863 | ci_save_default_power_profile(adev); | ||
3864 | |||
3829 | return 0; | 3865 | return 0; |
3830 | } | 3866 | } |
3831 | 3867 | ||
@@ -6688,6 +6724,218 @@ static int ci_dpm_set_mclk_od(struct amdgpu_device *adev, uint32_t value) | |||
6688 | return 0; | 6724 | return 0; |
6689 | } | 6725 | } |
6690 | 6726 | ||
6727 | static int ci_dpm_get_power_profile_state(struct amdgpu_device *adev, | ||
6728 | struct amd_pp_profile *query) | ||
6729 | { | ||
6730 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6731 | |||
6732 | if (!pi || !query) | ||
6733 | return -EINVAL; | ||
6734 | |||
6735 | if (query->type == AMD_PP_GFX_PROFILE) | ||
6736 | memcpy(query, &pi->gfx_power_profile, | ||
6737 | sizeof(struct amd_pp_profile)); | ||
6738 | else if (query->type == AMD_PP_COMPUTE_PROFILE) | ||
6739 | memcpy(query, &pi->compute_power_profile, | ||
6740 | sizeof(struct amd_pp_profile)); | ||
6741 | else | ||
6742 | return -EINVAL; | ||
6743 | |||
6744 | return 0; | ||
6745 | } | ||
6746 | |||
6747 | static int ci_populate_requested_graphic_levels(struct amdgpu_device *adev, | ||
6748 | struct amd_pp_profile *request) | ||
6749 | { | ||
6750 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6751 | struct ci_dpm_table *dpm_table = &(pi->dpm_table); | ||
6752 | struct SMU7_Discrete_GraphicsLevel *levels = | ||
6753 | pi->smc_state_table.GraphicsLevel; | ||
6754 | uint32_t array = pi->dpm_table_start + | ||
6755 | offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); | ||
6756 | uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) * | ||
6757 | SMU7_MAX_LEVELS_GRAPHICS; | ||
6758 | uint32_t i; | ||
6759 | |||
6760 | for (i = 0; i < dpm_table->sclk_table.count; i++) { | ||
6761 | levels[i].ActivityLevel = | ||
6762 | cpu_to_be16(request->activity_threshold); | ||
6763 | levels[i].EnabledForActivity = 1; | ||
6764 | levels[i].UpH = request->up_hyst; | ||
6765 | levels[i].DownH = request->down_hyst; | ||
6766 | } | ||
6767 | |||
6768 | return amdgpu_ci_copy_bytes_to_smc(adev, array, (uint8_t *)levels, | ||
6769 | array_size, pi->sram_end); | ||
6770 | } | ||
6771 | |||
6772 | static void ci_find_min_clock_masks(struct amdgpu_device *adev, | ||
6773 | uint32_t *sclk_mask, uint32_t *mclk_mask, | ||
6774 | uint32_t min_sclk, uint32_t min_mclk) | ||
6775 | { | ||
6776 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6777 | struct ci_dpm_table *dpm_table = &(pi->dpm_table); | ||
6778 | uint32_t i; | ||
6779 | |||
6780 | for (i = 0; i < dpm_table->sclk_table.count; i++) { | ||
6781 | if (dpm_table->sclk_table.dpm_levels[i].enabled && | ||
6782 | dpm_table->sclk_table.dpm_levels[i].value >= min_sclk) | ||
6783 | *sclk_mask |= 1 << i; | ||
6784 | } | ||
6785 | |||
6786 | for (i = 0; i < dpm_table->mclk_table.count; i++) { | ||
6787 | if (dpm_table->mclk_table.dpm_levels[i].enabled && | ||
6788 | dpm_table->mclk_table.dpm_levels[i].value >= min_mclk) | ||
6789 | *mclk_mask |= 1 << i; | ||
6790 | } | ||
6791 | } | ||
6792 | |||
6793 | static int ci_set_power_profile_state(struct amdgpu_device *adev, | ||
6794 | struct amd_pp_profile *request) | ||
6795 | { | ||
6796 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6797 | int tmp_result, result = 0; | ||
6798 | uint32_t sclk_mask = 0, mclk_mask = 0; | ||
6799 | |||
6800 | tmp_result = ci_freeze_sclk_mclk_dpm(adev); | ||
6801 | if (tmp_result) { | ||
6802 | DRM_ERROR("Failed to freeze SCLK MCLK DPM!"); | ||
6803 | result = tmp_result; | ||
6804 | } | ||
6805 | |||
6806 | tmp_result = ci_populate_requested_graphic_levels(adev, | ||
6807 | request); | ||
6808 | if (tmp_result) { | ||
6809 | DRM_ERROR("Failed to populate requested graphic levels!"); | ||
6810 | result = tmp_result; | ||
6811 | } | ||
6812 | |||
6813 | tmp_result = ci_unfreeze_sclk_mclk_dpm(adev); | ||
6814 | if (tmp_result) { | ||
6815 | DRM_ERROR("Failed to unfreeze SCLK MCLK DPM!"); | ||
6816 | result = tmp_result; | ||
6817 | } | ||
6818 | |||
6819 | ci_find_min_clock_masks(adev, &sclk_mask, &mclk_mask, | ||
6820 | request->min_sclk, request->min_mclk); | ||
6821 | |||
6822 | if (sclk_mask) { | ||
6823 | if (!pi->sclk_dpm_key_disabled) | ||
6824 | amdgpu_ci_send_msg_to_smc_with_parameter( | ||
6825 | adev, | ||
6826 | PPSMC_MSG_SCLKDPM_SetEnabledMask, | ||
6827 | pi->dpm_level_enable_mask. | ||
6828 | sclk_dpm_enable_mask & | ||
6829 | sclk_mask); | ||
6830 | } | ||
6831 | |||
6832 | if (mclk_mask) { | ||
6833 | if (!pi->mclk_dpm_key_disabled) | ||
6834 | amdgpu_ci_send_msg_to_smc_with_parameter( | ||
6835 | adev, | ||
6836 | PPSMC_MSG_MCLKDPM_SetEnabledMask, | ||
6837 | pi->dpm_level_enable_mask. | ||
6838 | mclk_dpm_enable_mask & | ||
6839 | mclk_mask); | ||
6840 | } | ||
6841 | |||
6842 | |||
6843 | return result; | ||
6844 | } | ||
6845 | |||
6846 | static int ci_dpm_set_power_profile_state(struct amdgpu_device *adev, | ||
6847 | struct amd_pp_profile *request) | ||
6848 | { | ||
6849 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6850 | int ret = -1; | ||
6851 | |||
6852 | if (!pi || !request) | ||
6853 | return -EINVAL; | ||
6854 | |||
6855 | if (adev->pm.dpm.forced_level != | ||
6856 | AMD_DPM_FORCED_LEVEL_AUTO) | ||
6857 | return -EINVAL; | ||
6858 | |||
6859 | if (request->min_sclk || | ||
6860 | request->min_mclk || | ||
6861 | request->activity_threshold || | ||
6862 | request->up_hyst || | ||
6863 | request->down_hyst) { | ||
6864 | if (request->type == AMD_PP_GFX_PROFILE) | ||
6865 | memcpy(&pi->gfx_power_profile, request, | ||
6866 | sizeof(struct amd_pp_profile)); | ||
6867 | else if (request->type == AMD_PP_COMPUTE_PROFILE) | ||
6868 | memcpy(&pi->compute_power_profile, request, | ||
6869 | sizeof(struct amd_pp_profile)); | ||
6870 | else | ||
6871 | return -EINVAL; | ||
6872 | |||
6873 | if (request->type == pi->current_power_profile) | ||
6874 | ret = ci_set_power_profile_state( | ||
6875 | adev, | ||
6876 | request); | ||
6877 | } else { | ||
6878 | /* set power profile if it exists */ | ||
6879 | switch (request->type) { | ||
6880 | case AMD_PP_GFX_PROFILE: | ||
6881 | ret = ci_set_power_profile_state( | ||
6882 | adev, | ||
6883 | &pi->gfx_power_profile); | ||
6884 | break; | ||
6885 | case AMD_PP_COMPUTE_PROFILE: | ||
6886 | ret = ci_set_power_profile_state( | ||
6887 | adev, | ||
6888 | &pi->compute_power_profile); | ||
6889 | break; | ||
6890 | default: | ||
6891 | return -EINVAL; | ||
6892 | } | ||
6893 | } | ||
6894 | |||
6895 | if (!ret) | ||
6896 | pi->current_power_profile = request->type; | ||
6897 | |||
6898 | return 0; | ||
6899 | } | ||
6900 | |||
6901 | static int ci_dpm_reset_power_profile_state(struct amdgpu_device *adev, | ||
6902 | struct amd_pp_profile *request) | ||
6903 | { | ||
6904 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6905 | |||
6906 | if (!pi || !request) | ||
6907 | return -EINVAL; | ||
6908 | |||
6909 | if (request->type == AMD_PP_GFX_PROFILE) { | ||
6910 | pi->gfx_power_profile = pi->default_gfx_power_profile; | ||
6911 | return ci_dpm_set_power_profile_state(adev, | ||
6912 | &pi->gfx_power_profile); | ||
6913 | } else if (request->type == AMD_PP_COMPUTE_PROFILE) { | ||
6914 | pi->compute_power_profile = | ||
6915 | pi->default_compute_power_profile; | ||
6916 | return ci_dpm_set_power_profile_state(adev, | ||
6917 | &pi->compute_power_profile); | ||
6918 | } else | ||
6919 | return -EINVAL; | ||
6920 | } | ||
6921 | |||
6922 | static int ci_dpm_switch_power_profile(struct amdgpu_device *adev, | ||
6923 | enum amd_pp_profile_type type) | ||
6924 | { | ||
6925 | struct ci_power_info *pi = ci_get_pi(adev); | ||
6926 | struct amd_pp_profile request = {0}; | ||
6927 | |||
6928 | if (!pi) | ||
6929 | return -EINVAL; | ||
6930 | |||
6931 | if (pi->current_power_profile != type) { | ||
6932 | request.type = type; | ||
6933 | return ci_dpm_set_power_profile_state(adev, &request); | ||
6934 | } | ||
6935 | |||
6936 | return 0; | ||
6937 | } | ||
6938 | |||
6691 | const struct amd_ip_funcs ci_dpm_ip_funcs = { | 6939 | const struct amd_ip_funcs ci_dpm_ip_funcs = { |
6692 | .name = "ci_dpm", | 6940 | .name = "ci_dpm", |
6693 | .early_init = ci_dpm_early_init, | 6941 | .early_init = ci_dpm_early_init, |
@@ -6730,6 +6978,10 @@ static const struct amdgpu_dpm_funcs ci_dpm_funcs = { | |||
6730 | .set_mclk_od = ci_dpm_set_mclk_od, | 6978 | .set_mclk_od = ci_dpm_set_mclk_od, |
6731 | .check_state_equal = ci_check_state_equal, | 6979 | .check_state_equal = ci_check_state_equal, |
6732 | .get_vce_clock_state = amdgpu_get_vce_clock_state, | 6980 | .get_vce_clock_state = amdgpu_get_vce_clock_state, |
6981 | .get_power_profile_state = ci_dpm_get_power_profile_state, | ||
6982 | .set_power_profile_state = ci_dpm_set_power_profile_state, | ||
6983 | .reset_power_profile_state = ci_dpm_reset_power_profile_state, | ||
6984 | .switch_power_profile = ci_dpm_switch_power_profile, | ||
6733 | }; | 6985 | }; |
6734 | 6986 | ||
6735 | static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev) | 6987 | static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev) |
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h index 91be2996ae7c..84cbc9c45f4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h | |||
@@ -295,6 +295,13 @@ struct ci_power_info { | |||
295 | bool fan_is_controlled_by_smc; | 295 | bool fan_is_controlled_by_smc; |
296 | u32 t_min; | 296 | u32 t_min; |
297 | u32 fan_ctrl_default_mode; | 297 | u32 fan_ctrl_default_mode; |
298 | |||
299 | /* power profile */ | ||
300 | struct amd_pp_profile gfx_power_profile; | ||
301 | struct amd_pp_profile compute_power_profile; | ||
302 | struct amd_pp_profile default_gfx_power_profile; | ||
303 | struct amd_pp_profile default_compute_power_profile; | ||
304 | enum amd_pp_profile_type current_power_profile; | ||
298 | }; | 305 | }; |
299 | 306 | ||
300 | #define CISLANDS_VOLTAGE_CONTROL_NONE 0x0 | 307 | #define CISLANDS_VOLTAGE_CONTROL_NONE 0x0 |