Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 196518
b: refs/heads/master
c: a424816
h: refs/heads/master
v: v3
  • Loading branch information
Alex Deucher authored and Dave Airlie committed May 18, 2010
1 parent 4aa3c88 commit e6179a8
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 57 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 49e02b7306cb7e01965fe5f41ba0f80085142f6e
refs/heads/master: a424816fb37f894a37585cf86dfdd6b8b1dc681f
66 changes: 42 additions & 24 deletions trunk/drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ void r100_get_power_state(struct radeon_device *rdev,
pcie_lanes);
}

void r100_set_power_state(struct radeon_device *rdev)
void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
{
u32 sclk, mclk;

Expand All @@ -167,33 +167,51 @@ void r100_set_power_state(struct radeon_device *rdev)
if (rdev->pm.active_crtc_count > 1)
mclk = rdev->clock.default_mclk;

/* set pcie lanes */
/* TODO */
/* voltage, pcie lanes, etc.*/
radeon_pm_misc(rdev);

/* set voltage */
/* TODO */

/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}
if (static_switch) {
radeon_pm_prepare(rdev);
/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_set_engine_clock(rdev, sclk);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}
#if 0
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_set_memory_clock(rdev, mclk);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
#endif
radeon_pm_finish(rdev);
} else {
/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}

#if 0
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_memory_clock(rdev, mclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_pm_prepare(rdev);
radeon_set_memory_clock(rdev, mclk);
radeon_pm_finish(rdev);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
#endif
}

rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
Expand Down
69 changes: 42 additions & 27 deletions trunk/drivers/gpu/drm/radeon/r600.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ void r600_get_power_state(struct radeon_device *rdev,
pcie_lanes);
}

void r600_set_power_state(struct radeon_device *rdev)
void r600_set_power_state(struct radeon_device *rdev, bool static_switch)
{
u32 sclk, mclk;

Expand All @@ -266,37 +266,52 @@ void r600_set_power_state(struct radeon_device *rdev)
clock_info[rdev->pm.requested_clock_mode_index].mclk;
if (mclk > rdev->clock.default_mclk)
mclk = rdev->clock.default_mclk;
/* don't change the mclk with multiple crtcs */
if (rdev->pm.active_crtc_count > 1)
mclk = rdev->clock.default_mclk;

/* set pcie lanes */
/* TODO */

/* set voltage */
/* TODO */
/* voltage, pcie lanes, etc.*/
radeon_pm_misc(rdev);

/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}
if (static_switch) {
radeon_pm_prepare(rdev);
/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_set_engine_clock(rdev, sclk);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}
#if 0
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_set_memory_clock(rdev, mclk);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
#endif
radeon_pm_finish(rdev);
} else {
/* set engine clock */
if (sclk != rdev->pm.current_sclk) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
DRM_INFO("Setting: e: %d\n", sclk);
}

#if 0
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_memory_clock(rdev, mclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_sync_with_vblank(rdev);
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_pm_prepare(rdev);
radeon_set_memory_clock(rdev, mclk);
radeon_pm_finish(rdev);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
DRM_INFO("Setting: m: %d\n", mclk);
}
#endif
}

rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
Expand Down
7 changes: 5 additions & 2 deletions trunk/drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ struct radeon_asic {
void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
bool (*gui_idle)(struct radeon_device *rdev);
void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action);
void (*set_power_state)(struct radeon_device *rdev);
void (*set_power_state)(struct radeon_device *rdev, bool static_switch);
void (*pm_misc)(struct radeon_device *rdev);
void (*pm_prepare)(struct radeon_device *rdev);
void (*pm_finish)(struct radeon_device *rdev);
Expand Down Expand Up @@ -1226,7 +1226,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev))
#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a))
#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev))
#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s))
#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev))
#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev))
#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))

/* Common functions */
/* AGP */
Expand Down
4 changes: 2 additions & 2 deletions trunk/drivers/gpu/drm/radeon/radeon_asic.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void r100_enable_bm(struct radeon_device *rdev);
void r100_set_common_regs(struct radeon_device *rdev);
void r100_bm_disable(struct radeon_device *rdev);
extern bool r100_gui_idle(struct radeon_device *rdev);
extern void r100_set_power_state(struct radeon_device *rdev);
extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch);
extern void r100_get_power_state(struct radeon_device *rdev,
enum radeon_pm_action action);
extern void r100_pm_misc(struct radeon_device *rdev);
Expand Down Expand Up @@ -281,7 +281,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo);
extern bool r600_gui_idle(struct radeon_device *rdev);
extern void r600_set_power_state(struct radeon_device *rdev);
extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch);
extern void r600_get_power_state(struct radeon_device *rdev,
enum radeon_pm_action action);
extern void r600_pm_misc(struct radeon_device *rdev);
Expand Down
139 changes: 138 additions & 1 deletion trunk/drivers/gpu/drm/radeon/radeon_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,128 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev);
static void radeon_pm_idle_work_handler(struct work_struct *work);
static int radeon_debugfs_pm_init(struct radeon_device *rdev);

