diff options
author | Dave Airlie <airlied@linux.ie> | 2010-02-01 00:38:10 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-03-01 01:20:37 -0500 |
commit | 6a9ee8af344e3bd7dbd61e67037096cdf7f83289 (patch) | |
tree | 07cdb493a790cf45bc473f2fc2ea1b9a166d5191 /drivers/gpu/drm/nouveau/nouveau_state.c | |
parent | 9fd1de52945e06ed88a440c99ca92dab74b9b33c (diff) |
vga_switcheroo: initial implementation (v15)
Many new laptops now come with 2 gpus, one to be used for low power
modes and one for gaming/on-ac applications. These GPUs are typically
wired to the laptop panel and VGA ports via a multiplexer unit which
is controlled via ACPI methods.
4 combinations of systems typically exist - with 2 ACPI methods.
Intel/ATI - Lenovo W500/T500 - use ATPX ACPI method
ATI/ATI - some ASUS - use ATPX ACPI Method
Intel/Nvidia - - use _DSM ACPI method
Nvidia/Nvidia - - use _DSM ACPI method.
TODO:
This patch adds support for the ATPX method and initial bits
for the _DSM methods that need to written by someone with
access to the hardware.
Add a proper non-debugfs interface - need to get some proper
testing first.
v2: add power up/down support for both devices
on W500 puts i915/radeon into D3 and cuts power to radeon.
v3: redo probing methods, no DMI list, drm devices call to
register with switcheroo, it tries to find an ATPX method on
any device and once there is two devices + ATPX it inits the
switcher.
v4: ATPX msg handling using buffers - should work on more machines
v5: rearchitect after more mjg59 discussion - move ATPX handling to
radeon driver.
v6: add file headers + initial nouveau bits (to be filled out).
v7: merge delayed switcher code.
v8: avoid suspend/resume of gpu that is off
v9: rearchitect - mjg59 is always right. - move all ATPX code to
radeon, should allow simpler DSM also proper ATRM handling
v10: add ATRM support for radeon BIOS, add mutex to lock vgasr_priv
v11: fix bug in resuming Intel for 2nd time.
v12: start fixing up nvidia code blindly.
v13: blindly guess at finishing nvidia code
v14: remove radeon audio hacks - fix up intel resume more like upstream
v15: clean up printks + remove unnecessary igd/dis pointers
mount debugfs
/sys/kernel/debug/vgaswitcheroo/switch - should exist if ATPX detected
+ 2 cards.
DIS - immediate change to discrete
IGD - immediate change to IGD
DDIS - delayed change to discrete
DIGD - delayed change to IGD
ON - turn on not in use
OFF - turn off not in use
Tested on W500 (Intel/ATI) and T500 (Intel/ATI)
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_state.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a4851af5b05..85d65b91389 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "drm_sarea.h" | 29 | #include "drm_sarea.h" |
30 | #include "drm_crtc_helper.h" | 30 | #include "drm_crtc_helper.h" |
31 | #include <linux/vgaarb.h> | 31 | #include <linux/vgaarb.h> |
32 | #include <linux/vga_switcheroo.h> | ||
32 | 33 | ||
33 | #include "nouveau_drv.h" | 34 | #include "nouveau_drv.h" |
34 | #include "nouveau_drm.h" | 35 | #include "nouveau_drm.h" |
@@ -371,6 +372,30 @@ out_err: | |||
371 | return ret; | 372 | return ret; |
372 | } | 373 | } |
373 | 374 | ||
375 | static void nouveau_switcheroo_set_state(struct pci_dev *pdev, | ||
376 | enum vga_switcheroo_state state) | ||
377 | { | ||
378 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | ||
379 | if (state == VGA_SWITCHEROO_ON) { | ||
380 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); | ||
381 | nouveau_pci_resume(pdev); | ||
382 | } else { | ||
383 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); | ||
384 | nouveau_pci_suspend(pdev, pmm); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) | ||
389 | { | ||
390 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
391 | bool can_switch; | ||
392 | |||
393 | spin_lock(&dev->count_lock); | ||
394 | can_switch = (dev->open_count == 0); | ||
395 | spin_unlock(&dev->count_lock); | ||
396 | return can_switch; | ||
397 | } | ||
398 | |||
374 | int | 399 | int |
375 | nouveau_card_init(struct drm_device *dev) | 400 | nouveau_card_init(struct drm_device *dev) |
376 | { | 401 | { |
@@ -384,6 +409,8 @@ nouveau_card_init(struct drm_device *dev) | |||
384 | return 0; | 409 | return 0; |
385 | 410 | ||
386 | vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); | 411 | vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); |
412 | vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, | ||
413 | nouveau_switcheroo_can_switch); | ||
387 | 414 | ||
388 | /* Initialise internal driver API hooks */ | 415 | /* Initialise internal driver API hooks */ |
389 | ret = nouveau_init_engine_ptrs(dev); | 416 | ret = nouveau_init_engine_ptrs(dev); |
@@ -617,11 +644,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) | |||
617 | NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", | 644 | NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", |
618 | dev->pci_vendor, dev->pci_device, dev->pdev->class); | 645 | dev->pci_vendor, dev->pci_device, dev->pdev->class); |
619 | 646 | ||
620 | dev_priv->acpi_dsm = nouveau_dsm_probe(dev); | ||
621 | |||
622 | if (dev_priv->acpi_dsm) | ||
623 | nouveau_hybrid_setup(dev); | ||
624 | |||
625 | dev_priv->wq = create_workqueue("nouveau"); | 647 | dev_priv->wq = create_workqueue("nouveau"); |
626 | if (!dev_priv->wq) | 648 | if (!dev_priv->wq) |
627 | return -EINVAL; | 649 | return -EINVAL; |