git: e75f61962ca4 - main - ig4(4): fix attach of ACPI-enumerated LPSS controllers

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Thu, 17 Sep 2026 09:10:09 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=e75f61962ca47f0b0ae4aed89c8416e6544d9845

commit e75f61962ca47f0b0ae4aed89c8416e6544d9845
Author:     Please <please@forget.me.uk>
AuthorDate: 2026-09-17 09:08:43 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2026-09-17 09:08:43 +0000

    ig4(4): fix attach of ACPI-enumerated LPSS controllers
    
    Intel LPSS I2C controllers enumerated through ACPI rather than PCI never
    attach on Haswell and Broadwell, so every device behind those buses is
    lost. On a Dell XPS 13 9343 that hides the I2C HID touchpad and leaves
    only the PS/2 fallback, which the firmware does not restore after S3.
    
    Three causes, all on the ACPI path:
    
    Firmware may leave an LPSS function in D3, where its registers read as
    all-ones and set_controller() fails with "controller error during
    attach-1". Run _PS0 before mapping them. The PCI path does not need
    this, which is why the gap went unnoticed.
    
    INT33C2, INT33C3, INT3432 and INT3433 are Lynx Point-LP and Wildcat
    Point-LP, which ig4_pci.c already classifies as IG4_HASWELL; the ACPI
    path called everything but APMC0D0F an Atom SoC.
    
    The functional clock stays gated until bit 0 of IG4_REG_CLK_PARMS is
    set. Until then the controller accepts writes into the TX FIFO, never
    drives the bus, raises no interrupts, and every transfer ends in
    IIC_ETIMEOUT. Linux ungates the same bit in acpi_lpss.c. Doing it in
    ig4iic_set_config() covers resume as well as attach.
    
    With all three in place the touchpad attaches as iichid0/hmt1 with
    multi-touch and survives suspend and resume.
    
    PR:             298558
    Tested by:      Please (XPS 13 9343, Broadwell-U, 15.1-RELEASE-p3)
    Reviewed by:    wulf
    MFC after:      1 week
---
 sys/dev/ichiic/ig4_acpi.c | 10 ++++++++++
 sys/dev/ichiic/ig4_iic.c  | 11 +++++++++++
 sys/dev/ichiic/ig4_reg.h  |  1 +
 3 files changed, 22 insertions(+)

diff --git a/sys/dev/ichiic/ig4_acpi.c b/sys/dev/ichiic/ig4_acpi.c
index 1275790a4412..10540d2bd889 100644
--- a/sys/dev/ichiic/ig4_acpi.c
+++ b/sys/dev/ichiic/ig4_acpi.c
@@ -95,10 +95,20 @@ ig4iic_acpi_attach(device_t dev)
 		return (error);
 	if (strcmp(str, "APMC0D0F") == 0) {
 		sc->version = IG4_EMAG;
+	} else if (strcmp(str, "INT33C2") == 0 || strcmp(str, "INT33C3") == 0 ||
+	    strcmp(str, "INT3432") == 0 || strcmp(str, "INT3433") == 0) {
+		/* Lynx Point-LP / Wildcat Point-LP LPSS in ACPI mode. */
+		sc->version = IG4_HASWELL;
 	} else {
 		/* All the other HIDs matched are Atom SOCs. */
 		sc->version = IG4_ATOM;
 	}
+	/*
+	 * Firmware may leave LPSS functions in D3 (e.g. Dell XPS 13 9343):
+	 * the registers then read as all-ones and attach fails.  Run _PS0.
+	 */
+	acpi_set_powerstate(dev, ACPI_STATE_D0);
+
 	sc->regs_rid = 0;
 	sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
 					  &sc->regs_rid, RF_ACTIVE);
diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c
index 161a940c5e7a..a326d487e1d9 100644
--- a/sys/dev/ichiic/ig4_iic.c
+++ b/sys/dev/ichiic/ig4_iic.c
@@ -933,6 +933,17 @@ ig4iic_set_config(ig4iic_softc_t *sc, bool reset, bool force_restore)
 		reset = true;
 	}
 
+	/*
+	 * Haswell/Broadwell LPSS in ACPI mode can come up with the functional
+	 * clock gated.  The controller then accepts FIFO writes but never
+	 * drives the bus and every transfer times out.
+	 */
+	if (sc->version == IG4_HASWELL) {
+		v = reg_read(sc, IG4_REG_CLK_PARMS);
+		if ((v & IG4_CLK_PARMS_EN) == 0)
+			reg_write(sc, IG4_REG_CLK_PARMS, v | IG4_CLK_PARMS_EN);
+	}
+
 	if ((sc->version == IG4_HASWELL || sc->version == IG4_ATOM) && reset) {
 		reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW);
 		reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW);
diff --git a/sys/dev/ichiic/ig4_reg.h b/sys/dev/ichiic/ig4_reg.h
index 35342f7d79aa..435475465e6f 100644
--- a/sys/dev/ichiic/ig4_reg.h
+++ b/sys/dev/ichiic/ig4_reg.h
@@ -124,6 +124,7 @@
 #define IG4_REG_DEVIDLE_CTRL	0x024C	/* RW	Device Control */
 /* Available at least on Atom SoCs */
 #define IG4_REG_CLK_PARMS	0x0800	/* RW	Clock Parameters */
+#define IG4_CLK_PARMS_EN	0x00000001 /* functional clock ungated */
 /* Available at least on Atom SoCs and Haswell mobile */
 #define IG4_REG_RESETS_HSW	0x0804	/* RW	Reset Register */
 #define IG4_REG_GENERAL		0x0808	/* RW	General Register */