Commit | Line | Data |
---|---|---|
77145f1c BS |
1 | #include <linux/vgaarb.h> |
2 | #include <linux/vga_switcheroo.h> | |
3 | ||
612a9aab LT |
4 | #include <drm/drmP.h> |
5 | #include <drm/drm_crtc_helper.h> | |
77145f1c BS |
6 | |
7 | #include "nouveau_drm.h" | |
8 | #include "nouveau_acpi.h" | |
9 | #include "nouveau_fbcon.h" | |
5b8a43ae | 10 | #include "nouveau_vga.h" |
77145f1c BS |
11 | |
12 | static unsigned int | |
13 | nouveau_vga_set_decode(void *priv, bool state) | |
14 | { | |
15 | struct nouveau_device *device = nouveau_dev(priv); | |
16 | ||
17 | if (device->chipset >= 0x40) | |
18 | nv_wr32(device, 0x088054, state); | |
19 | else | |
20 | nv_wr32(device, 0x001854, state); | |
21 | ||
22 | if (state) | |
23 | return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | | |
24 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; | |
25 | else | |
26 | return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; | |
27 | } | |
28 | ||
29 | static void | |
30 | nouveau_switcheroo_set_state(struct pci_dev *pdev, | |
31 | enum vga_switcheroo_state state) | |
32 | { | |
33 | struct drm_device *dev = pci_get_drvdata(pdev); | |
77145f1c BS |
34 | |
35 | if (state == VGA_SWITCHEROO_ON) { | |
36 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); | |
37 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | |
2d8b9ccb | 38 | nouveau_pmops_resume(&pdev->dev); |
77145f1c BS |
39 | drm_kms_helper_poll_enable(dev); |
40 | dev->switch_power_state = DRM_SWITCH_POWER_ON; | |
41 | } else { | |
42 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); | |
43 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | |
44 | drm_kms_helper_poll_disable(dev); | |
45 | nouveau_switcheroo_optimus_dsm(); | |
2d8b9ccb | 46 | nouveau_pmops_suspend(&pdev->dev); |
77145f1c BS |
47 | dev->switch_power_state = DRM_SWITCH_POWER_OFF; |
48 | } | |
49 | } | |
50 | ||
51 | static void | |
52 | nouveau_switcheroo_reprobe(struct pci_dev *pdev) | |
53 | { | |
54 | struct drm_device *dev = pci_get_drvdata(pdev); | |
55 | nouveau_fbcon_output_poll_changed(dev); | |
56 | } | |
57 | ||
58 | static bool | |
59 | nouveau_switcheroo_can_switch(struct pci_dev *pdev) | |
60 | { | |
61 | struct drm_device *dev = pci_get_drvdata(pdev); | |
62 | bool can_switch; | |
63 | ||
64 | spin_lock(&dev->count_lock); | |
65 | can_switch = (dev->open_count == 0); | |
66 | spin_unlock(&dev->count_lock); | |
67 | return can_switch; | |
68 | } | |
69 | ||
70 | static const struct vga_switcheroo_client_ops | |
71 | nouveau_switcheroo_ops = { | |
72 | .set_gpu_state = nouveau_switcheroo_set_state, | |
73 | .reprobe = nouveau_switcheroo_reprobe, | |
74 | .can_switch = nouveau_switcheroo_can_switch, | |
75 | }; | |
76 | ||
77 | void | |
78 | nouveau_vga_init(struct nouveau_drm *drm) | |
79 | { | |
80 | struct drm_device *dev = drm->dev; | |
81 | vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); | |
0d69704a | 82 | vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops, false); |
77145f1c BS |
83 | } |
84 | ||
85 | void | |
86 | nouveau_vga_fini(struct nouveau_drm *drm) | |
87 | { | |
88 | struct drm_device *dev = drm->dev; | |
89 | vga_switcheroo_unregister_client(dev->pdev); | |
90 | vga_client_register(dev->pdev, NULL, NULL, NULL); | |
91 | } | |
92 | ||
93 | ||
94 | void | |
95 | nouveau_vga_lastclose(struct drm_device *dev) | |
96 | { | |
97 | vga_switcheroo_process_delayed_switch(); | |
98 | } |