xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/i915/display/intel_acpi.c (revision 7282f92ed4674909e9296ba6e60a08e3bc23e342)
1 /*	$NetBSD: intel_acpi.c,v 1.8 2022/02/27 14:22:42 riastradh Exp $	*/
2 
3 // SPDX-License-Identifier: GPL-2.0
4 /*
5  * Intel ACPI functions
6  *
7  * _DSM related code stolen from nouveau_acpi.c.
8  */
9 
10 #include <sys/cdefs.h>
11 __KERNEL_RCSID(0, "$NetBSD: intel_acpi.c,v 1.8 2022/02/27 14:22:42 riastradh Exp $");
12 
13 #include <linux/pci.h>
14 #include <linux/acpi.h>
15 
16 #include "i915_drv.h"
17 #include "intel_acpi.h"
18 
19 #ifdef __NetBSD__
20 
21 #include <dev/acpi/acpireg.h>
22 #define _COMPONENT ACPI_BUTTON_COMPONENT
23 ACPI_MODULE_NAME("acpi_intel_brightness")
24 
25 #include <dev/acpi/acpi_pci.h>
26 
27 #include <linux/nbsd-namespace-acpi.h>
28 #endif
29 
30 #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
31 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
32 
33 static const guid_t intel_dsm_guid =
34 	GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
35 		  0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
36 
intel_dsm_port_name(u8 id)37 static const char *intel_dsm_port_name(u8 id)
38 {
39 	switch (id) {
40 	case 0:
41 		return "Reserved";
42 	case 1:
43 		return "Analog VGA";
44 	case 2:
45 		return "LVDS";
46 	case 3:
47 		return "Reserved";
48 	case 4:
49 		return "HDMI/DVI_B";
50 	case 5:
51 		return "HDMI/DVI_C";
52 	case 6:
53 		return "HDMI/DVI_D";
54 	case 7:
55 		return "DisplayPort_A";
56 	case 8:
57 		return "DisplayPort_B";
58 	case 9:
59 		return "DisplayPort_C";
60 	case 0xa:
61 		return "DisplayPort_D";
62 	case 0xb:
63 	case 0xc:
64 	case 0xd:
65 		return "Reserved";
66 	case 0xe:
67 		return "WiDi";
68 	default:
69 		return "bad type";
70 	}
71 }
72 
intel_dsm_mux_type(u8 type)73 static const char *intel_dsm_mux_type(u8 type)
74 {
75 	switch (type) {
76 	case 0:
77 		return "unknown";
78 	case 1:
79 		return "No MUX, iGPU only";
80 	case 2:
81 		return "No MUX, dGPU only";
82 	case 3:
83 		return "MUXed between iGPU and dGPU";
84 	default:
85 		return "bad type";
86 	}
87 }
88 
intel_dsm_platform_mux_info(acpi_handle dhandle)89 static void intel_dsm_platform_mux_info(acpi_handle dhandle)
90 {
91 	int i;
92 	union acpi_object *pkg, *connector_count;
93 
94 	pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid,
95 			INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
96 			NULL, ACPI_TYPE_PACKAGE);
97 	if (!pkg) {
98 		DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
99 		return;
100 	}
101 
102 	connector_count = &pkg->package.elements[0];
103 	DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
104 		  (unsigned long long)connector_count->integer.value);
105 	for (i = 1; i < pkg->package.count; i++) {
106 		union acpi_object *obj = &pkg->package.elements[i];
107 		union acpi_object *connector_id = &obj->package.elements[0];
108 		union acpi_object *info = &obj->package.elements[1];
109 		DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
110 			  (unsigned long long)connector_id->integer.value);
111 		DRM_DEBUG_DRIVER("  port id: %s\n",
112 		       intel_dsm_port_name(info->buffer.pointer[0]));
113 		DRM_DEBUG_DRIVER("  display mux info: %s\n",
114 		       intel_dsm_mux_type(info->buffer.pointer[1]));
115 		DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
116 		       intel_dsm_mux_type(info->buffer.pointer[2]));
117 		DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
118 		       intel_dsm_mux_type(info->buffer.pointer[3]));
119 	}
120 
121 	ACPI_FREE(pkg);
122 }
123 
124 #ifdef __NetBSD__
intel_dsm_pci_probe(ACPI_HANDLE dhandle)125 static ACPI_HANDLE intel_dsm_pci_probe(ACPI_HANDLE dhandle)
126 #else
127 static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev)
128 #endif
129 {
130 #ifndef __NetBSD__
131 	acpi_handle dhandle;
132 
133 	dhandle = ACPI_HANDLE(&pdev->dev);
134 	if (!dhandle)
135 		return NULL;
136 #endif
137 
138 	if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
139 			    1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
140 		DRM_DEBUG_KMS("no _DSM method for intel device\n");
141 		return NULL;
142 	}
143 
144 	intel_dsm_platform_mux_info(dhandle);
145 
146 	return dhandle;
147 }
148 
149 #ifdef __NetBSD__
150 
151 static int vga_count;
152 static ACPI_HANDLE intel_dsm_handle;
153 
154 /* XXX from sys/dev/pci/vga_pcivar.h */
155 #define	DEVICE_IS_VGA_PCI(class, id)					\
156 	    (((PCI_CLASS(class) == PCI_CLASS_DISPLAY &&			\
157 	      PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_VGA) ||	\
158 	     (PCI_CLASS(class) == PCI_CLASS_PREHISTORIC &&		\
159 	      PCI_SUBCLASS(class) == PCI_SUBCLASS_PREHISTORIC_VGA)) ? 1 : 0)
160 
161 static int
intel_dsm_vga_match(const struct pci_attach_args * pa)162 intel_dsm_vga_match(const struct pci_attach_args *pa)
163 {
164 
165 	if (!DEVICE_IS_VGA_PCI(pa->pa_class, pa->pa_id))
166 		return 0;
167 
168 	vga_count++;
169 	struct acpi_devnode *node =
170 	    acpi_pcidev_find(pci_get_segment(pa->pa_pc),
171 		pa->pa_bus, pa->pa_device, pa->pa_function);
172 	if (node != NULL && intel_dsm_handle == NULL)
173 		intel_dsm_handle = intel_dsm_pci_probe(node->ad_handle);
174 	return 0;
175 }
176 
intel_dsm_detect(struct drm_device * dev)177 static bool intel_dsm_detect(struct drm_device *dev)
178 {
179 	char acpi_method_name[255] = { 0 };
180 
181 	vga_count = 0;
182 	pci_find_device(&dev->pdev->pd_pa, intel_dsm_vga_match);
183 
184 	if (vga_count == 2 && intel_dsm_handle) {
185 		const char *name = acpi_name(intel_dsm_handle);
186 		strlcpy(acpi_method_name, name, sizeof(acpi_method_name));
187 		DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
188 				 acpi_method_name);
189 		return true;
190 	}
191 
192 	return false;
193 }
194 #else
intel_dsm_detect(void)195 static bool intel_dsm_detect(void)
196 {
197 	acpi_handle dhandle = NULL;
198 	char acpi_method_name[255] = { 0 };
199 	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
200 	struct pci_dev *pdev = NULL;
201 	int vga_count = 0;
202 
203 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
204 		vga_count++;
205 		dhandle = intel_dsm_pci_probe(pdev) ?: dhandle;
206 	}
207 
208 	if (vga_count == 2 && dhandle) {
209 		acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer);
210 		DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
211 				 acpi_method_name);
212 		return true;
213 	}
214 
215 	return false;
216 }
217 #endif
218 
219 #ifdef __NetBSD__
intel_register_dsm_handler(struct drm_i915_private * i915)220 void intel_register_dsm_handler(struct drm_i915_private *i915)
221 {
222 	if (!intel_dsm_detect(&i915->drm))
223 		return;
224 }
225 #else
intel_register_dsm_handler(void)226 void intel_register_dsm_handler(void)
227 {
228 	if (!intel_dsm_detect())
229 		return;
230 }
231 #endif
232 
intel_unregister_dsm_handler(void)233 void intel_unregister_dsm_handler(void)
234 {
235 }
236