Home | History | Annotate | Line # | Download | only in display
      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