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