summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_pm.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c176
1 files changed, 116 insertions, 60 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 4b6542538ff9..a855a96dd2ea 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -20,14 +20,20 @@
* Authors: Rafał Miłecki <zajec5@gmail.com>
* Alex Deucher <alexdeucher@gmail.com>
*/
-#include <drm/drmP.h>
-#include "radeon.h"
-#include "avivod.h"
+
+#include <linux/debugfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/pci.h>
+#include <linux/power_supply.h>
+
+#include <drm/drm_vblank.h>
+
#include "atom.h"
+#include "avivod.h"
#include "r600_dpm.h"
-#include <linux/power_supply.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
+#include "radeon.h"
+#include "radeon_pm.h"
#define RADEON_IDLE_LOOP_MS 100
#define RADEON_RECLOCK_DELAY_MS 200
@@ -42,7 +48,7 @@ static const char *radeon_pm_state_type_name[5] = {
};
static void radeon_dynpm_idle_work_handler(struct work_struct *work);
-static int radeon_debugfs_pm_init(struct radeon_device *rdev);
+static void radeon_debugfs_pm_init(struct radeon_device *rdev);
static bool radeon_pm_in_vbl(struct radeon_device *rdev);
static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
static void radeon_pm_update_profile(struct radeon_device *rdev);
@@ -149,7 +155,7 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev)
return;
list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
- if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
+ if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
ttm_bo_unmap_virtual(&bo->tbo);
}
}
@@ -276,7 +282,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
if (rdev->irq.installed) {
i = 0;
- drm_for_each_crtc(crtc, rdev->ddev) {
+ drm_for_each_crtc(crtc, rdev_to_drm(rdev)) {
if (rdev->pm.active_crtcs & (1 << i)) {
/* This can fail if a modeset is in progress */
if (drm_crtc_vblank_get(crtc) == 0)
@@ -293,7 +299,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
if (rdev->irq.installed) {
i = 0;
- drm_for_each_crtc(crtc, rdev->ddev) {
+ drm_for_each_crtc(crtc, rdev_to_drm(rdev)) {
if (rdev->pm.req_vblank & (1 << i)) {
rdev->pm.req_vblank &= ~(1 << i);
drm_crtc_vblank_put(crtc);
@@ -355,11 +361,10 @@ static ssize_t radeon_get_pm_profile(struct device *dev,
struct radeon_device *rdev = ddev->dev_private;
int cp = rdev->pm.profile;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (cp == PM_PROFILE_AUTO) ? "auto" :
- (cp == PM_PROFILE_LOW) ? "low" :
- (cp == PM_PROFILE_MID) ? "mid" :
- (cp == PM_PROFILE_HIGH) ? "high" : "default");
+ return sysfs_emit(buf, "%s\n", (cp == PM_PROFILE_AUTO) ? "auto" :
+ (cp == PM_PROFILE_LOW) ? "low" :
+ (cp == PM_PROFILE_MID) ? "mid" :
+ (cp == PM_PROFILE_HIGH) ? "high" : "default");
}
static ssize_t radeon_set_pm_profile(struct device *dev,
@@ -410,9 +415,8 @@ static ssize_t radeon_get_pm_method(struct device *dev,
struct radeon_device *rdev = ddev->dev_private;
int pm = rdev->pm.pm_method;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (pm == PM_METHOD_DYNPM) ? "dynpm" :
- (pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
+ return sysfs_emit(buf, "%s\n", (pm == PM_METHOD_DYNPM) ? "dynpm" :
+ (pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
}
static ssize_t radeon_set_pm_method(struct device *dev,
@@ -467,9 +471,9 @@ static ssize_t radeon_get_dpm_state(struct device *dev,
struct radeon_device *rdev = ddev->dev_private;
enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
- (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
+ return sysfs_emit(buf, "%s\n",
+ (pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
+ (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
}
static ssize_t radeon_set_dpm_state(struct device *dev,
@@ -513,11 +517,11 @@ static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
if ((rdev->flags & RADEON_IS_PX) &&
(ddev->switch_power_state != DRM_SWITCH_POWER_ON))
- return snprintf(buf, PAGE_SIZE, "off\n");
+ return sysfs_emit(buf, "off\n");
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
- (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+ return sysfs_emit(buf, "%s\n",
+ (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+ (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
}
static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
@@ -584,7 +588,7 @@ static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
int err;
int value;
- if(!rdev->asic->dpm.fan_ctrl_set_mode)
+ if (!rdev->asic->dpm.fan_ctrl_set_mode)
return -EINVAL;
err = kstrtoint(buf, 10, &value);
@@ -667,7 +671,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
char *buf)
{
struct radeon_device *rdev = dev_get_drvdata(dev);
- struct drm_device *ddev = rdev->ddev;
+ struct drm_device *ddev = rdev_to_drm(rdev);
int temp;
/* Can't get temperature when the card is off */
@@ -680,7 +684,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
else
temp = 0;
- return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+ return sysfs_emit(buf, "%d\n", temp);
}
static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
@@ -696,7 +700,7 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
else
temp = rdev->pm.dpm.thermal.max_temp;
- return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+ return sysfs_emit(buf, "%d\n", temp);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
@@ -707,6 +711,51 @@ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_
static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
+static ssize_t radeon_hwmon_show_sclk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ struct drm_device *ddev = rdev_to_drm(rdev);
+ u32 sclk = 0;
+
+ /* Can't get clock frequency when the card is off */
+ if ((rdev->flags & RADEON_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
+ if (rdev->asic->dpm.get_current_sclk)
+ sclk = radeon_dpm_get_current_sclk(rdev);
+
+ /* Value returned by dpm is in 10 KHz units, need to convert it into Hz
+ for hwmon */
+ sclk *= 10000;
+
+ return sysfs_emit(buf, "%u\n", sclk);
+}
+
+static SENSOR_DEVICE_ATTR(freq1_input, S_IRUGO, radeon_hwmon_show_sclk, NULL,
+ 0);
+
+static ssize_t radeon_hwmon_show_vddc(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ struct drm_device *ddev = rdev_to_drm(rdev);
+ u16 vddc = 0;
+
+ /* Can't get vddc when the card is off */
+ if ((rdev->flags & RADEON_IS_PX) &&
+ (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+ return -EINVAL;
+
+ if (rdev->asic->dpm.get_current_vddc)
+ vddc = rdev->asic->dpm.get_current_vddc(rdev);
+
+ return sysfs_emit(buf, "%u\n", vddc);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, radeon_hwmon_show_vddc, NULL,
+ 0);
static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -716,6 +765,8 @@ static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_min.dev_attr.attr,
&sensor_dev_attr_pwm1_max.dev_attr.attr,
+ &sensor_dev_attr_freq1_input.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
NULL
};
@@ -733,7 +784,14 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
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_pwm1_min.dev_attr.attr ||
+ attr == &sensor_dev_attr_freq1_input.dev_attr.attr ||
+ attr == &sensor_dev_attr_in0_input.dev_attr.attr))
+ return 0;
+
+ /* Skip vddc attribute if get_current_vddc is not implemented */
+ if (attr == &sensor_dev_attr_in0_input.dev_attr.attr &&
+ !rdev->asic->dpm.get_current_vddc)
return 0;
/* Skip fan attributes if fan is not present */
@@ -849,8 +907,7 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
static bool radeon_dpm_single_display(struct radeon_device *rdev)
{
- bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
- true : false;
+ bool single_display = rdev->pm.dpm.new_active_crtc_count < 2;
/* check if the vblank period is too short to adjust the mclk */
if (single_display && rdev->asic->dpm.vblank_too_short) {
@@ -1339,10 +1396,7 @@ static int radeon_pm_init_old(struct radeon_device *rdev)
INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler);
if (rdev->pm.num_power_states > 1) {
- if (radeon_debugfs_pm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for PM!\n");
- }
-
+ radeon_debugfs_pm_init(rdev);
DRM_INFO("radeon: power management initialized\n");
}
@@ -1396,9 +1450,7 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)
goto dpm_failed;
rdev->pm.dpm_enabled = true;
- if (radeon_debugfs_pm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for dpm!\n");
- }
+ radeon_debugfs_pm_init(rdev);
DRM_INFO("radeon: dpm initialized\n");
@@ -1577,7 +1629,7 @@ int radeon_pm_late_init(struct radeon_device *rdev)
ret = device_create_file(rdev->dev, &dev_attr_power_method);
if (ret)
DRM_ERROR("failed to create device file for power method\n");
- if (!ret)
+ else
rdev->pm.sysfs_initialized = true;
}
}
@@ -1639,7 +1691,7 @@ void radeon_pm_fini(struct radeon_device *rdev)
static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
{
- struct drm_device *ddev = rdev->ddev;
+ struct drm_device *ddev = rdev_to_drm(rdev);
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
@@ -1712,9 +1764,10 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
{
- struct drm_device *ddev = rdev->ddev;
+ struct drm_device *ddev = rdev_to_drm(rdev);
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
+ struct radeon_connector *radeon_connector;
if (!rdev->pm.dpm_enabled)
return;
@@ -1724,6 +1777,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
/* update active crtc counts */
rdev->pm.dpm.new_active_crtcs = 0;
rdev->pm.dpm.new_active_crtc_count = 0;
+ rdev->pm.dpm.high_pixelclock_count = 0;
if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
list_for_each_entry(crtc,
&ddev->mode_config.crtc_list, head) {
@@ -1731,6 +1785,12 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
if (crtc->enabled) {
rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
rdev->pm.dpm.new_active_crtc_count++;
+ if (!radeon_crtc->connector)
+ continue;
+
+ radeon_connector = to_radeon_connector(radeon_crtc->connector);
+ if (radeon_connector->pixelclock_for_modeset > 297000)
+ rdev->pm.dpm.high_pixelclock_count++;
}
}
}
@@ -1765,7 +1825,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
*/
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
if (rdev->pm.active_crtcs & (1 << crtc)) {
- vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev,
+ vbl_status = radeon_get_crtc_scanoutpos(rdev_to_drm(rdev),
crtc,
USE_REAL_VBLANKSTART,
&vpos, &hpos, NULL, NULL,
@@ -1784,7 +1844,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
u32 stat_crtc = 0;
bool in_vbl = radeon_pm_in_vbl(rdev);
- if (in_vbl == false)
+ if (!in_vbl)
DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc,
finish ? "exit" : "entry");
return in_vbl;
@@ -1793,11 +1853,10 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
static void radeon_dynpm_idle_work_handler(struct work_struct *work)
{
struct radeon_device *rdev;
- int resched;
+
rdev = container_of(work, struct radeon_device,
pm.dynpm_idle_work.work);
- resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
mutex_lock(&rdev->pm.mutex);
if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
int not_processed = 0;
@@ -1839,7 +1898,7 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
* to false since we want to wait for vbl to avoid flicker.
*/
if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE &&
- jiffies > rdev->pm.dynpm_action_timeout) {
+ time_after(jiffies, rdev->pm.dynpm_action_timeout)) {
radeon_pm_get_dynpm_state(rdev);
radeon_pm_set_clocks(rdev);
}
@@ -1848,7 +1907,6 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
}
mutex_unlock(&rdev->pm.mutex);
- ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
}
/*
@@ -1856,12 +1914,10 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
*/
#if defined(CONFIG_DEBUG_FS)
-static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
+static int radeon_debugfs_pm_info_show(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct drm_device *ddev = rdev->ddev;
+ struct radeon_device *rdev = m->private;
+ struct drm_device *ddev = rdev_to_drm(rdev);
if ((rdev->flags & RADEON_IS_PX) &&
(ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
@@ -1892,16 +1948,16 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
return 0;
}
-static struct drm_info_list radeon_pm_info_list[] = {
- {"radeon_pm_info", radeon_debugfs_pm_info, 0, NULL},
-};
+DEFINE_SHOW_ATTRIBUTE(radeon_debugfs_pm_info);
#endif
-static int radeon_debugfs_pm_init(struct radeon_device *rdev)
+static void radeon_debugfs_pm_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
- return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list));
-#else
- return 0;
+ struct dentry *root = rdev_to_drm(rdev)->primary->debugfs_root;
+
+ debugfs_create_file("radeon_pm_info", 0444, root, rdev,
+ &radeon_debugfs_pm_info_fops);
+
#endif
}