diff options
| author | Devin Teske <dteske@FreeBSD.org> | 2026-06-19 17:24:58 +0000 |
|---|---|---|
| committer | Devin Teske <dteske@FreeBSD.org> | 2026-06-21 05:28:47 +0000 |
| commit | a4ed783cee2a10629db7a6c254712f96bd820288 (patch) | |
| tree | 014af760a63151c55e8ba8b4e1fecd68912fe79f /sys/dev | |
| parent | fa515f60fce0edd09d0b1078852ec06b1cd0a74c (diff) | |
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/hid/hid.c | 2 | ||||
| -rw-r--r-- | sys/dev/ichiic/ig4_iic.c | 52 |
2 files changed, 47 insertions, 7 deletions
diff --git a/sys/dev/hid/hid.c b/sys/dev/hid/hid.c index 453c37d806fc..c07343fc057f 100644 --- a/sys/dev/hid/hid.c +++ b/sys/dev/hid/hid.c @@ -66,7 +66,7 @@ hid_test_quirk_t *hid_test_quirk_p = &hid_test_quirk_w; #define MAXUSAGE 64 #define MAXPUSH 4 #define MAXID 16 -#define MAXLOCCNT 2048 +#define MAXLOCCNT 4096 struct hid_pos_data { uint32_t rid; diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c index cd88b28a2d52..161a940c5e7a 100644 --- a/sys/dev/ichiic/ig4_iic.c +++ b/sys/dev/ichiic/ig4_iic.c @@ -134,7 +134,7 @@ static const struct ig4_hw ig4iic_hw[] = { }, }; -static int ig4iic_set_config(ig4iic_softc_t *sc, bool reset); +static int ig4iic_set_config(ig4iic_softc_t *sc, bool reset, bool force_restore); static driver_filter_t ig4iic_intr; static void ig4iic_dump(ig4iic_softc_t *sc); @@ -661,7 +661,7 @@ ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) ig4iic_xfer_abort(sc) != 0) { device_printf(sc->dev, "Failed to abort " "transfer. Do the controller reset.\n"); - ig4iic_set_config(sc, true); + ig4iic_set_config(sc, true, false); } else { while (reg_read(sc, IG4_REG_I2C_STA) & IG4_STATUS_RX_NOTEMPTY) @@ -910,12 +910,23 @@ ig4iic_get_config(ig4iic_softc_t *sc) } static int -ig4iic_set_config(ig4iic_softc_t *sc, bool reset) +ig4iic_set_config(ig4iic_softc_t *sc, bool reset, bool force_restore) { uint32_t v; + int i; + /* + * Take the LPSS DesignWare core out of the "device idle" state. While + * idle the core is power-gated: its register bank reads back as zero and + * writes are dropped. Normally we perform this un-idle handshake only + * when IG4_RESTORE_REQUIRED is observed in DEVIDLE_CTRL, but some + * platforms (e.g. Intel Alder Lake-P) do not raise that status across + * suspend-to-idle (S0ix). Callers that know the core was idled (the + * resume path) pass force_restore to perform the handshake regardless. + */ v = reg_read(sc, IG4_REG_DEVIDLE_CTRL); - if (IG4_HAS_ADDREGS(sc->version) && (v & IG4_RESTORE_REQUIRED)) { + if (IG4_HAS_ADDREGS(sc->version) && + (force_restore || (v & IG4_RESTORE_REQUIRED))) { reg_write(sc, IG4_REG_DEVIDLE_CTRL, IG4_DEVICE_IDLE | IG4_RESTORE_REQUIRED); reg_write(sc, IG4_REG_DEVIDLE_CTRL, 0); pause("i2crst", 1); @@ -928,6 +939,23 @@ ig4iic_set_config(ig4iic_softc_t *sc, bool reset) } else if (IG4_HAS_ADDREGS(sc->version) && reset) { reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL); reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL); + /* + * The DesignWare core's register bank is inaccessible (reads + * back as zero) until it leaves reset. Poll the fixed + * component-type signature so we proceed exactly when the core + * is ready, rather than waiting a fixed, guessed interval. + */ + for (i = 0; i < 100; i++) { + if (reg_read(sc, IG4_REG_COMP_TYPE) == IG4_COMP_TYPE) + break; + DELAY(10); + } + if (i == 100) { + device_printf(sc->dev, "WARNING: I2C controller core " + "did not leave reset (COMP_TYPE 0x%08x); device " + "may be unusable\n", + reg_read(sc, IG4_REG_COMP_TYPE)); + } } if (sc->version == IG4_ATOM) @@ -1037,7 +1065,7 @@ ig4iic_attach(ig4iic_softc_t *sc) ig4iic_get_config(sc); - error = ig4iic_set_config(sc, IG4_HAS_ADDREGS(sc->version)); + error = ig4iic_set_config(sc, IG4_HAS_ADDREGS(sc->version), false); if (error) goto done; ig4iic_get_fifo(sc); @@ -1130,7 +1158,19 @@ int ig4iic_resume(ig4iic_softc_t *sc) int error; sx_xlock(&sc->call_lock); - if (ig4iic_set_config(sc, IG4_HAS_ADDREGS(sc->version))) + + /* + * ig4iic_suspend() leaves the controller power-gated in the LPSS + * "device idle" state. Force the un-idle/restore handshake in + * ig4iic_set_config() so the DesignWare core is reliably restored + * before reconfiguration: some platforms (e.g. Intel Alder Lake-P) do + * not raise IG4_RESTORE_REQUIRED across suspend-to-idle (S0ix), and + * without the forced handshake the core stays gated, set_config()'s + * writes are dropped, and every subsequent transfer fails with + * IIC_ETIMEOUT, leaving child I2C-HID devices (touchpad, touchscreen) + * dead after resume. + */ + if (ig4iic_set_config(sc, IG4_HAS_ADDREGS(sc->version), true)) device_printf(sc->dev, "controller error during resume\n"); sx_xunlock(&sc->call_lock); |
