intel_acpi.c 3.6 KB

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