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