On Tue, Apr 18, 2017 at 1:54 PM, Hans de Goede <hdegoede@xxxxxxxxxx> wrote: > Several 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 use it when it needs it), this > commit makes acpi_bus_get_status() always set status to ACPI_STA_DEFAULT > for the 80862288 device, fixing the lack of backlight control. > > Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> > --- > Changes in v2: > -Use pr_debug instead of ACPI_DEBUG_PRINT > Changes in v3: > -Un-inline acpi_set_device_status and do the always_present_device_ids > table check inside the un-inlined version of it > Changes in v4: > -Use dev_info instead of pr_debug > -Not only check for ACPI HID but also for CPU (SoC) model so as to not > for devices present on other models then for which the quirk is intended and > to avoid enabling unrelated ACPI devices which happen to use the same HID > Changes in v5: > -Only do the dev_info once per device (acpi_set_device_status gets called > multiple times per device during boot) > Changes in v6: > -Allow specifying more then one CPU-model for a single HID > -Not only match the HID but also the UID, like on Cherry Trail, on some Bay > Trail Windows 10 tablets we need to enable the PWM controller to get working > backlight even though _STA returns 0. The Bay Trail SoC has 2 PWM controllers > and we only need the first one. UID matching will allows adding an entry for > Bay Trail which only enables the first PWM controller > --- > drivers/acpi/bus.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/acpi/acpi_bus.h | 6 +---- > 2 files changed, 66 insertions(+), 5 deletions(-) > > diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c > index 34fbe02..eb30630 100644 > --- a/drivers/acpi/bus.c > +++ b/drivers/acpi/bus.c > @@ -34,6 +34,8 @@ > #include <linux/reboot.h> > #include <linux/delay.h> > #ifdef CONFIG_X86 > +#include <asm/cpu_device_id.h> > +#include <asm/intel-family.h> > #include <asm/mpspec.h> > #endif > #include <linux/acpi_iort.h> > @@ -132,6 +134,69 @@ int acpi_bus_get_status(struct acpi_device *device) > } > EXPORT_SYMBOL(acpi_bus_get_status); > > +#ifdef CONFIG_X86 > +/* > + * 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. > + * 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_device_id { > + struct acpi_device_id hid[2]; > + struct x86_cpu_id cpu_ids[2]; This really is x86-specific, so it should go into somewhere like arch/x86/kernel/acpi/ or drivers/acpi/x86/ (not present yet). > + const char *uid; > +}; > + > +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } > + > +#define ENTRY(hid, uid, cpu_models) { \ > + { { hid, }, {} }, \ > + { cpu_models, {} }, \ > + uid, \ > +} > + > +static const struct always_present_device_id always_present_device_ids[] = { > + /* > + * Cherry Trail PWM directly poked by GPU driver in win10, > + * but Linux uses a separate PWM driver, harmless if not used. > + */ > + ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), > +}; > +#endif > + > +void acpi_set_device_status(struct acpi_device *adev, u32 sta) > +{ > + u32 *status = (u32 *)&adev->status; > +#ifdef CONFIG_X86 > + u32 old_status = *status; > + int i; > + > + /* acpi_match_device_ids checks status, so start with default */ > + *status = ACPI_STA_DEFAULT; > + for (i = 0; i < ARRAY_SIZE(always_present_device_ids); i++) { > + if (acpi_match_device_ids(adev, > + always_present_device_ids[i].hid) == 0 && > + adev->pnp.unique_id && > + strcmp(adev->pnp.unique_id, > + always_present_device_ids[i].uid) == 0 && > + x86_match_cpu(always_present_device_ids[i].cpu_ids)) { Split this condition please. It is almost unreadable as is. > + if (old_status != ACPI_STA_DEFAULT) > + dev_info(&adev->dev, > + "Device [%s] is in always present list setting status [%08x]\n", > + adev->pnp.bus_id, ACPI_STA_DEFAULT); > + return; > + } > + } > +#endif > + *status = sta; > +} > + > void acpi_bus_private_data_handler(acpi_handle handle, > void *context) > { Thanks, Rafael -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html