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 | { | |
967e7bde | 15 | struct nvif_device *device = &nouveau_drm(priv)->device; |
77145f1c | 16 | |
967e7bde BS |
17 | if (device->info.family == NV_DEVICE_INFO_V0_CURIE && |
18 | device->info.chipset >= 0x4c) | |
db2bec18 | 19 | nvif_wr32(device, 0x088060, state); |
77145f1c | 20 | else |
967e7bde | 21 | if (device->info.chipset >= 0x40) |
db2bec18 BS |
22 | nvif_wr32(device, 0x088054, state); |
23 | else | |
24 | nvif_wr32(device, 0x001854, state); | |
77145f1c BS |
25 | |
26 | if (state) | |
27 | return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | | |
28 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; | |
29 | else | |
30 | return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; | |
31 | } | |
32 | ||
33 | static void | |
34 | nouveau_switcheroo_set_state(struct pci_dev *pdev, | |
35 | enum vga_switcheroo_state state) | |
36 | { | |
37 | struct drm_device *dev = pci_get_drvdata(pdev); | |
77145f1c | 38 | |
5addcf0a DA |
39 | if ((nouveau_is_optimus() || nouveau_is_v1_dsm()) && state == VGA_SWITCHEROO_OFF) |
40 | return; | |
41 | ||
77145f1c BS |
42 | if (state == VGA_SWITCHEROO_ON) { |
43 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); | |
44 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | |
2d8b9ccb | 45 | nouveau_pmops_resume(&pdev->dev); |
77145f1c BS |
46 | drm_kms_helper_poll_enable(dev); |
47 | dev->switch_power_state = DRM_SWITCH_POWER_ON; | |
48 | } else { | |
49 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); | |
50 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | |
51 | drm_kms_helper_poll_disable(dev); | |
52 | nouveau_switcheroo_optimus_dsm(); | |
2d8b9ccb | 53 | nouveau_pmops_suspend(&pdev->dev); |
77145f1c BS |
54 | dev->switch_power_state = DRM_SWITCH_POWER_OFF; |
55 | } | |
56 | } | |
57 | ||
58 | static void | |
59 | nouveau_switcheroo_reprobe(struct pci_dev *pdev) | |
60 | { | |
61 | struct drm_device *dev = pci_get_drvdata(pdev); | |
62 | nouveau_fbcon_output_poll_changed(dev); | |
63 | } | |
64 | ||
65 | static bool | |
66 | nouveau_switcheroo_can_switch(struct pci_dev *pdev) | |
67 | { | |
68 | struct drm_device *dev = pci_get_drvdata(pdev); | |
77145f1c | 69 | |
fc8fd40e DV |
70 | /* |
71 | * FIXME: open_count is protected by drm_global_mutex but that would lead to | |
72 | * locking inversion with the driver load path. And the access here is | |
73 | * completely racy anyway. So don't bother with locking for now. | |
74 | */ | |
75 | return dev->open_count == 0; | |
77145f1c BS |
76 | } |
77 | ||
78 | static const struct vga_switcheroo_client_ops | |
79 | nouveau_switcheroo_ops = { | |
80 | .set_gpu_state = nouveau_switcheroo_set_state, | |
81 | .reprobe = nouveau_switcheroo_reprobe, | |
82 | .can_switch = nouveau_switcheroo_can_switch, | |
83 | }; | |
84 | ||
85 | void | |
86 | nouveau_vga_init(struct nouveau_drm *drm) | |
87 | { | |
88 | struct drm_device *dev = drm->dev; | |
5addcf0a | 89 | bool runtime = false; |
420b9469 AC |
90 | |
91 | /* only relevant for PCI devices */ | |
92 | if (!dev->pdev) | |
93 | return; | |
94 | ||
77145f1c | 95 | vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); |
5addcf0a DA |
96 | |
97 | if (nouveau_runtime_pm == 1) | |
98 | runtime = true; | |
99 | if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) | |
100 | runtime = true; | |
101 | vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops, runtime); | |
102 | ||
103 | if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus()) | |
104 | vga_switcheroo_init_domain_pm_ops(drm->dev->dev, &drm->vga_pm_domain); | |
77145f1c BS |
105 | } |
106 | ||
107 | void | |
108 | nouveau_vga_fini(struct nouveau_drm *drm) | |
109 | { | |
110 | struct drm_device *dev = drm->dev; | |
53beaa01 AD |
111 | bool runtime = false; |
112 | ||
113 | if (nouveau_runtime_pm == 1) | |
114 | runtime = true; | |
115 | if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) | |
116 | runtime = true; | |
117 | ||
77145f1c | 118 | vga_switcheroo_unregister_client(dev->pdev); |
53beaa01 AD |
119 | if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus()) |
120 | vga_switcheroo_fini_domain_pm_ops(drm->dev->dev); | |
77145f1c BS |
121 | vga_client_register(dev->pdev, NULL, NULL, NULL); |
122 | } | |
123 | ||
124 | ||
125 | void | |
126 | nouveau_vga_lastclose(struct drm_device *dev) | |
127 | { | |
128 | vga_switcheroo_process_delayed_switch(); | |
129 | } |