18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * X86 ACPI Utility Functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: 88c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/dmi.h> 138c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 148c2ecf20Sopenharmony_ci#include <asm/intel-family.h> 158c2ecf20Sopenharmony_ci#include "../internal.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because 198c2ecf20Sopenharmony_ci * some recent Windows drivers bind to one device but poke at multiple 208c2ecf20Sopenharmony_ci * devices at the same time, so the others get hidden. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Some BIOS-es (temporarily) hide specific APCI devices to work around Windows 238c2ecf20Sopenharmony_ci * driver bugs. We use DMI matching to match known cases of this. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Likewise sometimes some not-actually present devices are sometimes 268c2ecf20Sopenharmony_ci * reported as present, which may cause issues. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * We work around this by using the below quirk list to override the status 298c2ecf20Sopenharmony_ci * reported by the _STA method with a fixed value (ACPI_STA_DEFAULT or 0). 308c2ecf20Sopenharmony_ci * Note this MUST only be done for devices where this is safe. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * This status overriding is limited to specific CPU (SoC) models both to 338c2ecf20Sopenharmony_ci * avoid potentially causing trouble on other models and because some HIDs 348c2ecf20Sopenharmony_ci * are re-used on different SoCs for completely different devices. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct override_status_id { 378c2ecf20Sopenharmony_ci struct acpi_device_id hid[2]; 388c2ecf20Sopenharmony_ci struct x86_cpu_id cpu_ids[2]; 398c2ecf20Sopenharmony_ci struct dmi_system_id dmi_ids[2]; /* Optional */ 408c2ecf20Sopenharmony_ci const char *uid; 418c2ecf20Sopenharmony_ci const char *path; 428c2ecf20Sopenharmony_ci unsigned long long status; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define ENTRY(status, hid, uid, path, cpu_model, dmi...) { \ 468c2ecf20Sopenharmony_ci { { hid, }, {} }, \ 478c2ecf20Sopenharmony_ci { X86_MATCH_INTEL_FAM6_MODEL(cpu_model, NULL), {} }, \ 488c2ecf20Sopenharmony_ci { { .matches = dmi }, {} }, \ 498c2ecf20Sopenharmony_ci uid, \ 508c2ecf20Sopenharmony_ci path, \ 518c2ecf20Sopenharmony_ci status, \ 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define PRESENT_ENTRY_HID(hid, uid, cpu_model, dmi...) \ 558c2ecf20Sopenharmony_ci ENTRY(ACPI_STA_DEFAULT, hid, uid, NULL, cpu_model, dmi) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define NOT_PRESENT_ENTRY_HID(hid, uid, cpu_model, dmi...) \ 588c2ecf20Sopenharmony_ci ENTRY(0, hid, uid, NULL, cpu_model, dmi) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define PRESENT_ENTRY_PATH(path, cpu_model, dmi...) \ 618c2ecf20Sopenharmony_ci ENTRY(ACPI_STA_DEFAULT, "", NULL, path, cpu_model, dmi) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define NOT_PRESENT_ENTRY_PATH(path, cpu_model, dmi...) \ 648c2ecf20Sopenharmony_ci ENTRY(0, "", NULL, path, cpu_model, dmi) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct override_status_id override_status_ids[] = { 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * Bay / Cherry Trail PWM directly poked by GPU driver in win10, 698c2ecf20Sopenharmony_ci * but Linux uses a separate PWM driver, harmless if not used. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("80860F09", "1", ATOM_SILVERMONT, {}), 728c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("80862288", "1", ATOM_AIRMONT, {}), 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * The INT0002 device is necessary to clear wakeup interrupt sources 768c2ecf20Sopenharmony_ci * on Cherry Trail devices, without it we get nobody cared IRQ msgs. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("INT0002", "1", ATOM_AIRMONT, {}), 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * On the Dell Venue 11 Pro 7130 and 7139, the DSDT hides 818c2ecf20Sopenharmony_ci * the touchscreen ACPI device until a certain time 828c2ecf20Sopenharmony_ci * after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed 838c2ecf20Sopenharmony_ci * *and* _STA has been called at least 3 times since. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("SYNA7500", "1", HASWELL_L, { 868c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 878c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"), 888c2ecf20Sopenharmony_ci }), 898c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("SYNA7500", "1", HASWELL_L, { 908c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 918c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"), 928c2ecf20Sopenharmony_ci }), 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * The GPD win BIOS dated 20170221 has disabled the accelerometer, the 968c2ecf20Sopenharmony_ci * drivers sometimes cause crashes under Windows and this is how the 978c2ecf20Sopenharmony_ci * manufacturer has solved this :| The DMI match may not seem unique, 988c2ecf20Sopenharmony_ci * but it is. In the 67000+ DMI decode dumps from linux-hardware.org 998c2ecf20Sopenharmony_ci * only 116 have board_vendor set to "AMI Corporation" and of those 116 1008c2ecf20Sopenharmony_ci * only the GPD win and pocket entries' board_name is "Default string". 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * Unfortunately the GPD pocket also uses these strings and its BIOS 1038c2ecf20Sopenharmony_ci * was copy-pasted from the GPD win, so it has a disabled KIOX000A 1048c2ecf20Sopenharmony_ci * node which we should not enable, thus we also check the BIOS date. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, { 1078c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1088c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "Default string"), 1098c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), 1108c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "02/21/2017") 1118c2ecf20Sopenharmony_ci }), 1128c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, { 1138c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1148c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "Default string"), 1158c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), 1168c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "03/20/2017") 1178c2ecf20Sopenharmony_ci }), 1188c2ecf20Sopenharmony_ci PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, { 1198c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1208c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "Default string"), 1218c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), 1228c2ecf20Sopenharmony_ci DMI_MATCH(DMI_BIOS_DATE, "05/25/2017") 1238c2ecf20Sopenharmony_ci }), 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * The GPD win/pocket have a PCI wifi card, but its DSDT has the SDIO 1278c2ecf20Sopenharmony_ci * mmc controller enabled and that has a child-device which _PS3 1288c2ecf20Sopenharmony_ci * method sets a GPIO causing the PCI wifi card to turn off. 1298c2ecf20Sopenharmony_ci * See above remark about uniqueness of the DMI match. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci NOT_PRESENT_ENTRY_PATH("\\_SB_.PCI0.SDHB.BRC1", ATOM_AIRMONT, { 1328c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1338c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), 1348c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), 1358c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 1368c2ecf20Sopenharmony_ci }), 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cibool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci bool ret = false; 1428c2ecf20Sopenharmony_ci unsigned int i; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(override_status_ids); i++) { 1458c2ecf20Sopenharmony_ci if (!x86_match_cpu(override_status_ids[i].cpu_ids)) 1468c2ecf20Sopenharmony_ci continue; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (override_status_ids[i].dmi_ids[0].matches[0].slot && 1498c2ecf20Sopenharmony_ci !dmi_check_system(override_status_ids[i].dmi_ids)) 1508c2ecf20Sopenharmony_ci continue; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (override_status_ids[i].path) { 1538c2ecf20Sopenharmony_ci struct acpi_buffer path = { ACPI_ALLOCATE_BUFFER, NULL }; 1548c2ecf20Sopenharmony_ci bool match; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &path)) 1578c2ecf20Sopenharmony_ci continue; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci match = strcmp((char *)path.pointer, override_status_ids[i].path) == 0; 1608c2ecf20Sopenharmony_ci kfree(path.pointer); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!match) 1638c2ecf20Sopenharmony_ci continue; 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci if (acpi_match_device_ids(adev, override_status_ids[i].hid)) 1668c2ecf20Sopenharmony_ci continue; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!adev->pnp.unique_id || 1698c2ecf20Sopenharmony_ci strcmp(adev->pnp.unique_id, override_status_ids[i].uid)) 1708c2ecf20Sopenharmony_ci continue; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci *status = override_status_ids[i].status; 1748c2ecf20Sopenharmony_ci ret = true; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci} 180