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