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