15d0b1887SFrançois Tigeot /*
25d0b1887SFrançois Tigeot * Intel ACPI functions
35d0b1887SFrançois Tigeot *
45d0b1887SFrançois Tigeot * _DSM related code stolen from nouveau_acpi.c.
55d0b1887SFrançois Tigeot */
65d0b1887SFrançois Tigeot #include <linux/pci.h>
7bf017597SFrançois Tigeot #include <linux/acpi.h>
85d0b1887SFrançois Tigeot #include <drm/drmP.h>
95d0b1887SFrançois Tigeot #include "i915_drv.h"
105d0b1887SFrançois Tigeot
115d0b1887SFrançois Tigeot #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
125d0b1887SFrançois Tigeot #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
135d0b1887SFrançois Tigeot
145d0b1887SFrançois Tigeot #if 0
155d0b1887SFrançois Tigeot static struct intel_dsm_priv {
165d0b1887SFrançois Tigeot acpi_handle dhandle;
175d0b1887SFrançois Tigeot } intel_dsm_priv;
185d0b1887SFrançois Tigeot
19*3f2dd94aSFrançois Tigeot static const guid_t intel_dsm_guid =
20*3f2dd94aSFrançois Tigeot GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
21*3f2dd94aSFrançois Tigeot 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
225d0b1887SFrançois Tigeot
235d0b1887SFrançois Tigeot static char *intel_dsm_port_name(u8 id)
245d0b1887SFrançois Tigeot {
255d0b1887SFrançois Tigeot switch (id) {
265d0b1887SFrançois Tigeot case 0:
275d0b1887SFrançois Tigeot return "Reserved";
285d0b1887SFrançois Tigeot case 1:
295d0b1887SFrançois Tigeot return "Analog VGA";
305d0b1887SFrançois Tigeot case 2:
315d0b1887SFrançois Tigeot return "LVDS";
325d0b1887SFrançois Tigeot case 3:
335d0b1887SFrançois Tigeot return "Reserved";
345d0b1887SFrançois Tigeot case 4:
355d0b1887SFrançois Tigeot return "HDMI/DVI_B";
365d0b1887SFrançois Tigeot case 5:
375d0b1887SFrançois Tigeot return "HDMI/DVI_C";
385d0b1887SFrançois Tigeot case 6:
395d0b1887SFrançois Tigeot return "HDMI/DVI_D";
405d0b1887SFrançois Tigeot case 7:
415d0b1887SFrançois Tigeot return "DisplayPort_A";
425d0b1887SFrançois Tigeot case 8:
435d0b1887SFrançois Tigeot return "DisplayPort_B";
445d0b1887SFrançois Tigeot case 9:
455d0b1887SFrançois Tigeot return "DisplayPort_C";
465d0b1887SFrançois Tigeot case 0xa:
475d0b1887SFrançois Tigeot return "DisplayPort_D";
485d0b1887SFrançois Tigeot case 0xb:
495d0b1887SFrançois Tigeot case 0xc:
505d0b1887SFrançois Tigeot case 0xd:
515d0b1887SFrançois Tigeot return "Reserved";
525d0b1887SFrançois Tigeot case 0xe:
535d0b1887SFrançois Tigeot return "WiDi";
545d0b1887SFrançois Tigeot default:
555d0b1887SFrançois Tigeot return "bad type";
565d0b1887SFrançois Tigeot }
575d0b1887SFrançois Tigeot }
585d0b1887SFrançois Tigeot
595d0b1887SFrançois Tigeot static char *intel_dsm_mux_type(u8 type)
605d0b1887SFrançois Tigeot {
615d0b1887SFrançois Tigeot switch (type) {
625d0b1887SFrançois Tigeot case 0:
635d0b1887SFrançois Tigeot return "unknown";
645d0b1887SFrançois Tigeot case 1:
655d0b1887SFrançois Tigeot return "No MUX, iGPU only";
665d0b1887SFrançois Tigeot case 2:
675d0b1887SFrançois Tigeot return "No MUX, dGPU only";
685d0b1887SFrançois Tigeot case 3:
695d0b1887SFrançois Tigeot return "MUXed between iGPU and dGPU";
705d0b1887SFrançois Tigeot default:
715d0b1887SFrançois Tigeot return "bad type";
725d0b1887SFrançois Tigeot }
735d0b1887SFrançois Tigeot }
745d0b1887SFrançois Tigeot
755d0b1887SFrançois Tigeot static void intel_dsm_platform_mux_info(void)
765d0b1887SFrançois Tigeot {
779edbd4a0SFrançois Tigeot int i;
789edbd4a0SFrançois Tigeot union acpi_object *pkg, *connector_count;
795d0b1887SFrançois Tigeot
80*3f2dd94aSFrançois Tigeot pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, &intel_dsm_guid,
819edbd4a0SFrançois Tigeot INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
829edbd4a0SFrançois Tigeot NULL, ACPI_TYPE_PACKAGE);
839edbd4a0SFrançois Tigeot if (!pkg) {
849edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
859edbd4a0SFrançois Tigeot return;
865d0b1887SFrançois Tigeot }
875d0b1887SFrançois Tigeot
889edbd4a0SFrançois Tigeot connector_count = &pkg->package.elements[0];
895d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
905d0b1887SFrançois Tigeot (unsigned long long)connector_count->integer.value);
915d0b1887SFrançois Tigeot for (i = 1; i < pkg->package.count; i++) {
925d0b1887SFrançois Tigeot union acpi_object *obj = &pkg->package.elements[i];
939edbd4a0SFrançois Tigeot union acpi_object *connector_id = &obj->package.elements[0];
945d0b1887SFrançois Tigeot union acpi_object *info = &obj->package.elements[1];
955d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
965d0b1887SFrançois Tigeot (unsigned long long)connector_id->integer.value);
975d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" port id: %s\n",
985d0b1887SFrançois Tigeot intel_dsm_port_name(info->buffer.pointer[0]));
995d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" display mux info: %s\n",
1005d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[1]));
1015d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
1025d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[2]));
1035d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
1045d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[3]));
1055d0b1887SFrançois Tigeot }
1065d0b1887SFrançois Tigeot
1079edbd4a0SFrançois Tigeot ACPI_FREE(pkg);
1085d0b1887SFrançois Tigeot }
1095d0b1887SFrançois Tigeot
1105d0b1887SFrançois Tigeot static bool intel_dsm_pci_probe(struct pci_dev *pdev)
1115d0b1887SFrançois Tigeot {
1129edbd4a0SFrançois Tigeot acpi_handle dhandle;
1135d0b1887SFrançois Tigeot
1149edbd4a0SFrançois Tigeot dhandle = ACPI_HANDLE(&pdev->dev);
1155d0b1887SFrançois Tigeot if (!dhandle)
1165d0b1887SFrançois Tigeot return false;
1175d0b1887SFrançois Tigeot
118*3f2dd94aSFrançois Tigeot if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
1199edbd4a0SFrançois Tigeot 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
1205d0b1887SFrançois Tigeot DRM_DEBUG_KMS("no _DSM method for intel device\n");
1215d0b1887SFrançois Tigeot return false;
1225d0b1887SFrançois Tigeot }
1235d0b1887SFrançois Tigeot
1245d0b1887SFrançois Tigeot intel_dsm_priv.dhandle = dhandle;
1255d0b1887SFrançois Tigeot intel_dsm_platform_mux_info();
1269edbd4a0SFrançois Tigeot
1275d0b1887SFrançois Tigeot return true;
1285d0b1887SFrançois Tigeot }
1295d0b1887SFrançois Tigeot
1305d0b1887SFrançois Tigeot static bool intel_dsm_detect(void)
1315d0b1887SFrançois Tigeot {
1325d0b1887SFrançois Tigeot char acpi_method_name[255] = { 0 };
1335d0b1887SFrançois Tigeot struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
1345d0b1887SFrançois Tigeot struct pci_dev *pdev = NULL;
1355d0b1887SFrançois Tigeot bool has_dsm = false;
1365d0b1887SFrançois Tigeot int vga_count = 0;
1375d0b1887SFrançois Tigeot
1385d0b1887SFrançois Tigeot while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
1395d0b1887SFrançois Tigeot vga_count++;
1405d0b1887SFrançois Tigeot has_dsm |= intel_dsm_pci_probe(pdev);
1415d0b1887SFrançois Tigeot }
1425d0b1887SFrançois Tigeot
1435d0b1887SFrançois Tigeot if (vga_count == 2 && has_dsm) {
1445d0b1887SFrançois Tigeot acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
145352ff8bdSFrançois Tigeot DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
1465d0b1887SFrançois Tigeot acpi_method_name);
1475d0b1887SFrançois Tigeot return true;
1485d0b1887SFrançois Tigeot }
1495d0b1887SFrançois Tigeot
1505d0b1887SFrançois Tigeot return false;
1515d0b1887SFrançois Tigeot }
1525d0b1887SFrançois Tigeot
1535d0b1887SFrançois Tigeot void intel_register_dsm_handler(void)
1545d0b1887SFrançois Tigeot {
1555d0b1887SFrançois Tigeot if (!intel_dsm_detect())
1565d0b1887SFrançois Tigeot return;
1575d0b1887SFrançois Tigeot }
1585d0b1887SFrançois Tigeot #endif
1595d0b1887SFrançois Tigeot
intel_unregister_dsm_handler(void)1605d0b1887SFrançois Tigeot void intel_unregister_dsm_handler(void)
1615d0b1887SFrançois Tigeot {
1625d0b1887SFrançois Tigeot }
163