diff options
author | Evan Quan <evan.quan@amd.com> | 2019-01-14 02:44:44 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2019-01-25 16:15:34 -0500 |
commit | 828e37efe802ba8c868922af23099638fde5b7b4 (patch) | |
tree | 6860d47f01d20d92cfe804fe970f0c8b61422177 /drivers/gpu/drm | |
parent | d7337ca2640cde21ff178bd78f01d94cd5ea2e08 (diff) |
drm/amd/powerplay: support retrieving and adjusting fclock power levels V2
User can use "pp_dpm_fclk" to retrieve and adjust fclock power
levels.
V2: expose this interface for Vega20 and later ASICs only
Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 53 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 64 |
3 files changed, 116 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 4bdb1d082bea..23eb6f61da13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -680,13 +680,14 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev, | |||
680 | } | 680 | } |
681 | 681 | ||
682 | /** | 682 | /** |
683 | * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_pcie | 683 | * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_pcie |
684 | * | 684 | * |
685 | * The amdgpu driver provides a sysfs API for adjusting what power levels | 685 | * The amdgpu driver provides a sysfs API for adjusting what power levels |
686 | * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, | 686 | * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, |
687 | * pp_dpm_socclk and pp_dpm_pcie are used for this. | 687 | * pp_dpm_socclk, pp_dpm_fclk and pp_dpm_pcie are used for this. |
688 | * | 688 | * |
689 | * pp_dpm_socclk interface is only available for Vega10 and later ASICs. | 689 | * pp_dpm_socclk interface is only available for Vega10 and later ASICs. |
690 | * pp_dpm_fclk interface is only available for Vega20 and later ASICs. | ||
690 | * | 691 | * |
691 | * Reading back the files will show you the available power levels within | 692 | * Reading back the files will show you the available power levels within |
692 | * the power state and the clock information for those levels. | 693 | * the power state and the clock information for those levels. |
@@ -842,6 +843,42 @@ static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev, | |||
842 | return count; | 843 | return count; |
843 | } | 844 | } |
844 | 845 | ||
846 | static ssize_t amdgpu_get_pp_dpm_fclk(struct device *dev, | ||
847 | struct device_attribute *attr, | ||
848 | char *buf) | ||
849 | { | ||
850 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
851 | struct amdgpu_device *adev = ddev->dev_private; | ||
852 | |||
853 | if (adev->powerplay.pp_funcs->print_clock_levels) | ||
854 | return amdgpu_dpm_print_clock_levels(adev, PP_FCLK, buf); | ||
855 | else | ||
856 | return snprintf(buf, PAGE_SIZE, "\n"); | ||
857 | } | ||
858 | |||
859 | static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev, | ||
860 | struct device_attribute *attr, | ||
861 | const char *buf, | ||
862 | size_t count) | ||
863 | { | ||
864 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
865 | struct amdgpu_device *adev = ddev->dev_private; | ||
866 | int ret; | ||
867 | uint32_t mask = 0; | ||
868 | |||
869 | ret = amdgpu_read_mask(buf, count, &mask); | ||
870 | if (ret) | ||
871 | return ret; | ||
872 | |||
873 | if (adev->powerplay.pp_funcs->force_clock_level) | ||
874 | ret = amdgpu_dpm_force_clock_level(adev, PP_FCLK, mask); | ||
875 | |||
876 | if (ret) | ||
877 | return -EINVAL; | ||
878 | |||
879 | return count; | ||
880 | } | ||
881 | |||
845 | static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, | 882 | static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, |
846 | struct device_attribute *attr, | 883 | struct device_attribute *attr, |
847 | char *buf) | 884 | char *buf) |
@@ -1128,6 +1165,9 @@ static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR, | |||
1128 | static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR, | 1165 | static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR, |
1129 | amdgpu_get_pp_dpm_socclk, | 1166 | amdgpu_get_pp_dpm_socclk, |
1130 | amdgpu_set_pp_dpm_socclk); | 1167 | amdgpu_set_pp_dpm_socclk); |
1168 | static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR, | ||
1169 | amdgpu_get_pp_dpm_fclk, | ||
1170 | amdgpu_set_pp_dpm_fclk); | ||
1131 | static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR, | 1171 | static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR, |
1132 | amdgpu_get_pp_dpm_pcie, | 1172 | amdgpu_get_pp_dpm_pcie, |
1133 | amdgpu_set_pp_dpm_pcie); | 1173 | amdgpu_set_pp_dpm_pcie); |
@@ -2294,6 +2334,13 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) | |||
2294 | return ret; | 2334 | return ret; |
2295 | } | 2335 | } |
2296 | } | 2336 | } |
2337 | if (adev->asic_type >= CHIP_VEGA20) { | ||
2338 | ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk); | ||
2339 | if (ret) { | ||
2340 | DRM_ERROR("failed to create device file pp_dpm_fclk\n"); | ||
2341 | return ret; | ||
2342 | } | ||
2343 | } | ||
2297 | ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie); | 2344 | ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie); |
2298 | if (ret) { | 2345 | if (ret) { |
2299 | DRM_ERROR("failed to create device file pp_dpm_pcie\n"); | 2346 | DRM_ERROR("failed to create device file pp_dpm_pcie\n"); |
@@ -2384,6 +2431,8 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) | |||
2384 | if (adev->asic_type >= CHIP_VEGA10) | 2431 | if (adev->asic_type >= CHIP_VEGA10) |
2385 | device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk); | 2432 | device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk); |
2386 | device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); | 2433 | device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); |
2434 | if (adev->asic_type >= CHIP_VEGA20) | ||
2435 | device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk); | ||
2387 | device_remove_file(adev->dev, &dev_attr_pp_sclk_od); | 2436 | device_remove_file(adev->dev, &dev_attr_pp_sclk_od); |
2388 | device_remove_file(adev->dev, &dev_attr_pp_mclk_od); | 2437 | device_remove_file(adev->dev, &dev_attr_pp_mclk_od); |
2389 | device_remove_file(adev->dev, | 2438 | device_remove_file(adev->dev, |
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index f5ec25a6ab54..f82de14f6560 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h | |||
@@ -93,6 +93,7 @@ enum pp_clock_type { | |||
93 | PP_MCLK, | 93 | PP_MCLK, |
94 | PP_PCIE, | 94 | PP_PCIE, |
95 | PP_SOCCLK, | 95 | PP_SOCCLK, |
96 | PP_FCLK, | ||
96 | OD_SCLK, | 97 | OD_SCLK, |
97 | OD_MCLK, | 98 | OD_MCLK, |
98 | OD_VDDC_CURVE, | 99 | OD_VDDC_CURVE, |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index e7c890f036fa..4e7399c310e2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | |||
@@ -1736,6 +1736,17 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_ | |||
1736 | return ret); | 1736 | return ret); |
1737 | } | 1737 | } |
1738 | 1738 | ||
1739 | if (data->smu_features[GNLD_DPM_FCLK].enabled && | ||
1740 | (feature_mask & FEATURE_DPM_FCLK_MASK)) { | ||
1741 | min_freq = data->dpm_table.fclk_table.dpm_state.soft_min_level; | ||
1742 | |||
1743 | PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( | ||
1744 | hwmgr, PPSMC_MSG_SetSoftMinByFreq, | ||
1745 | (PPCLK_FCLK << 16) | (min_freq & 0xffff))), | ||
1746 | "Failed to set soft min fclk!", | ||
1747 | return ret); | ||
1748 | } | ||
1749 | |||
1739 | return ret; | 1750 | return ret; |
1740 | } | 1751 | } |
1741 | 1752 | ||
@@ -1808,6 +1819,17 @@ static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_ | |||
1808 | return ret); | 1819 | return ret); |
1809 | } | 1820 | } |
1810 | 1821 | ||
1822 | if (data->smu_features[GNLD_DPM_FCLK].enabled && | ||
1823 | (feature_mask & FEATURE_DPM_FCLK_MASK)) { | ||
1824 | max_freq = data->dpm_table.fclk_table.dpm_state.soft_max_level; | ||
1825 | |||
1826 | PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( | ||
1827 | hwmgr, PPSMC_MSG_SetSoftMaxByFreq, | ||
1828 | (PPCLK_FCLK << 16) | (max_freq & 0xffff))), | ||
1829 | "Failed to set soft max fclk!", | ||
1830 | return ret); | ||
1831 | } | ||
1832 | |||
1811 | return ret; | 1833 | return ret; |
1812 | } | 1834 | } |
1813 | 1835 | ||
@@ -2324,6 +2346,34 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, | |||
2324 | 2346 | ||
2325 | break; | 2347 | break; |
2326 | 2348 | ||
2349 | case PP_FCLK: | ||
2350 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | ||
2351 | soft_max_level = mask ? (fls(mask) - 1) : 0; | ||
2352 | |||
2353 | if (soft_max_level >= data->dpm_table.fclk_table.count) { | ||
2354 | pr_err("Clock level specified %d is over max allowed %d\n", | ||
2355 | soft_max_level, | ||
2356 | data->dpm_table.fclk_table.count - 1); | ||
2357 | return -EINVAL; | ||
2358 | } | ||
2359 | |||
2360 | data->dpm_table.fclk_table.dpm_state.soft_min_level = | ||
2361 | data->dpm_table.fclk_table.dpm_levels[soft_min_level].value; | ||
2362 | data->dpm_table.fclk_table.dpm_state.soft_max_level = | ||
2363 | data->dpm_table.fclk_table.dpm_levels[soft_max_level].value; | ||
2364 | |||
2365 | ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_FCLK_MASK); | ||
2366 | PP_ASSERT_WITH_CODE(!ret, | ||
2367 | "Failed to upload boot level to lowest!", | ||
2368 | return ret); | ||
2369 | |||
2370 | ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_FCLK_MASK); | ||
2371 | PP_ASSERT_WITH_CODE(!ret, | ||
2372 | "Failed to upload dpm max level to highest!", | ||
2373 | return ret); | ||
2374 | |||
2375 | break; | ||
2376 | |||
2327 | case PP_PCIE: | 2377 | case PP_PCIE: |
2328 | soft_min_level = mask ? (ffs(mask) - 1) : 0; | 2378 | soft_min_level = mask ? (ffs(mask) - 1) : 0; |
2329 | soft_max_level = mask ? (fls(mask) - 1) : 0; | 2379 | soft_max_level = mask ? (fls(mask) - 1) : 0; |
@@ -2920,6 +2970,8 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, | |||
2920 | PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable; | 2970 | PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable; |
2921 | struct amdgpu_device *adev = hwmgr->adev; | 2971 | struct amdgpu_device *adev = hwmgr->adev; |
2922 | struct pp_clock_levels_with_latency clocks; | 2972 | struct pp_clock_levels_with_latency clocks; |
2973 | struct vega20_single_dpm_table *fclk_dpm_table = | ||
2974 | &(data->dpm_table.fclk_table); | ||
2923 | int i, now, size = 0; | 2975 | int i, now, size = 0; |
2924 | int ret = 0; | 2976 | int ret = 0; |
2925 | uint32_t gen_speed, lane_width; | 2977 | uint32_t gen_speed, lane_width; |
@@ -2976,6 +3028,18 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, | |||
2976 | (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); | 3028 | (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); |
2977 | break; | 3029 | break; |
2978 | 3030 | ||
3031 | case PP_FCLK: | ||
3032 | ret = vega20_get_current_clk_freq(hwmgr, PPCLK_FCLK, &now); | ||
3033 | PP_ASSERT_WITH_CODE(!ret, | ||
3034 | "Attempt to get current fclk freq Failed!", | ||
3035 | return ret); | ||
3036 | |||
3037 | for (i = 0; i < fclk_dpm_table->count; i++) | ||
3038 | size += sprintf(buf + size, "%d: %uMhz %s\n", | ||
3039 | i, fclk_dpm_table->dpm_levels[i].value, | ||
3040 | fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : ""); | ||
3041 | break; | ||
3042 | |||
2979 | case PP_PCIE: | 3043 | case PP_PCIE: |
2980 | gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & | 3044 | gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & |
2981 | PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) | 3045 | PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) |