]> Git Repo - linux.git/blobdiff - drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
Merge tag 'iommu-updates-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_pm.c
index 9982f1b1f8c43ed3e8b0e5247a364a25a5f59a2d..b455da4877829e57b76178ed2300959c4dade7f4 100644 (file)
@@ -455,6 +455,29 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
        return count;
 }
 
+/**
+ * DOC: pp_od_clk_voltage
+ *
+ * The amdgpu driver provides a sysfs API for adjusting the clocks and voltages
+ * in each power level within a power state.  The pp_od_clk_voltage is used for
+ * this.
+ *
+ * Reading the file will display:
+ * - a list of engine clock levels and voltages labeled OD_SCLK
+ * - a list of memory clock levels and voltages labeled OD_MCLK
+ * - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE
+ *
+ * To manually adjust these settings, first select manual using
+ * power_dpm_force_performance_level. Enter a new value for each
+ * level by writing a string that contains "s/m level clock voltage" to
+ * the file.  E.g., "s 1 500 820" will update sclk level 1 to be 500 MHz
+ * at 820 mV; "m 0 350 810" will update mclk level 0 to be 350 MHz at
+ * 810 mV.  When you have edited all of the states as needed, write
+ * "c" (commit) to the file to commit your changes.  If you want to reset to the
+ * default power levels, write "r" (reset) to the file to reset them.
+ *
+ */
+
 static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
                struct device_attribute *attr,
                const char *buf,
@@ -532,6 +555,7 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
        if (adev->powerplay.pp_funcs->print_clock_levels) {
                size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf);
                size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf+size);
+               size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf+size);
                return size;
        } else {
                return snprintf(buf, PAGE_SIZE, "\n");
@@ -539,6 +563,23 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev,
 
 }
 
+/**
+ * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
+ *
+ * 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,
+ * and pp_dpm_pcie are used for this.
+ *
+ * Reading back the files will show you the available power levels within
+ * the power state and the clock information for those levels.
+ *
+ * To manually adjust these states, first select manual using
+ * power_dpm_force_performance_level.
+ * Secondly,Enter a new value for each level by inputing a string that
+ * 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.
+ */
+
 static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev,
                struct device_attribute *attr,
                char *buf)
@@ -561,23 +602,27 @@ static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev,
        struct amdgpu_device *adev = ddev->dev_private;
        int ret;
        long level;
-       uint32_t i, mask = 0;
-       char sub_str[2];
+       uint32_t mask = 0;
+       char *sub_str = NULL;
+       char *tmp;
+       char buf_cpy[count];
+       const char delimiter[3] = {' ', '\n', '\0'};
 
-       for (i = 0; i < strlen(buf); i++) {
-               if (*(buf + i) == '\n')
-                       continue;
-               sub_str[0] = *(buf + i);
-               sub_str[1] = '\0';
-               ret = kstrtol(sub_str, 0, &level);
+       memcpy(buf_cpy, buf, count+1);
+       tmp = buf_cpy;
+       while (tmp[0]) {
+               sub_str =  strsep(&tmp, delimiter);
+               if (strlen(sub_str)) {
+                       ret = kstrtol(sub_str, 0, &level);
 
-               if (ret) {
-                       count = -EINVAL;
-                       goto fail;
-               }
-               mask |= 1 << level;
+                       if (ret) {
+                               count = -EINVAL;
+                               goto fail;
+                       }
+                       mask |= 1 << level;
+               } else
+                       break;
        }
-
        if (adev->powerplay.pp_funcs->force_clock_level)
                amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask);
 
@@ -607,21 +652,26 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev,
        struct amdgpu_device *adev = ddev->dev_private;
        int ret;
        long level;
-       uint32_t i, mask = 0;
-       char sub_str[2];
+       uint32_t mask = 0;
+       char *sub_str = NULL;
+       char *tmp;
+       char buf_cpy[count];
+       const char delimiter[3] = {' ', '\n', '\0'};
 
-       for (i = 0; i < strlen(buf); i++) {
-               if (*(buf + i) == '\n')
-                       continue;
-               sub_str[0] = *(buf + i);
-               sub_str[1] = '\0';
-               ret = kstrtol(sub_str, 0, &level);
+       memcpy(buf_cpy, buf, count+1);
+       tmp = buf_cpy;
+       while (tmp[0]) {
+               sub_str =  strsep(&tmp, delimiter);
+               if (strlen(sub_str)) {
+                       ret = kstrtol(sub_str, 0, &level);
 
-               if (ret) {
-                       count = -EINVAL;
-                       goto fail;
-               }
-               mask |= 1 << level;
+                       if (ret) {
+                               count = -EINVAL;
+                               goto fail;
+                       }
+                       mask |= 1 << level;
+               } else
+                       break;
        }
        if (adev->powerplay.pp_funcs->force_clock_level)
                amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask);
@@ -652,21 +702,27 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev,
        struct amdgpu_device *adev = ddev->dev_private;
        int ret;
        long level;
