diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 346e80a7119b..fd45212c4b98 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -610,6 +610,174 @@ fail: return count; } +static ssize_t amdgpu_get_pp_power_profile(struct device *dev, + char *buf, struct amd_pp_profile *query) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret = 0; + + if (adev->pp_enabled) + ret = amdgpu_dpm_get_power_profile_state( + adev, query); + else if (adev->pm.funcs->get_power_profile_state) + ret = adev->pm.funcs->get_power_profile_state( + adev, query); + + if (ret) + return ret; + + return snprintf(buf, PAGE_SIZE, + "%d %d %d %d %d\n", + query->min_sclk / 100, + query->min_mclk / 100, + query->activity_threshold, + query->up_hyst, + query->down_hyst); +} + +static ssize_t amdgpu_get_pp_gfx_power_profile(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amd_pp_profile query = {0}; + + query.type = AMD_PP_GFX_PROFILE; + + return amdgpu_get_pp_power_profile(dev, buf, &query); +} + +static ssize_t amdgpu_get_pp_compute_power_profile(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amd_pp_profile query = {0}; + + query.type = AMD_PP_COMPUTE_PROFILE; + + return amdgpu_get_pp_power_profile(dev, buf, &query); +} + +static ssize_t amdgpu_set_pp_power_profile(struct device *dev, + const char *buf, + size_t count, + struct amd_pp_profile *request) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + uint32_t loop = 0; + char *sub_str, buf_cpy[128], *tmp_str; + const char delimiter[3] = {' ', '\n', '\0'}; + long int value; + int ret = 0; + + if (strncmp("reset", buf, strlen("reset")) == 0) { + if (adev->pp_enabled) + ret = amdgpu_dpm_reset_power_profile_state( + adev, request); + else if (adev->pm.funcs->reset_power_profile_state) + ret = adev->pm.funcs->reset_power_profile_state( + adev, request); + if (ret) { + count = -EINVAL; + goto fail; + } + return count; + } + + if (strncmp("set", buf, strlen("set")) == 0) { + if (adev->pp_enabled) + ret = amdgpu_dpm_set_power_profile_state( + adev, request); + else if (adev->pm.funcs->set_power_profile_state) + ret = adev->pm.funcs->set_power_profile_state( + adev, request); + if (ret) { + count = -EINVAL; + goto fail; + } + return count; + } + + if (count + 1 >= 128) { + count = -EINVAL; + goto fail; + } + + memcpy(buf_cpy, buf, count + 1); + tmp_str = buf_cpy; + + while (tmp_str[0]) { + sub_str = strsep(&tmp_str, delimiter); + ret = kstrtol(sub_str, 0, &value); + if (ret) { + count = -EINVAL; + goto fail; + } + + switch (loop) { + case 0: + /* input unit MHz convert to dpm table unit 10KHz*/ + request->min_sclk = (uint32_t)value * 100; + break; + case 1: + /* input unit MHz convert to dpm table unit 10KHz*/ + request->min_mclk = (uint32_t)value * 100; + break; + case 2: + request->activity_threshold = (uint16_t)value; + break; + case 3: + request->up_hyst = (uint8_t)value; + break; + case 4: + request->down_hyst = (uint8_t)value; + break; + default: + break; + } + + loop++; + } + + if (adev->pp_enabled) + ret = amdgpu_dpm_set_power_profile_state( + adev, request); + else if (adev->pm.funcs->set_power_profile_state) + ret = adev->pm.funcs->set_power_profile_state( + adev, request); + + if (ret) + count = -EINVAL; + +fail: + return count; +} + +static ssize_t amdgpu_set_pp_gfx_power_profile(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct amd_pp_profile request = {0}; + + request.type = AMD_PP_GFX_PROFILE; + + return amdgpu_set_pp_power_profile(dev, buf, count, &request); +} + +static ssize_t amdgpu_set_pp_compute_power_profile(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct amd_pp_profile request = {0}; + + request.type = AMD_PP_COMPUTE_PROFILE; + + return amdgpu_set_pp_power_profile(dev, buf, count, &request); +} + static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state); static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, amdgpu_get_dpm_forced_performance_level, @@ -637,6 +805,12 @@ static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_mclk_od, S_IRUGO | S_IWUSR, amdgpu_get_pp_mclk_od, amdgpu_set_pp_mclk_od); +static DEVICE_ATTR(pp_gfx_power_profile, S_IRUGO | S_IWUSR, + amdgpu_get_pp_gfx_power_profile, + amdgpu_set_pp_gfx_power_profile); +static DEVICE_ATTR(pp_compute_power_profile, S_IRUGO | S_IWUSR, + amdgpu_get_pp_compute_power_profile, + amdgpu_set_pp_compute_power_profile); static ssize_t amdgpu_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -1255,6 +1429,20 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) DRM_ERROR("failed to create device file pp_mclk_od\n"); return ret; } + ret = device_create_file(adev->dev, + &dev_attr_pp_gfx_power_profile); + if (ret) { + DRM_ERROR("failed to create device file " + "pp_gfx_power_profile\n"); + return ret; + } + ret = device_create_file(adev->dev, + &dev_attr_pp_compute_power_profile); + if (ret) { + DRM_ERROR("failed to create device file " + "pp_compute_power_profile\n"); + return ret; + } ret = amdgpu_debugfs_pm_init(adev); if (ret) { @@ -1284,6 +1472,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); device_remove_file(adev->dev, &dev_attr_pp_sclk_od); device_remove_file(adev->dev, &dev_attr_pp_mclk_od); + device_remove_file(adev->dev, + &dev_attr_pp_gfx_power_profile); + device_remove_file(adev->dev, + &dev_attr_pp_compute_power_profile); } void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) |