Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/amdgpu: add power profile support for CI

Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com>
Acked-by: Rex Zhu <Rex.Zhu@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Eric Huang and committed by
Alex Deucher
618c0483 03609ebc

+259
+252
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
··· 3681 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 3718 static int ci_init_smc_table(struct amdgpu_device *adev) 3685 3719 { 3686 3720 struct ci_power_info *pi = ci_get_pi(adev); ··· 3859 3825 pi->sram_end); 3860 3826 if (ret) 3861 3827 return ret; 3828 + 3829 + ci_save_default_power_profile(adev); 3862 3830 3863 3831 return 0; 3864 3832 } ··· 6724 6688 return 0; 6725 6689 } 6726 6690 6691 + static int ci_dpm_get_power_profile_state(struct amdgpu_device *adev, 6692 + struct amd_pp_profile *query) 6693 + { 6694 + struct ci_power_info *pi = ci_get_pi(adev); 6695 + 6696 + if (!pi || !query) 6697 + return -EINVAL; 6698 + 6699 + if (query->type == AMD_PP_GFX_PROFILE) 6700 + memcpy(query, &pi->gfx_power_profile, 6701 + sizeof(struct amd_pp_profile)); 6702 + else if (query->type == AMD_PP_COMPUTE_PROFILE) 6703 + memcpy(query, &pi->compute_power_profile, 6704 + sizeof(struct amd_pp_profile)); 6705 + else 6706 + return -EINVAL; 6707 + 6708 + return 0; 6709 + } 6710 + 6711 + static int ci_populate_requested_graphic_levels(struct amdgpu_device *adev, 6712 + struct amd_pp_profile *request) 6713 + { 6714 + struct ci_power_info *pi = ci_get_pi(adev); 6715 + struct ci_dpm_table *dpm_table = &(pi->dpm_table); 6716 + struct SMU7_Discrete_GraphicsLevel *levels = 6717 + pi->smc_state_table.GraphicsLevel; 6718 + uint32_t array = pi->dpm_table_start + 6719 + offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); 6720 + uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) * 6721 + SMU7_MAX_LEVELS_GRAPHICS; 6722 + uint32_t i; 6723 + 6724 + for (i = 0; i < dpm_table->sclk_table.count; i++) { 6725 + levels[i].ActivityLevel = 6726 + cpu_to_be16(request->activity_threshold); 6727 + levels[i].EnabledForActivity = 1; 6728 + levels[i].UpH = request->up_hyst; 6729 + levels[i].DownH = request->down_hyst; 6730 + } 6731 + 6732 + return amdgpu_ci_copy_bytes_to_smc(adev, array, (uint8_t *)levels, 6733 + array_size, pi->sram_end); 6734 + } 6735 + 6736 + static void ci_find_min_clock_masks(struct amdgpu_device *adev, 6737 + uint32_t *sclk_mask, uint32_t *mclk_mask, 6738 + uint32_t min_sclk, uint32_t min_mclk) 6739 + { 6740 + struct ci_power_info *pi = ci_get_pi(adev); 6741 + struct ci_dpm_table *dpm_table = &(pi->dpm_table); 6742 + uint32_t i; 6743 + 6744 + for (i = 0; i < dpm_table->sclk_table.count; i++) { 6745 + if (dpm_table->sclk_table.dpm_levels[i].enabled && 6746 + dpm_table->sclk_table.dpm_levels[i].value >= min_sclk) 6747 + *sclk_mask |= 1 << i; 6748 + } 6749 + 6750 + for (i = 0; i < dpm_table->mclk_table.count; i++) { 6751 + if (dpm_table->mclk_table.dpm_levels[i].enabled && 6752 + dpm_table->mclk_table.dpm_levels[i].value >= min_mclk) 6753 + *mclk_mask |= 1 << i; 6754 + } 6755 + } 6756 + 6757 + static int ci_set_power_profile_state(struct amdgpu_device *adev, 6758 + struct amd_pp_profile *request) 6759 + { 6760 + struct ci_power_info *pi = ci_get_pi(adev); 6761 + int tmp_result, result = 0; 6762 + uint32_t sclk_mask = 0, mclk_mask = 0; 6763 + 6764 + tmp_result = ci_freeze_sclk_mclk_dpm(adev); 6765 + if (tmp_result) { 6766 + DRM_ERROR("Failed to freeze SCLK MCLK DPM!"); 6767 + result = tmp_result; 6768 + } 6769 + 6770 + tmp_result = ci_populate_requested_graphic_levels(adev, 6771 + request); 6772 + if (tmp_result) { 6773 + DRM_ERROR("Failed to populate requested graphic levels!"); 6774 + result = tmp_result; 6775 + } 6776 + 6777 + tmp_result = ci_unfreeze_sclk_mclk_dpm(adev); 6778 + if (tmp_result) { 6779 + DRM_ERROR("Failed to unfreeze SCLK MCLK DPM!"); 6780 + result = tmp_result; 6781 + } 6782 + 6783 + ci_find_min_clock_masks(adev, &sclk_mask, &mclk_mask, 6784 + request->min_sclk, request->min_mclk); 6785 + 6786 + if (sclk_mask) { 6787 + if (!pi->sclk_dpm_key_disabled) 6788 + amdgpu_ci_send_msg_to_smc_with_parameter( 6789 + adev, 6790 + PPSMC_MSG_SCLKDPM_SetEnabledMask, 6791 + pi->dpm_level_enable_mask. 6792 + sclk_dpm_enable_mask & 6793 + sclk_mask); 6794 + } 6795 + 6796 + if (mclk_mask) { 6797 + if (!pi->mclk_dpm_key_disabled) 6798 + amdgpu_ci_send_msg_to_smc_with_parameter( 6799 + adev, 6800 + PPSMC_MSG_MCLKDPM_SetEnabledMask, 6801 + pi->dpm_level_enable_mask. 6802 + mclk_dpm_enable_mask & 6803 + mclk_mask); 6804 + } 6805 + 6806 + 6807 + return result; 6808 + } 6809 + 6810 + static int ci_dpm_set_power_profile_state(struct amdgpu_device *adev, 6811 + struct amd_pp_profile *request) 6812 + { 6813 + struct ci_power_info *pi = ci_get_pi(adev); 6814 + int ret = -1; 6815 + 6816 + if (!pi || !request) 6817 + return -EINVAL; 6818 + 6819 + if (adev->pm.dpm.forced_level != 6820 + AMD_DPM_FORCED_LEVEL_AUTO) 6821 + return -EINVAL; 6822 + 6823 + if (request->min_sclk || 6824 + request->min_mclk || 6825 + request->activity_threshold || 6826 + request->up_hyst || 6827 + request->down_hyst) { 6828 + if (request->type == AMD_PP_GFX_PROFILE) 6829 + memcpy(&pi->gfx_power_profile, request, 6830 + sizeof(struct amd_pp_profile)); 6831 + else if (request->type == AMD_PP_COMPUTE_PROFILE) 6832 + memcpy(&pi->compute_power_profile, request, 6833 + sizeof(struct amd_pp_profile)); 6834 + else 6835 + return -EINVAL; 6836 + 6837 + if (request->type == pi->current_power_profile) 6838 + ret = ci_set_power_profile_state( 6839 + adev, 6840 + request); 6841 + } else { 6842 + /* set power profile if it exists */ 6843 + switch (request->type) { 6844 + case AMD_PP_GFX_PROFILE: 6845 + ret = ci_set_power_profile_state( 6846 + adev, 6847 + &pi->gfx_power_profile); 6848 + break; 6849 + case AMD_PP_COMPUTE_PROFILE: 6850 + ret = ci_set_power_profile_state( 6851 + adev, 6852 + &pi->compute_power_profile); 6853 + break; 6854 + default: 6855 + return -EINVAL; 6856 + } 6857 + } 6858 + 6859 + if (!ret) 6860 + pi->current_power_profile = request->type; 6861 + 6862 + return 0; 6863 + } 6864 + 6865 + static int ci_dpm_reset_power_profile_state(struct amdgpu_device *adev, 6866 + struct amd_pp_profile *request) 6867 + { 6868 + struct ci_power_info *pi = ci_get_pi(adev); 6869 + 6870 + if (!pi || !request) 6871 + return -EINVAL; 6872 + 6873 + if (request->type == AMD_PP_GFX_PROFILE) { 6874 + pi->gfx_power_profile = pi->default_gfx_power_profile; 6875 + return ci_dpm_set_power_profile_state(adev, 6876 + &pi->gfx_power_profile); 6877 + } else if (request->type == AMD_PP_COMPUTE_PROFILE) { 6878 + pi->compute_power_profile = 6879 + pi->default_compute_power_profile; 6880 + return ci_dpm_set_power_profile_state(adev, 6881 + &pi->compute_power_profile); 6882 + } else 6883 + return -EINVAL; 6884 + } 6885 + 6886 + static int ci_dpm_switch_power_profile(struct amdgpu_device *adev, 6887 + enum amd_pp_profile_type type) 6888 + { 6889 + struct ci_power_info *pi = ci_get_pi(adev); 6890 + struct amd_pp_profile request = {0}; 6891 + 6892 + if (!pi) 6893 + return -EINVAL; 6894 + 6895 + if (pi->current_power_profile != type) { 6896 + request.type = type; 6897 + return ci_dpm_set_power_profile_state(adev, &request); 6898 + } 6899 + 6900 + return 0; 6901 + } 6902 + 6727 6903 const struct amd_ip_funcs ci_dpm_ip_funcs = { 6728 6904 .name = "ci_dpm", 6729 6905 .early_init = ci_dpm_early_init, ··· 6978 6730 .set_mclk_od = ci_dpm_set_mclk_od, 6979 6731 .check_state_equal = ci_check_state_equal, 6980 6732 .get_vce_clock_state = amdgpu_get_vce_clock_state, 6733 + .get_power_profile_state = ci_dpm_get_power_profile_state, 6734 + .set_power_profile_state = ci_dpm_set_power_profile_state, 6735 + .reset_power_profile_state = ci_dpm_reset_power_profile_state, 6736 + .switch_power_profile = ci_dpm_switch_power_profile, 6981 6737 }; 6982 6738 6983 6739 static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev)
+7
drivers/gpu/drm/amd/amdgpu/ci_dpm.h
··· 295 295 bool fan_is_controlled_by_smc; 296 296 u32 t_min; 297 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 307 #define CISLANDS_VOLTAGE_CONTROL_NONE 0x0