drm/amd/amdgpu: add power profile sysfs entry
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_pm.c
index 346e80a..fd45212 100644 (file)
@@ -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)