mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-05-02 18:17:50 -04:00
drm/amd/powerplay: support retrieving and adjusting dcefclock power levels V2
User can use "pp_dpm_dcefclk" to retrieve and adjust dcefclock power levels. V2: expose this interface for Vega10 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>
This commit is contained in:
@@ -680,13 +680,16 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_pcie
|
* DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk
|
||||||
|
* pp_dpm_pcie
|
||||||
*
|
*
|
||||||
* The amdgpu driver provides a sysfs API for adjusting what power levels
|
* The amdgpu driver provides a sysfs API for adjusting what power levels
|
||||||
* are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk,
|
* are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk,
|
||||||
* pp_dpm_socclk, pp_dpm_fclk and pp_dpm_pcie are used for this.
|
* pp_dpm_socclk, pp_dpm_fclk, pp_dpm_dcefclk and pp_dpm_pcie are used for
|
||||||
|
* this.
|
||||||
*
|
*
|
||||||
* pp_dpm_socclk interface is only available for Vega10 and later ASICs.
|
* pp_dpm_socclk and pp_dpm_dcefclk interfaces are only available for
|
||||||
|
* Vega10 and later ASICs.
|
||||||
* pp_dpm_fclk interface is only available for Vega20 and later ASICs.
|
* pp_dpm_fclk interface is only available for Vega20 and later ASICs.
|
||||||
*
|
*
|
||||||
* Reading back the files will show you the available power levels within
|
* Reading back the files will show you the available power levels within
|
||||||
@@ -697,6 +700,8 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev,
|
|||||||
* Secondly,Enter a new value for each level by inputing a string that
|
* Secondly,Enter a new value for each level by inputing a string that
|
||||||
* contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie"
|
* contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie"
|
||||||
* E.g., echo 4 5 6 to > pp_dpm_sclk will enable sclk levels 4, 5, and 6.
|
* E.g., echo 4 5 6 to > pp_dpm_sclk will enable sclk levels 4, 5, and 6.
|
||||||
|
*
|
||||||
|
* NOTE: change to the dcefclk max dpm level is not supported now
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
|
static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
|
||||||
@@ -879,6 +884,42 @@ static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||||
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
|
|
||||||
|
if (adev->powerplay.pp_funcs->print_clock_levels)
|
||||||
|
return amdgpu_dpm_print_clock_levels(adev, PP_DCEFCLK, buf);
|
||||||
|
else
|
||||||
|
return snprintf(buf, PAGE_SIZE, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t amdgpu_set_pp_dpm_dcefclk(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||||
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
|
int ret;
|
||||||
|
uint32_t mask = 0;
|
||||||
|
|
||||||
|
ret = amdgpu_read_mask(buf, count, &mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (adev->powerplay.pp_funcs->force_clock_level)
|
||||||
|
ret = amdgpu_dpm_force_clock_level(adev, PP_DCEFCLK, mask);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev,
|
static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
@@ -1168,6 +1209,9 @@ static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR,
|
|||||||
static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR,
|
static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR,
|
||||||
amdgpu_get_pp_dpm_fclk,
|
amdgpu_get_pp_dpm_fclk,
|
||||||
amdgpu_set_pp_dpm_fclk);
|
amdgpu_set_pp_dpm_fclk);
|
||||||
|
static DEVICE_ATTR(pp_dpm_dcefclk, S_IRUGO | S_IWUSR,
|
||||||
|
amdgpu_get_pp_dpm_dcefclk,
|
||||||
|
amdgpu_set_pp_dpm_dcefclk);
|
||||||
static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR,
|
static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR,
|
||||||
amdgpu_get_pp_dpm_pcie,
|
amdgpu_get_pp_dpm_pcie,
|
||||||
amdgpu_set_pp_dpm_pcie);
|
amdgpu_set_pp_dpm_pcie);
|
||||||
@@ -2333,6 +2377,11 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
|
|||||||
DRM_ERROR("failed to create device file pp_dpm_socclk\n");
|
DRM_ERROR("failed to create device file pp_dpm_socclk\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
ret = device_create_file(adev->dev, &dev_attr_pp_dpm_dcefclk);
|
||||||
|
if (ret) {
|
||||||
|
DRM_ERROR("failed to create device file pp_dpm_dcefclk\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (adev->asic_type >= CHIP_VEGA20) {
|
if (adev->asic_type >= CHIP_VEGA20) {
|
||||||
ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk);
|
ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk);
|
||||||
@@ -2428,8 +2477,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
|
|||||||
|
|
||||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk);
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk);
|
||||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk);
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk);
|
||||||
if (adev->asic_type >= CHIP_VEGA10)
|
if (adev->asic_type >= CHIP_VEGA10) {
|
||||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk);
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk);
|
||||||
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_dcefclk);
|
||||||
|
}
|
||||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
|
||||||
if (adev->asic_type >= CHIP_VEGA20)
|
if (adev->asic_type >= CHIP_VEGA20)
|
||||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk);
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk);
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ enum pp_clock_type {
|
|||||||
PP_PCIE,
|
PP_PCIE,
|
||||||
PP_SOCCLK,
|
PP_SOCCLK,
|
||||||
PP_FCLK,
|
PP_FCLK,
|
||||||
|
PP_DCEFCLK,
|
||||||
OD_SCLK,
|
OD_SCLK,
|
||||||
OD_MCLK,
|
OD_MCLK,
|
||||||
OD_VDDC_CURVE,
|
OD_VDDC_CURVE,
|
||||||
|
|||||||
@@ -1747,6 +1747,17 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_
|
|||||||
return ret);
|
return ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->smu_features[GNLD_DPM_DCEFCLK].enabled &&
|
||||||
|
(feature_mask & FEATURE_DPM_DCEFCLK_MASK)) {
|
||||||
|
min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level;
|
||||||
|
|
||||||
|
PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(
|
||||||
|
hwmgr, PPSMC_MSG_SetHardMinByFreq,
|
||||||
|
(PPCLK_DCEFCLK << 16) | (min_freq & 0xffff))),
|
||||||
|
"Failed to set hard min dcefclk!",
|
||||||
|
return ret);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2259,7 +2270,7 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
|
|||||||
enum pp_clock_type type, uint32_t mask)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
|
struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
|
||||||
uint32_t soft_min_level, soft_max_level;
|
uint32_t soft_min_level, soft_max_level, hard_min_level;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -2374,6 +2385,28 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PP_DCEFCLK:
|
||||||
|
hard_min_level = mask ? (ffs(mask) - 1) : 0;
|
||||||
|
|
||||||
|
if (hard_min_level >= data->dpm_table.dcef_table.count) {
|
||||||
|
pr_err("Clock level specified %d is over max allowed %d\n",
|
||||||
|
hard_min_level,
|
||||||
|
data->dpm_table.dcef_table.count - 1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->dpm_table.dcef_table.dpm_state.hard_min_level =
|
||||||
|
data->dpm_table.dcef_table.dpm_levels[hard_min_level].value;
|
||||||
|
|
||||||
|
ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_DCEFCLK_MASK);
|
||||||
|
PP_ASSERT_WITH_CODE(!ret,
|
||||||
|
"Failed to upload boot level to lowest!",
|
||||||
|
return ret);
|
||||||
|
|
||||||
|
//TODO: Setting DCEFCLK max dpm level is not supported
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case PP_PCIE:
|
case PP_PCIE:
|
||||||
soft_min_level = mask ? (ffs(mask) - 1) : 0;
|
soft_min_level = mask ? (ffs(mask) - 1) : 0;
|
||||||
soft_max_level = mask ? (fls(mask) - 1) : 0;
|
soft_max_level = mask ? (fls(mask) - 1) : 0;
|
||||||
@@ -3040,6 +3073,23 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
|
|||||||
fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
|
fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PP_DCEFCLK:
|
||||||
|
ret = vega20_get_current_clk_freq(hwmgr, PPCLK_DCEFCLK, &now);
|
||||||
|
PP_ASSERT_WITH_CODE(!ret,
|
||||||
|
"Attempt to get current dcefclk freq Failed!",
|
||||||
|
return ret);
|
||||||
|
|
||||||
|
ret = vega20_get_dcefclocks(hwmgr, &clocks);
|
||||||
|
PP_ASSERT_WITH_CODE(!ret,
|
||||||
|
"Attempt to get dcefclk levels Failed!",
|
||||||
|
return ret);
|
||||||
|
|
||||||
|
for (i = 0; i < clocks.num_levels; i++)
|
||||||
|
size += sprintf(buf + size, "%d: %uMhz %s\n",
|
||||||
|
i, clocks.data[i].clocks_in_khz / 1000,
|
||||||
|
(clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
|
||||||
|
break;
|
||||||
|
|
||||||
case PP_PCIE:
|
case PP_PCIE:
|
||||||
gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
|
gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
|
||||||
PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
|
PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
|
||||||
|
|||||||
Reference in New Issue
Block a user