-       uint32_t i, mask = 0;
-       char sub_str[2];
+       uint32_t mask = 0;
+       char *sub_str = NULL;
+       char *tmp;
+       char buf_cpy[count];
+       const char delimiter[3] = {' ', '\n', '\0'};
+
+       memcpy(buf_cpy, buf, count+1);
+       tmp = buf_cpy;
 
-       for (i = 0; i < strlen(buf); i++) {
-               if (*(buf + i) == '\n')
-                       continue;
-               sub_str[0] = *(buf + i);
-               sub_str[1] = '\0';
-               ret = kstrtol(sub_str, 0, &level);
+       while (tmp[0]) {
+               sub_str =  strsep(&tmp, delimiter);
+               if (strlen(sub_str)) {
+                       ret = kstrtol(sub_str, 0, &level);
 
-               if (ret) {
-                       count = -EINVAL;
-                       goto fail;
-               }
-               mask |= 1 << level;
+                       if (ret) {
+                               count = -EINVAL;
+                               goto fail;
+                       }
+                       mask |= 1 << level;
+               } else
+                       break;
        }
        if (adev->powerplay.pp_funcs->force_clock_level)
                amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask);
@@ -763,6 +819,26 @@ fail:
        return count;
 }
 
+/**
+ * DOC: pp_power_profile_mode
+ *
+ * The amdgpu driver provides a sysfs API for adjusting the heuristics
+ * related to switching between power levels in a power state.  The file
+ * pp_power_profile_mode is used for this.
+ *
+ * Reading this file outputs a list of all of the predefined power profiles
+ * and the relevant heuristics settings for that profile.
+ *
+ * To select a profile or create a custom profile, first select manual using
+ * power_dpm_force_performance_level.  Writing the number of a predefined
+ * profile to pp_power_profile_mode will enable those heuristics.  To
+ * create a custom set of heuristics, write a string of numbers to the file
+ * starting with the number of the custom profile along with a setting
+ * for each heuristic parameter.  Due to differences across asic families
+ * the heuristic parameters vary from family to family.
+ *
+ */
+
 static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev,
                struct device_attribute *attr,
                char *buf)
@@ -1288,19 +1364,14 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
        struct amdgpu_device *adev = dev_get_drvdata(dev);
        umode_t effective_mode = attr->mode;
 
-       /* handle non-powerplay limitations */
-       if (!adev->powerplay.pp_handle) {
-               /* Skip fan attributes if fan is not present */
-               if (adev->pm.no_fan &&
-                   (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
-                    attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
-                    attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
-                    attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
-                       return 0;
-               /* requires powerplay */
-               if (attr == &sensor_dev_attr_fan1_input.dev_attr.attr)
-                       return 0;
-       }
+
+       /* Skip fan attributes if fan is not present */
+       if (adev->pm.no_fan && (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+           attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+           attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_pwm1_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_fan1_input.dev_attr.attr))
+               return 0;
 
        /* Skip limit attributes if DPM is not enabled */
        if (!adev->pm.dpm_enabled &&
@@ -1807,26 +1878,26 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
                        amdgpu_fence_wait_empty(ring);
        }
 
-       if (!amdgpu_device_has_dc_support(adev)) {
-               mutex_lock(&adev->pm.mutex);
-               amdgpu_dpm_get_active_displays(adev);
-               adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtcs;
-               adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
-               adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
-               /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */
-               if (adev->pm.pm_display_cfg.vrefresh > 120)
-                       adev->pm.pm_display_cfg.min_vblank_time = 0;
-               if (adev->powerplay.pp_funcs->display_configuration_change)
-                       adev->powerplay.pp_funcs->display_configuration_change(
-                                                       adev->powerplay.pp_handle,
-                                                       &adev->pm.pm_display_cfg);
-               mutex_unlock(&adev->pm.mutex);
-       }
-
        if (adev->powerplay.pp_funcs->dispatch_tasks) {
+               if (!amdgpu_device_has_dc_support(adev)) {
+                       mutex_lock(&adev->pm.mutex);
+                       amdgpu_dpm_get_active_displays(adev);
+                       adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtcs;
+                       adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
+                       adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
+                       /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */
+                       if (adev->pm.pm_display_cfg.vrefresh > 120)
+                               adev->pm.pm_display_cfg.min_vblank_time = 0;
+                       if (adev->powerplay.pp_funcs->display_configuration_change)
+                               adev->powerplay.pp_funcs->display_configuration_change(
+                                                               adev->powerplay.pp_handle,
+                                                               &adev->pm.pm_display_cfg);
+                       mutex_unlock(&adev->pm.mutex);
+               }
                amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL);
        } else {
                mutex_lock(&adev->pm.mutex);
+               amdgpu_dpm_get_active_displays(adev);
                /* update battery/ac status */
                if (power_supply_is_system_supplied() > 0)
                        adev->pm.dpm.ac_power = true;
This page took 0.039403 seconds and 4 git commands to generate.