static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev)
{
mutex_lock(&rdev->cp.mutex);

/* wait for GPU idle */
rdev->pm.gui_idle = false;
rdev->irq.gui_idle = true;
radeon_irq_set(rdev);
wait_event_interruptible_timeout(
rdev->irq.idle_queue, rdev->pm.gui_idle,
msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
rdev->irq.gui_idle = false;
radeon_irq_set(rdev);

radeon_set_power_state(rdev, true);

/* update display watermarks based on new power state */
radeon_update_bandwidth_info(rdev);
if (rdev->pm.active_crtc_count)
radeon_bandwidth_update(rdev);

mutex_unlock(&rdev->cp.mutex);
}

static ssize_t radeon_get_power_state_static(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;

return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index,
rdev->pm.current_clock_mode_index);
}

static ssize_t radeon_set_power_state_static(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
int ps, cm;

if (sscanf(buf, "%u.%u", &ps, &cm) != 2) {
DRM_ERROR("Invalid power state!\n");
return count;
}

mutex_lock(&rdev->pm.mutex);
if ((ps >= 0) && (ps < rdev->pm.num_power_states) &&
(cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) {
if ((rdev->pm.active_crtc_count > 1) &&
(rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) {
DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm);
} else {
/* disable dynpm */
rdev->pm.state = PM_STATE_DISABLED;
rdev->pm.planned_action = PM_ACTION_NONE;
rdev->pm.requested_power_state_index = ps;
rdev->pm.requested_clock_mode_index = cm;
radeon_pm_set_power_mode_static_locked(rdev);
}
} else
DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm);
mutex_unlock(&rdev->pm.mutex);

return count;
}

static ssize_t radeon_get_dynpm(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;

return snprintf(buf, PAGE_SIZE, "%s\n",
(rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled");
}

static ssize_t radeon_set_dynpm(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
int tmp = simple_strtoul(buf, NULL, 10);

if (tmp == 0) {
/* update power mode info */
radeon_pm_compute_clocks(rdev);
/* disable dynpm */
mutex_lock(&rdev->pm.mutex);
rdev->pm.state = PM_STATE_DISABLED;
rdev->pm.planned_action = PM_ACTION_NONE;
mutex_unlock(&rdev->pm.mutex);
DRM_INFO("radeon: dynamic power management disabled\n");
} else if (tmp == 1) {
if (rdev->pm.num_power_states > 1) {
/* enable dynpm */
mutex_lock(&rdev->pm.mutex);
rdev->pm.state = PM_STATE_PAUSED;
rdev->pm.planned_action = PM_ACTION_DEFAULT;
radeon_get_power_state(rdev, rdev->pm.planned_action);
mutex_unlock(&rdev->pm.mutex);
/* update power mode info */
radeon_pm_compute_clocks(rdev);
DRM_INFO("radeon: dynamic power management enabled\n");
} else
DRM_ERROR("dynpm not valid on this system\n");
} else
DRM_ERROR("Invalid setting: %d\n", tmp);

return count;
}

static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static);
static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm);


static const char *pm_state_names[4] = {
"PM_STATE_DISABLED",
"PM_STATE_MINIMUM",
Expand Down Expand Up @@ -111,6 +233,10 @@ int radeon_pm_init(struct radeon_device *rdev)
DRM_ERROR("Failed to register debugfs file for PM!\n");
}

/* where's the best place to put this? */
device_create_file(rdev->dev, &dev_attr_power_state);
device_create_file(rdev->dev, &dev_attr_dynpm);

INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler);

if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) {
Expand All @@ -132,8 +258,19 @@ void radeon_pm_fini(struct radeon_device *rdev)
rdev->pm.state = PM_STATE_DISABLED;
rdev->pm.planned_action = PM_ACTION_DEFAULT;
radeon_pm_set_clocks(rdev);
} else if ((rdev->pm.current_power_state_index !=
rdev->pm.default_power_state_index) ||
(rdev->pm.current_clock_mode_index != 0)) {
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
rdev->pm.requested_clock_mode_index = 0;
mutex_lock(&rdev->pm.mutex);
radeon_pm_set_power_mode_static_locked(rdev);
mutex_unlock(&rdev->pm.mutex);
}

device_remove_file(rdev->dev, &dev_attr_power_state);
device_remove_file(rdev->dev, &dev_attr_dynpm);

if (rdev->pm.i2c_bus)
radeon_i2c_destroy(rdev->pm.i2c_bus);
}
Expand Down Expand Up @@ -267,7 +404,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
{
/*radeon_fence_wait_last(rdev);*/

radeon_set_power_state(rdev);
radeon_set_power_state(rdev, false);
rdev->pm.planned_action = PM_ACTION_NONE;
}

Expand Down

0 comments on commit e6179a8

Please sign in to comment.