drm/radeon: add runtime PM support (v2)

This hooks radeon up to the runtime PM system to enable
dynamic power management for secondary GPUs in switchable
and powerxpress laptops.

v2: agd5f: clean up, add module parameter

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Dave Airlie
2012-09-17 14:40:31 +10:00
committed by Alex Deucher
parent 7473e830c4
commit 10ebc0bc09
10 changed files with 299 additions and 36 deletions
+39 -13
View File
@@ -101,6 +101,12 @@ static const char radeon_family_name[][16] = {
"LAST",
};
#if defined(CONFIG_VGA_SWITCHEROO)
bool radeon_is_px(void);
#else
static inline bool radeon_is_px(void) { return false; }
#endif
/**
* radeon_program_register_sequence - program an array of registers.
*
@@ -1076,6 +1082,10 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev)
static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
if (radeon_is_px() && state == VGA_SWITCHEROO_OFF)
return;
if (state == VGA_SWITCHEROO_ON) {
unsigned d3_delay = dev->pdev->d3_delay;
@@ -1086,7 +1096,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev))
dev->pdev->d3_delay = 20;
radeon_resume_kms(dev, 1);
radeon_resume_kms(dev, true, true);
dev->pdev->d3_delay = d3_delay;
@@ -1096,7 +1106,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
printk(KERN_INFO "radeon: switched off\n");
drm_kms_helper_poll_disable(dev);
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
radeon_suspend_kms(dev, 1);
radeon_suspend_kms(dev, true, true);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
@@ -1146,6 +1156,7 @@ int radeon_device_init(struct radeon_device *rdev,
{
int r, i;
int dma_bits;
bool runtime = false;
rdev->shutdown = false;
rdev->dev = &pdev->dev;
@@ -1292,7 +1303,14 @@ int radeon_device_init(struct radeon_device *rdev,
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, false);
if (radeon_runtime_pm == 1)
runtime = true;
if ((radeon_runtime_pm == -1) && radeon_is_px())
runtime = true;
vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime);
if (runtime)
vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain);
r = radeon_init(rdev);
if (r)
@@ -1382,7 +1400,7 @@ void radeon_device_fini(struct radeon_device *rdev)
* Returns 0 for success or an error on failure.
* Called at driver suspend.
*/
int radeon_suspend_kms(struct drm_device *dev, bool suspend)
int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
{
struct radeon_device *rdev;
struct drm_crtc *crtc;
@@ -1457,9 +1475,12 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend)
pci_disable_device(dev->pdev);
pci_set_power_state(dev->pdev, PCI_D3hot);
}
console_lock();
radeon_fbdev_set_suspend(rdev, 1);
console_unlock();
if (fbcon) {
console_lock();
radeon_fbdev_set_suspend(rdev, 1);
console_unlock();
}
return 0;
}
@@ -1472,7 +1493,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend)
* Returns 0 for success or an error on failure.
* Called at driver resume.
*/
int radeon_resume_kms(struct drm_device *dev, bool resume)
int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
{
struct drm_connector *connector;
struct radeon_device *rdev = dev->dev_private;
@@ -1481,12 +1502,15 @@ int radeon_resume_kms(struct drm_device *dev, bool resume)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
console_lock();
if (fbcon) {
console_lock();
}
if (resume) {
pci_set_power_state(dev->pdev, PCI_D0);
pci_restore_state(dev->pdev);
if (pci_enable_device(dev->pdev)) {
console_unlock();
if (fbcon)
console_unlock();
return -1;
}
}
@@ -1501,9 +1525,11 @@ int radeon_resume_kms(struct drm_device *dev, bool resume)
radeon_pm_resume(rdev);
radeon_restore_bios_scratch_regs(rdev);
radeon_fbdev_set_suspend(rdev, 0);
console_unlock();
if (fbcon) {
radeon_fbdev_set_suspend(rdev, 0);
console_unlock();
}
/* init dig PHYs, disp eng pll */
if (rdev->is_atom_bios) {
radeon_atom_encoder_init(rdev);