| @@ -1,31 +1,130 @@ | | | @@ -1,31 +1,130 @@ |
1 | /* $NetBSD: intel_acpi.c,v 1.2 2021/12/18 23:45:29 riastradh Exp $ */ | | 1 | /* $NetBSD: intel_acpi.c,v 1.3 2021/12/19 10:25:15 riastradh Exp $ */ |
2 | | | 2 | |
3 | // SPDX-License-Identifier: GPL-2.0 | | 3 | // SPDX-License-Identifier: GPL-2.0 |
4 | /* | | 4 | /* |
5 | * Intel ACPI functions | | 5 | * Intel ACPI functions |
6 | * | | 6 | * |
7 | * _DSM related code stolen from nouveau_acpi.c. | | 7 | * _DSM related code stolen from nouveau_acpi.c. |
8 | */ | | 8 | */ |
9 | | | 9 | |
10 | #include <sys/cdefs.h> | | 10 | #include <sys/cdefs.h> |
11 | __KERNEL_RCSID(0, "$NetBSD: intel_acpi.c,v 1.2 2021/12/18 23:45:29 riastradh Exp $"); | | 11 | __KERNEL_RCSID(0, "$NetBSD: intel_acpi.c,v 1.3 2021/12/19 10:25:15 riastradh Exp $"); |
12 | | | 12 | |
13 | #include <linux/pci.h> | | 13 | #include <linux/pci.h> |
14 | #include <linux/acpi.h> | | 14 | #include <linux/acpi.h> |
15 | | | 15 | |
16 | #include "i915_drv.h" | | 16 | #include "i915_drv.h" |
17 | #include "intel_acpi.h" | | 17 | #include "intel_acpi.h" |
18 | | | 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 | #define acpi_handle ACPI_HANDLE |
| | | 26 | #define buffer Buffer |
| | | 27 | #define elements Elements |
| | | 28 | #define integer Integer |
| | | 29 | #define package Package |
| | | 30 | #define value Value |
| | | 31 | |
| | | 32 | static ACPI_OBJECT * |
| | | 33 | acpi_evaluate_dsm(ACPI_HANDLE handle, const uint8_t *uuid, int rev, int func, |
| | | 34 | ACPI_OBJECT *argv4) |
| | | 35 | { |
| | | 36 | ACPI_OBJECT_LIST arg; |
| | | 37 | ACPI_OBJECT params[4]; |
| | | 38 | ACPI_BUFFER buf; |
| | | 39 | ACPI_STATUS rv; |
| | | 40 | |
| | | 41 | if (handle == NULL) |
| | | 42 | handle = ACPI_ROOT_OBJECT; |
| | | 43 | |
| | | 44 | arg.Count = 4; |
| | | 45 | arg.Pointer = params; |
| | | 46 | params[0].Type = ACPI_TYPE_BUFFER; |
| | | 47 | params[0].Buffer.Length = 16; |
| | | 48 | params[0].Buffer.Pointer = (char *)__UNCONST(uuid); |
| | | 49 | params[1].Type = ACPI_TYPE_INTEGER; |
| | | 50 | params[1].Integer.Value = rev; |
| | | 51 | params[2].Type = ACPI_TYPE_INTEGER; |
| | | 52 | params[2].Integer.Value = func; |
| | | 53 | if (argv4 != NULL) { |
| | | 54 | params[3] = *argv4; |
| | | 55 | } else { |
| | | 56 | params[3].Type = ACPI_TYPE_PACKAGE; |
| | | 57 | params[3].Package.Count = 0; |
| | | 58 | params[3].Package.Elements = NULL; |
| | | 59 | } |
| | | 60 | |
| | | 61 | buf.Pointer = NULL; |
| | | 62 | buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; |
| | | 63 | |
| | | 64 | rv = AcpiEvaluateObject(handle, "_DSM", &arg, &buf); |
| | | 65 | if (ACPI_SUCCESS(rv)) |
| | | 66 | return (ACPI_OBJECT *)buf.Pointer; |
| | | 67 | return NULL; |
| | | 68 | } |
| | | 69 | |
| | | 70 | static inline ACPI_OBJECT * |
| | | 71 | acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const uint8_t *uuid, int rev, |
| | | 72 | int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type) |
| | | 73 | { |
| | | 74 | ACPI_OBJECT *obj; |
| | | 75 | |
| | | 76 | obj = acpi_evaluate_dsm(handle, uuid, rev, func, argv4); |
| | | 77 | if (obj != NULL && obj->Type != type) { |
| | | 78 | ACPI_FREE(obj); |
| | | 79 | obj = NULL; |
| | | 80 | } |
| | | 81 | return obj; |
| | | 82 | } |
| | | 83 | |
| | | 84 | #define ACPI_INIT_DSM_ARGV4(cnt, eles) \ |
| | | 85 | { \ |
| | | 86 | .Package.Type = ACPI_TYPE_PACKAGE, \ |
| | | 87 | .Package.Count = (cnt), \ |
| | | 88 | .Package.Elements = (eles) \ |
| | | 89 | } |
| | | 90 | |
| | | 91 | static bool |
| | | 92 | acpi_check_dsm(ACPI_HANDLE handle, const uint8_t *uuid, int rev, uint64_t funcs) |
| | | 93 | { |
| | | 94 | ACPI_OBJECT *obj; |
| | | 95 | uint64_t mask = 0; |
| | | 96 | int i; |
| | | 97 | |
| | | 98 | if (funcs == 0) |
| | | 99 | return false; |
| | | 100 | |
| | | 101 | obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); |
| | | 102 | if (obj == NULL) |
| | | 103 | return false; |
| | | 104 | |
| | | 105 | if (obj->Type == ACPI_TYPE_INTEGER) |
| | | 106 | mask = obj->Integer.Value; |
| | | 107 | else if (obj->Type == ACPI_TYPE_BUFFER) |
| | | 108 | for (i = 0; i < obj->Buffer.Length && i < 8; i++) |
| | | 109 | mask |= (uint64_t)obj->Buffer.Pointer[i] << (i * 8); |
| | | 110 | ACPI_FREE(obj); |
| | | 111 | |
| | | 112 | if ((mask & 0x1) == 0x1 && (mask & funcs) == funcs) |
| | | 113 | return true; |
| | | 114 | return false; |
| | | 115 | } |
| | | 116 | #endif |
| | | 117 | |
19 | #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ | | 118 | #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ |
20 | #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ | | 119 | #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ |
21 | | | 120 | |
22 | static const guid_t intel_dsm_guid = | | 121 | static const guid_t intel_dsm_guid = |
23 | GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f, | | 122 | GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f, |
24 | 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c); | | 123 | 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c); |
25 | | | 124 | |
26 | static char *intel_dsm_port_name(u8 id) | | 125 | static char *intel_dsm_port_name(u8 id) |
27 | { | | 126 | { |
28 | switch (id) { | | 127 | switch (id) { |
29 | case 0: | | 128 | case 0: |
30 | return "Reserved"; | | 129 | return "Reserved"; |
31 | case 1: | | 130 | case 1: |
| @@ -68,96 +167,167 @@ static char *intel_dsm_mux_type(u8 type) | | | @@ -68,96 +167,167 @@ static char *intel_dsm_mux_type(u8 type) |
68 | return "No MUX, iGPU only"; | | 167 | return "No MUX, iGPU only"; |
69 | case 2: | | 168 | case 2: |
70 | return "No MUX, dGPU only"; | | 169 | return "No MUX, dGPU only"; |
71 | case 3: | | 170 | case 3: |
72 | return "MUXed between iGPU and dGPU"; | | 171 | return "MUXed between iGPU and dGPU"; |
73 | default: | | 172 | default: |
74 | return "bad type"; | | 173 | return "bad type"; |
75 | } | | 174 | } |
76 | } | | 175 | } |
77 | | | 176 | |
78 | static void intel_dsm_platform_mux_info(acpi_handle dhandle) | | 177 | static void intel_dsm_platform_mux_info(acpi_handle dhandle) |
79 | { | | 178 | { |
80 | int i; | | 179 | int i; |
| | | 180 | #ifdef __NetBSD__ |
| | | 181 | ACPI_OBJECT *pkg, *connector_count; |
| | | 182 | #else |
81 | union acpi_object *pkg, *connector_count; | | 183 | union acpi_object *pkg, *connector_count; |
| | | 184 | #endif |
82 | | | 185 | |
83 | pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid, | | 186 | pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid, |
84 | INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, | | 187 | INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, |
85 | NULL, ACPI_TYPE_PACKAGE); | | 188 | NULL, ACPI_TYPE_PACKAGE); |
86 | if (!pkg) { | | 189 | if (!pkg) { |
87 | DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); | | 190 | DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); |
88 | return; | | 191 | return; |
89 | } | | 192 | } |
90 | | | 193 | |
91 | connector_count = &pkg->package.elements[0]; | | 194 | connector_count = &pkg->package.elements[0]; |
92 | DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", | | 195 | DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", |
93 | (unsigned long long)connector_count->integer.value); | | 196 | (unsigned long long)connector_count->integer.value); |
94 | for (i = 1; i < pkg->package.count; i++) { | | 197 | for (i = 1; i < pkg->package.count; i++) { |
| | | 198 | #ifdef __NetBSD__ |
| | | 199 | ACPI_OBJECT *obj = &pkg->package.elements[i]; |
| | | 200 | ACPI_OBJECT *connector_id = &obj->package.elements[0]; |
| | | 201 | ACPI_OBJECT *info = &obj->package.elements[1]; |
| | | 202 | #else |
95 | union acpi_object *obj = &pkg->package.elements[i]; | | 203 | union acpi_object *obj = &pkg->package.elements[i]; |
96 | union acpi_object *connector_id = &obj->package.elements[0]; | | 204 | union acpi_object *connector_id = &obj->package.elements[0]; |
97 | union acpi_object *info = &obj->package.elements[1]; | | 205 | union acpi_object *info = &obj->package.elements[1]; |
| | | 206 | #endif |
98 | DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", | | 207 | DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", |
99 | (unsigned long long)connector_id->integer.value); | | 208 | (unsigned long long)connector_id->integer.value); |
100 | DRM_DEBUG_DRIVER(" port id: %s\n", | | 209 | DRM_DEBUG_DRIVER(" port id: %s\n", |
101 | intel_dsm_port_name(info->buffer.pointer[0])); | | 210 | intel_dsm_port_name(info->buffer.pointer[0])); |
102 | DRM_DEBUG_DRIVER(" display mux info: %s\n", | | 211 | DRM_DEBUG_DRIVER(" display mux info: %s\n", |
103 | intel_dsm_mux_type(info->buffer.pointer[1])); | | 212 | intel_dsm_mux_type(info->buffer.pointer[1])); |
104 | DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", | | 213 | DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", |
105 | intel_dsm_mux_type(info->buffer.pointer[2])); | | 214 | intel_dsm_mux_type(info->buffer.pointer[2])); |
106 | DRM_DEBUG_DRIVER(" hpd mux info: %s\n", | | 215 | DRM_DEBUG_DRIVER(" hpd mux info: %s\n", |
107 | intel_dsm_mux_type(info->buffer.pointer[3])); | | 216 | intel_dsm_mux_type(info->buffer.pointer[3])); |
108 | } | | 217 | } |
109 | | | 218 | |
110 | ACPI_FREE(pkg); | | 219 | ACPI_FREE(pkg); |
111 | } | | 220 | } |
112 | | | 221 | |
| | | 222 | #ifdef __NetBSD__ |
| | | 223 | static bool intel_dsm_pci_probe(ACPI_HANDLE dhandle) |
| | | 224 | #else |
113 | static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev) | | 225 | static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev) |
| | | 226 | #endif |
114 | { | | 227 | { |
| | | 228 | #ifndef __NetBSD__ |
115 | acpi_handle dhandle; | | 229 | acpi_handle dhandle; |
116 | | | 230 | |
117 | dhandle = ACPI_HANDLE(&pdev->dev); | | 231 | dhandle = ACPI_HANDLE(&pdev->dev); |
118 | if (!dhandle) | | 232 | if (!dhandle) |
119 | return NULL; | | 233 | return NULL; |
| | | 234 | #endif |
120 | | | 235 | |
121 | if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, | | 236 | if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, |
122 | 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { | | 237 | 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { |
123 | DRM_DEBUG_KMS("no _DSM method for intel device\n"); | | 238 | DRM_DEBUG_KMS("no _DSM method for intel device\n"); |
124 | return NULL; | | 239 | return NULL; |
125 | } | | 240 | } |
126 | | | 241 | |
127 | intel_dsm_platform_mux_info(dhandle); | | 242 | intel_dsm_platform_mux_info(dhandle); |
128 | | | 243 | |
129 | return dhandle; | | 244 | return dhandle; |
130 | } | | 245 | } |
131 | | | 246 | |
| | | 247 | #ifdef __NetBSD__ |
| | | 248 | |
| | | 249 | static int vga_count; |
| | | 250 | static bool has_dsm; |
| | | 251 | |
| | | 252 | /* XXX from sys/dev/pci/vga_pcivar.h */ |
| | | 253 | #define DEVICE_IS_VGA_PCI(class, id) \ |
| | | 254 | (((PCI_CLASS(class) == PCI_CLASS_DISPLAY && \ |
| | | 255 | PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_VGA) || \ |
| | | 256 | (PCI_CLASS(class) == PCI_CLASS_PREHISTORIC && \ |
| | | 257 | PCI_SUBCLASS(class) == PCI_SUBCLASS_PREHISTORIC_VGA)) ? 1 : 0) |
| | | 258 | |
| | | 259 | static int |
| | | 260 | intel_dsm_vga_match(const struct pci_attach_args *pa) |
| | | 261 | { |
| | | 262 | |
| | | 263 | if (!DEVICE_IS_VGA_PCI(pa->pa_class, pa->pa_id)) |
| | | 264 | return 0; |
| | | 265 | |
| | | 266 | vga_count++; |
| | | 267 | struct acpi_devnode *node = acpi_pcidev_find(0 /*XXX segment*/, |
| | | 268 | pa->pa_bus, pa->pa_device, pa->pa_function); |
| | | 269 | if (node != NULL) |
| | | 270 | has_dsm |= intel_dsm_pci_probe(node->ad_handle); |
| | | 271 | return 0; |
| | | 272 | } |
| | | 273 | |
| | | 274 | static bool intel_dsm_detect(struct drm_device *dev) |
| | | 275 | { |
| | | 276 | char acpi_method_name[255] = { 0 }; |
| | | 277 | |
| | | 278 | vga_count = 0; |
| | | 279 | has_dsm = false; |
| | | 280 | pci_find_device(&dev->pdev->pd_pa, intel_dsm_vga_match); |
| | | 281 | |
| | | 282 | if (vga_count == 2 && has_dsm) { |
| | | 283 | const char *name = acpi_name(intel_dsm_priv.dhandle); |
| | | 284 | strlcpy(acpi_method_name, name, sizeof(acpi_method_name)); |
| | | 285 | DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", |
| | | 286 | acpi_method_name); |
| | | 287 | return true; |
| | | 288 | } |
| | | 289 | |
| | | 290 | return false; |
| | | 291 | } |
| | | 292 | #else |
132 | static bool intel_dsm_detect(void) | | 293 | static bool intel_dsm_detect(void) |
133 | { | | 294 | { |
134 | acpi_handle dhandle = NULL; | | 295 | acpi_handle dhandle = NULL; |
135 | char acpi_method_name[255] = { 0 }; | | 296 | char acpi_method_name[255] = { 0 }; |
136 | struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; | | 297 | struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; |
137 | struct pci_dev *pdev = NULL; | | 298 | struct pci_dev *pdev = NULL; |
138 | int vga_count = 0; | | 299 | int vga_count = 0; |
139 | | | 300 | |
140 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { | | 301 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { |
141 | vga_count++; | | 302 | vga_count++; |
142 | dhandle = intel_dsm_pci_probe(pdev) ?: dhandle; | | 303 | dhandle = intel_dsm_pci_probe(pdev) ?: dhandle; |
143 | } | | 304 | } |
144 | | | 305 | |
145 | if (vga_count == 2 && dhandle) { | | 306 | if (vga_count == 2 && dhandle) { |
146 | acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer); | | 307 | acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer); |
147 | DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n", | | 308 | DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n", |
148 | acpi_method_name); | | 309 | acpi_method_name); |
149 | return true; | | 310 | return true; |
150 | } | | 311 | } |
151 | | | 312 | |
152 | return false; | | 313 | return false; |
153 | } | | 314 | } |
| | | 315 | #endif |
154 | | | 316 | |
| | | 317 | #ifdef __NetBSD__ |
| | | 318 | void intel_register_dsm_handler(struct drm_i915_private *i915) |
| | | 319 | { |
| | | 320 | if (!intel_dsm_detect(i915->base.pdev)) |
| | | 321 | return; |
| | | 322 | } |
| | | 323 | #else |
155 | void intel_register_dsm_handler(void) | | 324 | void intel_register_dsm_handler(void) |
156 | { | | 325 | { |
157 | if (!intel_dsm_detect()) | | 326 | if (!intel_dsm_detect()) |
158 | return; | | 327 | return; |
159 | } | | 328 | } |
| | | 329 | #endif |
160 | | | 330 | |
161 | void intel_unregister_dsm_handler(void) | | 331 | void intel_unregister_dsm_handler(void) |
162 | { | | 332 | { |
163 | } | | 333 | } |