Home | History | Annotate | Line # | Download | only in display
intel_acpi.c revision 1.2
      1 /*	$NetBSD: intel_acpi.c,v 1.2 2021/12/18 23:45:29 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.2 2021/12/18 23:45:29 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 #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
     20 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
     21 
     22 static const guid_t intel_dsm_guid =
     23 	GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
     24 		  0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
     25 
     26 static char *intel_dsm_port_name(u8 id)
     27 {
     28 	switch (id) {
     29 	case 0:
     30 		return "Reserved";
     31 	case 1:
     32 		return "Analog VGA";
     33 	case 2:
     34 		return "LVDS";
     35 	case 3:
     36 		return "Reserved";
     37 	case 4:
     38 		return "HDMI/DVI_B";
     39 	case 5:
     40 		return "HDMI/DVI_C";
     41 	case 6:
     42 		return "HDMI/DVI_D";
     43 	case 7:
     44 		return "DisplayPort_A";
     45 	case 8:
     46 		return "DisplayPort_B";
     47 	case 9:
     48 		return "DisplayPort_C";
     49 	case 0xa:
     50 		return "DisplayPort_D";
     51 	case 0xb:
     52 	case 0xc:
     53 	case 0xd:
     54 		return "Reserved";
     55 	case 0xe:
     56 		return "WiDi";
     57 	default:
     58 		return "bad type";
     59 	}
     60 }
     61 
     62 static char *intel_dsm_mux_type(u8 type)
     63 {
     64 	switch (type) {
     65 	case 0:
     66 		return "unknown";
     67 	case 1:
     68 		return "No MUX, iGPU only";
     69 	case 2:
     70 		return "No MUX, dGPU only";
     71 	case 3:
     72 		return "MUXed between iGPU and dGPU";
     73 	default:
     74 		return "bad type";
     75 	}
     76 }
     77 
     78 static void intel_dsm_platform_mux_info(acpi_handle dhandle)
     79 {
     80 	int i;
     81 	union acpi_object *pkg, *connector_count;
     82 
     83 	pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid,
     84 			INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
     85 			NULL, ACPI_TYPE_PACKAGE);
     86 	if (!pkg) {
     87 		DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
     88 		return;
     89 	}
     90 
     91 	connector_count = &pkg->package.elements[0];
     92 	DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
     93 		  (unsigned long long)connector_count->integer.value);
     94 	for (i = 1; i < pkg->package.count; i++) {
     95 		union acpi_object *obj = &pkg->package.elements[i];
     96 		union acpi_object *connector_id = &obj->package.elements[0];
     97 		union acpi_object *info = &obj->package.elements[1];
     98 		DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
     99 			  (unsigned long long)connector_id->integer.value);
    100 		DRM_DEBUG_DRIVER("  port id: %s\n",
    101 		       intel_dsm_port_name(info->buffer.pointer[0]));
    102 		DRM_DEBUG_DRIVER("  display mux info: %s\n",
    103 		       intel_dsm_mux_type(info->buffer.pointer[1]));
    104 		DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
    105 		       intel_dsm_mux_type(info->buffer.pointer[2]));
    106 		DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
    107 		       intel_dsm_mux_type(info->buffer.pointer[3]));
    108 	}
    109 
    110 	ACPI_FREE(pkg);
    111 }
    112 
    113 static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev)
    114 {
    115 	acpi_handle dhandle;
    116 
    117 	dhandle = ACPI_HANDLE(&pdev->dev);
    118 	if (!dhandle)
    119 		return NULL;
    120 
    121 	if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
    122 			    1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
    123 		DRM_DEBUG_KMS("no _DSM method for intel device\n");
    124 		return NULL;
    125 	}
    126 
    127 	intel_dsm_platform_mux_info(dhandle);
    128 
    129 	return dhandle;
    130 }
    131 
    132 static bool intel_dsm_detect(void)
    133 {
    134 	acpi_handle dhandle = NULL;
    135 	char acpi_method_name[255] = { 0 };
    136 	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
    137 	struct pci_dev *pdev = NULL;
    138 	int vga_count = 0;
    139 
    140 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
    141 		vga_count++;
    142 		dhandle = intel_dsm_pci_probe(pdev) ?: dhandle;
    143 	}
    144 
    145 	if (vga_count == 2 && dhandle) {
    146 		acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer);
    147 		DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
    148 				 acpi_method_name);
    149 		return true;
    150 	}
    151 
    152 	return false;
    153 }
    154 
    155 void intel_register_dsm_handler(void)
    156 {
    157 	if (!intel_dsm_detect())
    158 		return;
    159 }
    160 
    161 void intel_unregister_dsm_handler(void)
    162 {
    163 }
    164