utils.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * X86 ACPI Utility Functions
  3. *
  4. * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
  5. *
  6. * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
  7. * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #include <linux/acpi.h>
  14. #include <linux/dmi.h>
  15. #include <asm/cpu_device_id.h>
  16. #include <asm/intel-family.h>
  17. #include "../internal.h"
  18. /*
  19. * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because
  20. * some recent Windows drivers bind to one device but poke at multiple
  21. * devices at the same time, so the others get hidden.
  22. *
  23. * Some BIOS-es (temporarily) hide specific APCI devices to work around Windows
  24. * driver bugs. We use DMI matching to match known cases of this.
  25. *
  26. * We work around this by always reporting ACPI_STA_DEFAULT for these
  27. * devices. Note this MUST only be done for devices where this is safe.
  28. *
  29. * This forcing of devices to be present is limited to specific CPU (SoC)
  30. * models both to avoid potentially causing trouble on other models and
  31. * because some HIDs are re-used on different SoCs for completely
  32. * different devices.
  33. */
  34. struct always_present_id {
  35. struct acpi_device_id hid[2];
  36. struct x86_cpu_id cpu_ids[2];
  37. struct dmi_system_id dmi_ids[2]; /* Optional */
  38. const char *uid;
  39. };
  40. #define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
  41. #define ENTRY(hid, uid, cpu_models, dmi...) { \
  42. { { hid, }, {} }, \
  43. { cpu_models, {} }, \
  44. { { .matches = dmi }, {} }, \
  45. uid, \
  46. }
  47. static const struct always_present_id always_present_ids[] = {
  48. /*
  49. * Bay / Cherry Trail PWM directly poked by GPU driver in win10,
  50. * but Linux uses a separate PWM driver, harmless if not used.
  51. */
  52. ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1), {}),
  53. ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
  54. /*
  55. * The INT0002 device is necessary to clear wakeup interrupt sources
  56. * on Cherry Trail devices, without it we get nobody cared IRQ msgs.
  57. */
  58. ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
  59. /*
  60. * On the Dell Venue 11 Pro 7130 the DSDT hides the touchscreen ACPI
  61. * device until a certain time after _SB.PCI0.GFX0.LCD.LCD1._ON gets
  62. * called has passed *and* _STA has been called at least 3 times since.
  63. */
  64. ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), {
  65. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  66. DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
  67. }),
  68. /*
  69. * The GPD win BIOS dated 20170221 has disabled the accelerometer, the
  70. * drivers sometimes cause crashes under Windows and this is how the
  71. * manufacturer has solved this :| Note that the the DMI data is less
  72. * generic then it seems, a board_vendor of "AMI Corporation" is quite
  73. * rare and a board_name of "Default String" also is rare.
  74. *
  75. * Unfortunately the GPD pocket also uses these strings and its BIOS
  76. * was copy-pasted from the GPD win, so it has a disabled KIOX000A
  77. * node which we should not enable, thus we also check the BIOS date.
  78. */
  79. ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
  80. DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
  81. DMI_MATCH(DMI_BOARD_NAME, "Default string"),
  82. DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
  83. DMI_MATCH(DMI_BIOS_DATE, "02/21/2017")
  84. }),
  85. ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
  86. DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
  87. DMI_MATCH(DMI_BOARD_NAME, "Default string"),
  88. DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
  89. DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
  90. }),
  91. ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
  92. DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
  93. DMI_MATCH(DMI_BOARD_NAME, "Default string"),
  94. DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
  95. DMI_MATCH(DMI_BIOS_DATE, "05/25/2017")
  96. }),
  97. };
  98. bool acpi_device_always_present(struct acpi_device *adev)
  99. {
  100. u32 *status = (u32 *)&adev->status;
  101. u32 old_status = *status;
  102. bool ret = false;
  103. unsigned int i;
  104. /* acpi_match_device_ids checks status, so set it to default */
  105. *status = ACPI_STA_DEFAULT;
  106. for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) {
  107. if (acpi_match_device_ids(adev, always_present_ids[i].hid))
  108. continue;
  109. if (!adev->pnp.unique_id ||
  110. strcmp(adev->pnp.unique_id, always_present_ids[i].uid))
  111. continue;
  112. if (!x86_match_cpu(always_present_ids[i].cpu_ids))
  113. continue;
  114. if (always_present_ids[i].dmi_ids[0].matches[0].slot &&
  115. !dmi_check_system(always_present_ids[i].dmi_ids))
  116. continue;
  117. if (old_status != ACPI_STA_DEFAULT) /* Log only once */
  118. dev_info(&adev->dev,
  119. "Device [%s] is in always present list\n",
  120. adev->pnp.bus_id);
  121. ret = true;
  122. break;
  123. }
  124. *status = old_status;
  125. return ret;
  126. }