]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
drm/amd/powerplay: add some sysfs interfaces for powerplay.
authorEric Huang <JinHuiEric.Huang@amd.com>
Fri, 11 Dec 2015 21:24:34 +0000 (16:24 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 10 Feb 2016 19:16:59 +0000 (14:16 -0500)
The new sysfs interfaces:
pp_num_states: Read-only, return the number of all pp states, 0 if powerplay is not available.
pp_cur_state: Read-only, return the index number of current pp state.
pp_force_state: Read-write, to write a power state index will switch to selected state forcedly and
enable forced state mode, disable forced state mode. such as "echo >...".
pp_table: Read-write, binary output, to be used to read or write the dpm table, the maximum
file size is 4KB of page size.
pp_dpm_sclk: Read-write, reading will return a dpm levels list, to write an index number will force
powerplay to set the corresponding dpm level.
pp_dpm_mclk: same as sclk.
pp_dpm_pcie: same as sclk.

And add new setting "manual" to the existing interface power_dpm_force_performance_level.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
drivers/gpu/drm/amd/powerplay/inc/hwmgr.h

index 41c725e02f3924bf1f70519e7d454e05ab9b6e9c..532e0a17dd9a24b769bbda7a673ab573688a7413 100644 (file)
@@ -1503,6 +1503,7 @@ enum amdgpu_dpm_forced_level {
        AMDGPU_DPM_FORCED_LEVEL_AUTO = 0,
        AMDGPU_DPM_FORCED_LEVEL_LOW = 1,
        AMDGPU_DPM_FORCED_LEVEL_HIGH = 2,
+       AMDGPU_DPM_FORCED_LEVEL_MANUAL = 3,
 };
 
 struct amdgpu_vce_state {
@@ -2014,6 +2015,7 @@ struct amdgpu_device {
        /* powerplay */
        struct amd_powerplay            powerplay;
        bool                            pp_enabled;
+       bool                            pp_force_state_enabled;
 
        /* dpm */
        struct amdgpu_pm                pm;
@@ -2301,6 +2303,21 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
 #define amdgpu_dpm_get_performance_level(adev) \
        (adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle)
 
+#define amdgpu_dpm_get_pp_num_states(adev, data) \
+       (adev)->powerplay.pp_funcs->get_pp_num_states((adev)->powerplay.pp_handle, data)
+
+#define amdgpu_dpm_get_pp_table(adev, table) \
+       (adev)->powerplay.pp_funcs->get_pp_table((adev)->powerplay.pp_handle, table)
+
+#define amdgpu_dpm_set_pp_table(adev, buf, size) \
+       (adev)->powerplay.pp_funcs->set_pp_table((adev)->powerplay.pp_handle, buf, size)
+
+#define amdgpu_dpm_print_clock_levels(adev, type, buf) \
+       (adev)->powerplay.pp_funcs->print_clock_levels((adev)->powerplay.pp_handle, type, buf)
+
+#define amdgpu_dpm_force_clock_level(adev, type, level) \
+               (adev)->powerplay.pp_funcs->force_clock_level((adev)->powerplay.pp_handle, type, level)
+
 #define amdgpu_dpm_dispatch_task(adev, event_id, input, output)                \
        (adev)->powerplay.pp_funcs->dispatch_tasks((adev)->powerplay.pp_handle, (event_id), (input), (output))
 
index a0da563c8c82f8a3f9ba025514d99019af992e2f..d77b2bdbe800eeb633200d4a4639f0e70dc31c08 100644 (file)
@@ -119,7 +119,9 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
                level = amdgpu_dpm_get_performance_level(adev);
                return snprintf(buf, PAGE_SIZE, "%s\n",
                                (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
-                               (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+                               (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
+                               (level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
+                               (level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" : "unknown");
        } else {
                enum amdgpu_dpm_forced_level level;
 
@@ -146,6 +148,8 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
                level = AMDGPU_DPM_FORCED_LEVEL_HIGH;
        } else if (strncmp("auto", buf, strlen("auto")) == 0) {
                level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+       } else if (strncmp("manual", buf, strlen("manual")) == 0) {
+               level = AMDGPU_DPM_FORCED_LEVEL_MANUAL;
        } else {
                count = -EINVAL;
                goto fail;
@@ -172,10 +176,293 @@ fail:
        return count;
 }
 
+static ssize_t amdgpu_get_pp_num_states(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       struct pp_states_info data;
+       int i, buf_len;
+
+       if (adev->pp_enabled)
+               amdgpu_dpm_get_pp_num_states(adev, &data);
+
+       buf_len = snprintf(buf, PAGE_SIZE, "states: %d\n", data.nums);
+       for (i = 0; i < data.nums; i++)
+               buf_len += snprintf(buf + buf_len, PAGE_SIZE, "%d %s\n", i,
+                               (data.states[i] == POWER_STATE_TYPE_INTERNAL_BOOT) ? "boot" :
+                               (data.states[i] == POWER_STATE_TYPE_BATTERY) ? "battery" :
+                               (data.states[i] == POWER_STATE_TYPE_BALANCED) ? "balanced" :
+                               (data.states[i] == POWER_STATE_TYPE_PERFORMANCE) ? "performance" : "default");
+
+       return buf_len;
+}
+
+static ssize_t amdgpu_get_pp_cur_state(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       struct pp_states_info data;
+       enum amd_pm_state_type pm = 0;
+       int i = 0;
+
+       if (adev->pp_enabled) {
+
+               pm = amdgpu_dpm_get_current_power_state(adev);
+               amdgpu_dpm_get_pp_num_states(adev, &data);
+
+               for (i = 0; i < data.nums; i++) {
+                       if (pm == data.states[i])
+                               break;
+               }
+
+               if (i == data.nums)
+                       i = -EINVAL;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", i);
+}
+
+static ssize_t amdgpu_get_pp_force_state(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       struct pp_states_info data;
+       enum amd_pm_state_type pm = 0;
+       int i;
+
+       if (adev->pp_force_state_enabled && adev->pp_enabled) {
+               pm = amdgpu_dpm_get_current_power_state(adev);
+               amdgpu_dpm_get_pp_num_states(adev, &data);
+
+               for (i = 0; i < data.nums; i++) {
+                       if (pm == data.states[i])
+                               break;
+               }
+
+               if (i == data.nums)
+                       i = -EINVAL;
+
+               return snprintf(buf, PAGE_SIZE, "%d\n", i);
+
+       } else
+               return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static ssize_t amdgpu_set_pp_force_state(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;
+       enum amd_pm_state_type state = 0;
+       long idx;
+       int ret;
+
+       if (strlen(buf) == 1)
+               adev->pp_force_state_enabled = false;
+       else {
+               ret = kstrtol(buf, 0, &idx);
+
+               if (ret) {
+                       count = -EINVAL;
+                       goto fail;
+               }
+
+               if (adev->pp_enabled) {
+                       struct pp_states_info data;
+                       amdgpu_dpm_get_pp_num_states(adev, &data);
+                       state = data.states[idx];
+                       /* only set user selected power states */
+                       if (state != POWER_STATE_TYPE_INTERNAL_BOOT &&
+                               state != POWER_STATE_TYPE_DEFAULT) {
+                               amdgpu_dpm_dispatch_task(adev,
+                                               AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL);
+                               adev->pp_force_state_enabled = true;
+                       }
+               }
+       }
+fail:
+       return count;
+}
+
+static ssize_t amdgpu_get_pp_table(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       char *table = NULL;
+       int size, i;
+
+       if (adev->pp_enabled)
+               size = amdgpu_dpm_get_pp_table(adev, &table);
+       else
+               return 0;
+
+       if (size >= PAGE_SIZE)
+               size = PAGE_SIZE - 1;
+
+       for (i = 0; i < size; i++) {
+               sprintf(buf + i, "%02x", table[i]);
+       }
+       sprintf(buf + i, "\n");
+
+       return size;
+}
+
+static ssize_t amdgpu_set_pp_table(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;
+
+       if (adev->pp_enabled)
+               amdgpu_dpm_set_pp_table(adev, buf, count);
+
+       return count;
+}
+
+static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       ssize_t size = 0;
+
+       if (adev->pp_enabled)
+               size = amdgpu_dpm_print_clock_levels(adev, PP_SCLK, buf);
+
+       return size;
+}
+
+static ssize_t amdgpu_set_pp_dpm_sclk(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;
+       long level;
+
+       ret = kstrtol(buf, 0, &level);
+
+       if (ret) {
+               count = -EINVAL;
+               goto fail;
+       }
+
+       if (adev->pp_enabled)
+               amdgpu_dpm_force_clock_level(adev, PP_SCLK, level);
+fail:
+       return count;
+}
+
+static ssize_t amdgpu_get_pp_dpm_mclk(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       ssize_t size = 0;
+
+       if (adev->pp_enabled)
+               size = amdgpu_dpm_print_clock_levels(adev, PP_MCLK, buf);
+
+       return size;
+}
+
+static ssize_t amdgpu_set_pp_dpm_mclk(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;
+       long level;
+
+       ret = kstrtol(buf, 0, &level);
+
+       if (ret) {
+               count = -EINVAL;
+               goto fail;
+       }
+
+       if (adev->pp_enabled)
+               amdgpu_dpm_force_clock_level(adev, PP_MCLK, level);
+fail:
+       return count;
+}
+
+static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       ssize_t size = 0;
+
+       if (adev->pp_enabled)
+               size = amdgpu_dpm_print_clock_levels(adev, PP_PCIE, buf);
+
+       return size;
+}
+
+static ssize_t amdgpu_set_pp_dpm_pcie(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;
+       long level;
+
+       ret = kstrtol(buf, 0, &level);
+
+       if (ret) {
+               count = -EINVAL;
+               goto fail;
+       }
+
+       if (adev->pp_enabled)
+               amdgpu_dpm_force_clock_level(adev, PP_PCIE, level);
+fail:
+       return count;
+}
+
 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,
                   amdgpu_set_dpm_forced_performance_level);
+static DEVICE_ATTR(pp_num_states, S_IRUGO, amdgpu_get_pp_num_states, NULL);
+static DEVICE_ATTR(pp_cur_state, S_IRUGO, amdgpu_get_pp_cur_state, NULL);
+static DEVICE_ATTR(pp_force_state, S_IRUGO | S_IWUSR,
+               amdgpu_get_pp_force_state,
+               amdgpu_set_pp_force_state);
+static DEVICE_ATTR(pp_table, S_IRUGO | S_IWUSR,
+               amdgpu_get_pp_table,
+               amdgpu_set_pp_table);
+static DEVICE_ATTR(pp_dpm_sclk, S_IRUGO | S_IWUSR,
+               amdgpu_get_pp_dpm_sclk,
+               amdgpu_set_pp_dpm_sclk);
+static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR,
+               amdgpu_get_pp_dpm_mclk,
+               amdgpu_set_pp_dpm_mclk);
+static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR,
+               amdgpu_get_pp_dpm_pcie,
+               amdgpu_set_pp_dpm_pcie);
 
 static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
                                      struct device_attribute *attr,
@@ -765,6 +1052,44 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
                DRM_ERROR("failed to create device file for dpm state\n");
                return ret;
        }
+
+       if (adev->pp_enabled) {
+               ret = device_create_file(adev->dev, &dev_attr_pp_num_states);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_num_states\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_cur_state);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_cur_state\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_force_state);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_force_state\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_table);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_table\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_dpm_sclk);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_dpm_sclk\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_dpm_mclk);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_dpm_mclk\n");
+                       return ret;
+               }
+               ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie);
+               if (ret) {
+                       DRM_ERROR("failed to create device file pp_dpm_pcie\n");
+                       return ret;
+               }
+       }
        ret = amdgpu_debugfs_pm_init(adev);
        if (ret) {
                DRM_ERROR("Failed to register debugfs file for dpm!\n");
@@ -782,6 +1107,15 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
                hwmon_device_unregister(adev->pm.int_hwmon_dev);
        device_remove_file(adev->dev, &dev_attr_power_dpm_state);
        device_remove_file(adev->dev, &dev_attr_power_dpm_force_performance_level);
+       if (adev->pp_enabled) {
+               device_remove_file(adev->dev, &dev_attr_pp_num_states);
+               device_remove_file(adev->dev, &dev_attr_pp_cur_state);
+               device_remove_file(adev->dev, &dev_attr_pp_force_state);
+               device_remove_file(adev->dev, &dev_attr_pp_table);
+               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_pcie);
+       }
 }
 
 void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
