aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2017-04-21 06:47:40 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-04-26 18:02:43 -0400
commitb7ecf663c75eed1e764f57281f9508c49c18516e (patch)
tree61c77533f0e4676219c5137d601e8765c894f4cd
parent5a7ad1146caa895ad718a534399e38bd2ba721b7 (diff)
ACPI / bus: Introduce a list of ids for "always present" devices
Several Bay / Cherry Trail devices (all of which ship with Windows 10) hide the LPSS PWM controller in ACPI, typically the _STA method looks like this: Method (_STA, 0, NotSerialized) // _STA: Status { If (OSID == One) { Return (Zero) } Return (0x0F) } Where OSID is some dark magic seen in all Cherry Trail ACPI tables making the machine behave differently depending on which OS it *thinks* it is booting, this gets set in a number of ways which we cannot control, on some newer machines it simple hardcoded to "One" aka win10. This causes the PWM controller to get hidden, which means Linux cannot control the backlight level on cht based tablets / laptops. Since loading the driver for this does no harm (the only in kernel user of it is the i915 driver, which will only uses it when it needs it), this commit makes acpi_bus_get_status() always set status to ACPI_STA_DEFAULT for the LPSS PWM device, fixing the lack of backlight control. Signed-off-by: Hans de Goede <hdegoede@redhat.com> [ rjw: Rename the new file to utils.c ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/bus.c5
-rw-r--r--drivers/acpi/x86/utils.c85
-rw-r--r--include/acpi/acpi_bus.h9
4 files changed, 100 insertions, 0 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d94f92f88ca1..2a81d278bcf3 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o
50acpi-y += sysfs.o 50acpi-y += sysfs.o
51acpi-y += property.o 51acpi-y += property.o
52acpi-$(CONFIG_X86) += acpi_cmos_rtc.o 52acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
53acpi-$(CONFIG_X86) += x86/utils.o
53acpi-$(CONFIG_DEBUG_FS) += debugfs.o 54acpi-$(CONFIG_DEBUG_FS) += debugfs.o
54acpi-$(CONFIG_ACPI_NUMA) += numa.o 55acpi-$(CONFIG_ACPI_NUMA) += numa.o
55acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o 56acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 34fbe027e73a..784bda663d16 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -114,6 +114,11 @@ int acpi_bus_get_status(struct acpi_device *device)
114 acpi_status status; 114 acpi_status status;
115 unsigned long long sta; 115 unsigned long long sta;
116 116
117 if (acpi_device_always_present(device)) {
118 acpi_set_device_status(device, ACPI_STA_DEFAULT);
119 return 0;
120 }
121
117 status = acpi_bus_get_status_handle(device->handle, &sta); 122 status = acpi_bus_get_status_handle(device->handle, &sta);
118 if (ACPI_FAILURE(status)) 123 if (ACPI_FAILURE(status))
119 return -ENODEV; 124 return -ENODEV;
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
new file mode 100644
index 000000000000..c8e90ef4485f
--- /dev/null
+++ b/drivers/acpi/x86/utils.c
@@ -0,0 +1,85 @@
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
14#include <linux/acpi.h>
15#include <asm/cpu_device_id.h>
16#include <asm/intel-family.h>
17#include "../internal.h"
18
19/*
20 * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because
21 * some recent Windows drivers bind to one device but poke at multiple
22 * devices at the same time, so the others get hidden.
23 * We work around this by always reporting ACPI_STA_DEFAULT for these
24 * devices. Note this MUST only be done for devices where this is safe.
25 *
26 * This forcing of devices to be present is limited to specific CPU (SoC)
27 * models both to avoid potentially causing trouble on other models and
28 * because some HIDs are re-used on different SoCs for completely
29 * different devices.
30 */
31struct always_present_id {
32 struct acpi_device_id hid[2];
33 struct x86_cpu_id cpu_ids[2];
34 const char *uid;
35};
36
37#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
38
39#define ENTRY(hid, uid, cpu_models) { \
40 { { hid, }, {} }, \
41 { cpu_models, {} }, \
42 uid, \
43}
44
45static const struct always_present_id always_present_ids[] = {
46 /*
47 * Bay / Cherry Trail PWM directly poked by GPU driver in win10,
48 * but Linux uses a separate PWM driver, harmless if not used.
49 */
50 ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1)),
51 ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)),
52};
53
54bool acpi_device_always_present(struct acpi_device *adev)
55{
56 u32 *status = (u32 *)&adev->status;
57 u32 old_status = *status;
58 bool ret = false;
59 unsigned int i;
60
61 /* acpi_match_device_ids checks status, so set it to default */
62 *status = ACPI_STA_DEFAULT;
63 for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) {
64 if (acpi_match_device_ids(adev, always_present_ids[i].hid))
65 continue;
66
67 if (!adev->pnp.unique_id ||
68 strcmp(adev->pnp.unique_id, always_present_ids[i].uid))
69 continue;
70
71 if (!x86_match_cpu(always_present_ids[i].cpu_ids))
72 continue;
73
74 if (old_status != ACPI_STA_DEFAULT) /* Log only once */
75 dev_info(&adev->dev,
76 "Device [%s] is in always present list\n",
77 adev->pnp.bus_id);
78
79 ret = true;
80 break;
81 }
82 *status = old_status;
83
84 return ret;
85}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index ef0ae8aaa567..b86b90489140 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -586,6 +586,15 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
586int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); 586int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
587int acpi_disable_wakeup_device_power(struct acpi_device *dev); 587int acpi_disable_wakeup_device_power(struct acpi_device *dev);
588 588
589#ifdef CONFIG_X86
590bool acpi_device_always_present(struct acpi_device *adev);
591#else
592static inline bool acpi_device_always_present(struct acpi_device *adev)
593{
594 return false;
595}
596#endif
597
589#ifdef CONFIG_PM 598#ifdef CONFIG_PM
590acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, 599acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
591 void (*work_func)(struct work_struct *work)); 600 void (*work_func)(struct work_struct *work));