1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/vgaarb.h>
3 #include <linux/vga_switcheroo.h>
4 
5 #include <drm/drmP.h>
6 #include <drm/drm_crtc_helper.h>
7 #include <drm/drm_fb_helper.h>
8 
9 #include "nouveau_drv.h"
10 #include "nouveau_acpi.h"
11 #include "nouveau_fbcon.h"
12 #include "nouveau_vga.h"
13 
14 static unsigned int
15 nouveau_vga_set_decode(void *priv, bool state)
16 {
17 	struct nouveau_drm *drm = nouveau_drm(priv);
18 	struct nvif_object *device = &drm->client.device.object;
19 
20 	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE &&
21 	    drm->client.device.info.chipset >= 0x4c)
22 		nvif_wr32(device, 0x088060, state);
23 	else
24 	if (drm->client.device.info.chipset >= 0x40)
25 		nvif_wr32(device, 0x088054, state);
26 	else
27 		nvif_wr32(device, 0x001854, state);
28 
29 	if (state)
30 		return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
31 		       VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
32 	else
33 		return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
34 }
35 
36 static void
37 nouveau_switcheroo_set_state(struct pci_dev *pdev,
38 			     enum vga_switcheroo_state state)
39 {
40 	struct drm_device *dev = pci_get_drvdata(pdev);
41 
42 	if ((nouveau_is_optimus() || nouveau_is_v1_dsm()) && state == VGA_SWITCHEROO_OFF)
43 		return;
44 
45 	if (state == VGA_SWITCHEROO_ON) {
46 		pr_err("VGA switcheroo: switched nouveau on\n");
47 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
48 		nouveau_pmops_resume(&pdev->dev);
49 		drm_kms_helper_poll_enable(dev);
50 		dev->switch_power_state = DRM_SWITCH_POWER_ON;
51 	} else {
52 		pr_err("VGA switcheroo: switched nouveau off\n");
53 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
54 		drm_kms_helper_poll_disable(dev);
55 		nouveau_switcheroo_optimus_dsm();
56 		nouveau_pmops_suspend(&pdev->dev);
57 		dev->switch_power_state = DRM_SWITCH_POWER_OFF;
58 	}
59 }
60 
61 static void
62 nouveau_switcheroo_reprobe(struct pci_dev *pdev)
63 {
64 	struct drm_device *dev = pci_get_drvdata(pdev);
65 	drm_fb_helper_output_poll_changed(dev);
66 }
67 
68 static bool
69 nouveau_switcheroo_can_switch(struct pci_dev *pdev)
70 {
71 	struct drm_device *dev = pci_get_drvdata(pdev);
72 
73 	/*
74 	 * FIXME: open_count is protected by drm_global_mutex but that would lead to
75 	 * locking inversion with the driver load path. And the access here is
76 	 * completely racy anyway. So don't bother with locking for now.
77 	 */
78 	return dev->open_count == 0;
79 }
80 
81 static const struct vga_switcheroo_client_ops
82 nouveau_switcheroo_ops = {
83 	.set_gpu_state = nouveau_switcheroo_set_state,
84 	.reprobe = nouveau_switcheroo_reprobe,
85 	.can_switch = nouveau_switcheroo_can_switch,
86 };
87 
88 void
89 nouveau_vga_init(struct nouveau_drm *drm)
90 {
91 	struct drm_device *dev = drm->dev;
92 	bool runtime = nouveau_pmops_runtime();
93 
94 	/* only relevant for PCI devices */
95 	if (!dev->pdev)
96 		return;
97 
98 	vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
99 
100 	/* don't register Thunderbolt eGPU with vga_switcheroo */
101 	if (pci_is_thunderbolt_attached(dev->pdev))
102 		return;
103 
104 	vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops, runtime);
105 
106 	if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus())
107 		vga_switcheroo_init_domain_pm_ops(drm->dev->dev, &drm->vga_pm_domain);
108 }
109 
110 void
111 nouveau_vga_fini(struct nouveau_drm *drm)
112 {
113 	struct drm_device *dev = drm->dev;
114 	bool runtime = nouveau_pmops_runtime();
115 
116 	/* only relevant for PCI devices */
117 	if (!dev->pdev)
118 		return;
119 
120 	vga_client_register(dev->pdev, NULL, NULL, NULL);
121 
122 	if (pci_is_thunderbolt_attached(dev->pdev))
123 		return;
124 
125 	vga_switcheroo_unregister_client(dev->pdev);
126 	if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus())
127 		vga_switcheroo_fini_domain_pm_ops(drm->dev->dev);
128 }
129 
130 
131 void
132 nouveau_vga_lastclose(struct drm_device *dev)
133 {
134 	vga_switcheroo_process_delayed_switch();
135 }
136