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