index aa67244a77ae38cf69761bc964c5f1d4400874c5..4719fa7e8cd7d31ae6815085c48423a711f0e0ed 100644 (file)
@@ -433,7 +433,10 @@ enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
        case PP_StateUILabel_Performance:
                return POWER_STATE_TYPE_PERFORMANCE;
        default:
-               return POWER_STATE_TYPE_DEFAULT;
+               if (state->classification.flags & PP_StateClassificationFlag_Boot)
+                       return  POWER_STATE_TYPE_INTERNAL_BOOT;
+               else
+                       return POWER_STATE_TYPE_DEFAULT;
        }
 }
 
@@ -535,6 +538,112 @@ static int pp_dpm_get_temperature(void *handle)
        return hwmgr->hwmgr_func->get_temperature(hwmgr);
 }
 
+static int pp_dpm_get_pp_num_states(void *handle,
+               struct pp_states_info *data)
+{
+       struct pp_hwmgr *hwmgr;
+       int i;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       if (hwmgr == NULL || hwmgr->ps == NULL)
+               return -EINVAL;
+
+       data->nums = hwmgr->num_ps;
+
+       for (i = 0; i < hwmgr->num_ps; i++) {
+               struct pp_power_state *state = (struct pp_power_state *)
+                               ((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
+               switch (state->classification.ui_label) {
+               case PP_StateUILabel_Battery:
+                       data->states[i] = POWER_STATE_TYPE_BATTERY;
+                       break;
+               case PP_StateUILabel_Balanced:
+                       data->states[i] = POWER_STATE_TYPE_BALANCED;
+                       break;
+               case PP_StateUILabel_Performance:
+                       data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
+                       break;
+               default:
+                       if (state->classification.flags & PP_StateClassificationFlag_Boot)
+                               data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
+                       else
+                               data->states[i] = POWER_STATE_TYPE_DEFAULT;
+               }
+       }
+
+       return 0;
+}
+
+static int pp_dpm_get_pp_table(void *handle, char **table)
+{
+       struct pp_hwmgr *hwmgr;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+               hwmgr->hwmgr_func->get_pp_table == NULL)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->get_pp_table(hwmgr, table);
+}
+
+static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
+{
+       struct pp_hwmgr *hwmgr;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+               hwmgr->hwmgr_func->set_pp_table == NULL)
+                       return -EINVAL;
+
+       return hwmgr->hwmgr_func->set_pp_table(hwmgr, buf, size);
+}
+
+static int pp_dpm_force_clock_level(void *handle,
+               enum pp_clock_type type, int level)
+{
+       struct pp_hwmgr *hwmgr;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+                       hwmgr->hwmgr_func->force_clock_level == NULL)
+                               return -EINVAL;
+
+       return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, level);
+}
+
+static int pp_dpm_print_clock_levels(void *handle,
+               enum pp_clock_type type, char *buf)
+{
+       struct pp_hwmgr *hwmgr;
+
+       if (!handle)
+               return -EINVAL;
+
+       hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+       if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+                       hwmgr->hwmgr_func->print_clock_levels == NULL)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
+}
+
 const struct amd_powerplay_funcs pp_dpm_funcs = {
        .get_temperature = pp_dpm_get_temperature,
        .load_firmware = pp_dpm_load_fw,
@@ -552,6 +661,11 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {
        .get_fan_control_mode = pp_dpm_get_fan_control_mode,
        .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
        .get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
+       .get_pp_num_states = pp_dpm_get_pp_num_states,
+       .get_pp_table = pp_dpm_get_pp_table,
+       .set_pp_table = pp_dpm_set_pp_table,
+       .force_clock_level = pp_dpm_force_clock_level,
+       .print_clock_levels = pp_dpm_print_clock_levels,
 };
 
 static int amd_pp_instance_init(struct amd_pp_init *pp_init,
index e61a3e67852e27bffef8210f372dd916f21e5066..4702a281e6c5257bef4f3ae19a5680aba77e355c 100644 (file)
@@ -123,6 +123,7 @@ enum amd_dpm_forced_level {
        AMD_DPM_FORCED_LEVEL_AUTO = 0,
        AMD_DPM_FORCED_LEVEL_LOW = 1,
        AMD_DPM_FORCED_LEVEL_HIGH = 2,
+       AMD_DPM_FORCED_LEVEL_MANUAL = 3,
 };
 
 struct amd_pp_init {
@@ -225,6 +226,17 @@ enum {
        PP_GROUP_MAX
 };
 
+enum pp_clock_type {
+       PP_SCLK,
+       PP_MCLK,
+       PP_PCIE,
+};
+
+struct pp_states_info {
+       uint32_t nums;
+       uint32_t states[16];
+};
+
 #define PP_GROUP_MASK        0xF0000000
 #define PP_GROUP_SHIFT       28
 
@@ -278,6 +290,11 @@ struct amd_powerplay_funcs {
        int (*get_fan_control_mode)(void *handle);
        int (*set_fan_speed_percent)(void *handle, uint32_t percent);
        int (*get_fan_speed_percent)(void *handle, uint32_t *speed);
+       int (*get_pp_num_states)(void *handle, struct pp_states_info *data);
+       int (*get_pp_table)(void *handle, char **table);
+       int (*set_pp_table)(void *handle, const char *buf, size_t size);
+       int (*force_clock_level)(void *handle, enum pp_clock_type type, int level);
+       int (*print_clock_levels)(void *handle, enum pp_clock_type type, char *buf);
 };
 
 struct amd_powerplay {
index aeaa3dbba525ce98dfaf4cb4c006f9ddabbc6c7d..4094e818500418ff12c7404ace1216b0c9cefc3b 100644 (file)
@@ -327,6 +327,10 @@ struct pp_hwmgr_func {
        int (*get_dal_power_level)(struct pp_hwmgr *hwmgr,
                                   struct amd_pp_dal_clock_info *info);
        int (*power_off_asic)(struct pp_hwmgr *hwmgr);
+       int (*get_pp_table)(struct pp_hwmgr *hwmgr, char **table);
+       int (*set_pp_table)(struct pp_hwmgr *hwmgr, const char *buf, size_t size);
+       int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, int level);
+       int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf);
 };
 
 struct pp_table_func {