On Thu, Dec 30, 2021 at 3:17 PM Hans de Goede <hdegoede@xxxxxxxxxx> wrote: > > x86 ACPI boards which ship with only Android as their factory image usually > declare a whole bunch of bogus I2C devs in their ACPI tables and sometimes > there are issues with serdev devices on these boards too, e.g. the resource > points to the wrong serdev_controller. > > Instantiating I2C / serdev devs for these bogus devs causes various issues, > e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. > The Android x86 kernel fork shipped on these devices has some special code > to remove the bogus I2C clients (and serdevs are ignored completely). > > Introduce acpi_quirk_skip_i2c_client_enumeration() and > acpi_quirk_skip_serdev_enumeration() helpers. Which can be used by the I2C/ > serdev code to skip instantiating any I2C or serdev devs on broken boards. > > These 2 helpers are added to drivers/acpi/x86/utils.c so that the DMI table > can be shared between the I2C and serdev code. > > Note these boards typically do actually have I2C and serdev devices, just > different ones then the ones described in their DSDT. The devices which > are actually present are manually instantiated by the > drivers/platform/x86/x86-android-tablets.c kernel module. > > The new helpers are only build if CONFIG_X86_ANDROID_TABLETS is enabled, > otherwise they are empty stubs to not unnecessarily grow the kernel size. > > Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> > --- > Changes in v2: > - Move the i2c_acpi_known_good_ids[] list and checking into this patch / > into the new acpi_quirk_skip_i2c_client_enumeration() function Acked-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> or please let me know if you want me to take this series. Thanks! > --- > drivers/acpi/x86/utils.c | 111 +++++++++++++++++++++++++++++++++++++++ > include/acpi/acpi_bus.h | 16 ++++++ > 2 files changed, 127 insertions(+) > > diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c > index a2ae1ac41319..375a0911f06d 100644 > --- a/drivers/acpi/x86/utils.c > +++ b/drivers/acpi/x86/utils.c > @@ -10,6 +10,7 @@ > > #include <linux/acpi.h> > #include <linux/dmi.h> > +#include <linux/platform_device.h> > #include <asm/cpu_device_id.h> > #include <asm/intel-family.h> > #include "../internal.h" > @@ -208,3 +209,113 @@ bool force_storage_d3(void) > { > return x86_match_cpu(storage_d3_cpu_ids); > } > + > +#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) > +/* > + * x86 ACPI boards which ship with only Android as their factory image usually > + * declare a whole bunch of bogus I2C devices in their ACPI tables and sometimes > + * there are issues with serdev devices on these boards too, e.g. the resource > + * points to the wrong serdev_controller. > + * > + * Instantiating I2C / serdev devs for these bogus devs causes various issues, > + * e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. > + * The Android x86 kernel fork shipped on these devices has some special code > + * to remove the bogus I2C clients (and AFAICT serdevs are ignored completely). > + * > + * The acpi_quirk_skip_*_enumeration() functions below are used by the I2C or > + * serdev code to skip instantiating any I2C or serdev devs on broken boards. > + * > + * In case of I2C an exception is made for HIDs on the i2c_acpi_known_good_ids > + * list. These are known to always be correct (and in case of the audio-codecs > + * the drivers heavily rely on the codec being enumerated through ACPI). > + * > + * Note these boards typically do actually have I2C and serdev devices, > + * just different ones then the ones described in their DSDT. The devices > + * which are actually present are manually instantiated by the > + * drivers/platform/x86/x86-android-tablets.c kernel module. > + */ > +#define ACPI_QUIRK_SKIP_I2C_CLIENTS BIT(0) > +#define ACPI_QUIRK_UART1_TTY_UART2_SKIP BIT(1) > + > +static const struct dmi_system_id acpi_skip_serial_bus_enumeration_ids[] = { > + { > + .matches = { > + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), > + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), > + }, > + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | > + ACPI_QUIRK_UART1_TTY_UART2_SKIP), > + }, > + { > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), > + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), > + }, > + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, > + }, > + { > + /* Whitelabel (sold as various brands) TM800A550L */ > + .matches = { > + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), > + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), > + /* Above strings are too generic, also match on BIOS version */ > + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), > + }, > + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, > + }, > + {} > +}; > + > +static const struct acpi_device_id i2c_acpi_known_good_ids[] = { > + { "10EC5640", 0 }, /* RealTek ALC5640 audio codec */ > + { "INT33F4", 0 }, /* X-Powers AXP288 PMIC */ > + { "INT33FD", 0 }, /* Intel Crystal Cove PMIC */ > + { "NPCE69A", 0 }, /* Asus Transformer keyboard dock */ > + {} > +}; > + > +bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) > +{ > + const struct dmi_system_id *dmi_id; > + long quirks; > + > + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); > + if (!dmi_id) > + return false; > + > + quirks = (unsigned long)dmi_id->driver_data; > + if (!(quirks & ACPI_QUIRK_SKIP_I2C_CLIENTS)) > + return false; > + > + return acpi_match_device_ids(adev, i2c_acpi_known_good_ids); > +} > +EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration); > + > +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) > +{ > + struct acpi_device *adev = ACPI_COMPANION(controller_parent); > + const struct dmi_system_id *dmi_id; > + long quirks = 0; > + > + *skip = false; > + > + /* !dev_is_platform() to not match on PNP enumerated debug UARTs */ > + if (!adev || !adev->pnp.unique_id || !dev_is_platform(controller_parent)) > + return 0; > + > + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); > + if (dmi_id) > + quirks = (unsigned long)dmi_id->driver_data; > + > + if (quirks & ACPI_QUIRK_UART1_TTY_UART2_SKIP) { > + if (!strcmp(adev->pnp.unique_id, "1")) > + return -ENODEV; /* Create tty cdev instead of serdev */ > + > + if (!strcmp(adev->pnp.unique_id, "2")) > + *skip = true; > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); > +#endif > diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h > index 5895f6c7f6db..102b1cf433c7 100644 > --- a/include/acpi/acpi_bus.h > +++ b/include/acpi/acpi_bus.h > @@ -624,6 +624,22 @@ static inline bool acpi_device_override_status(struct acpi_device *adev, > } > #endif > > +#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) > +bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev); > +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip); > +#else > +static inline bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) > +{ > + return false; > +} > +static inline int > +acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) > +{ > + *skip = false; > + return 0; > +} > +#endif > + > #ifdef CONFIG_PM > void acpi_pm_wakeup_event(struct device *dev); > acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, > -- > 2.33.1 >