Date: Sun, 3 Nov 2019 21:08:26 +0000 (UTC) From: Vladimir Kondratyev <wulf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354315 - head/sys/dev/ichiic Message-ID: <201911032108.xA3L8Quq072214@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: wulf Date: Sun Nov 3 21:08:26 2019 New Revision: 354315 URL: https://svnweb.freebsd.org/changeset/base/354315 Log: [ig4] Set STOP condition and flush TX/RX FIFOs on error if controller has not it done for us yet. Reset controller when transfer abort is failed. Modified: head/sys/dev/ichiic/ig4_iic.c head/sys/dev/ichiic/ig4_reg.h Modified: head/sys/dev/ichiic/ig4_iic.c ============================================================================== --- head/sys/dev/ichiic/ig4_iic.c Sun Nov 3 21:07:12 2019 (r354314) +++ head/sys/dev/ichiic/ig4_iic.c Sun Nov 3 21:08:26 2019 (r354315) @@ -117,6 +117,7 @@ static const struct ig4_hw ig4iic_hw[] = { }, }; +static int ig4iic_set_config(ig4iic_softc_t *sc, bool reset); static void ig4iic_intr(void *cookie); static void ig4iic_dump(ig4iic_softc_t *sc); @@ -272,7 +273,7 @@ wait_intr(ig4iic_softc_t *sc, uint32_t intr) * reset the timeout if we see a change in the transmit * FIFO level as progress is being made. */ - if (intr & IG4_INTR_TX_EMPTY) { + if (intr & (IG4_INTR_TX_EMPTY | IG4_INTR_STOP_DET)) { v = reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK; if (txlvl != v) { txlvl = v; @@ -369,6 +370,34 @@ ig4iic_xfer_start(ig4iic_softc_t *sc, uint16_t slave, return (0); } +static bool +ig4iic_xfer_is_started(ig4iic_softc_t *sc) +{ + /* + * It requires that no IG4_REG_CLR_INTR or IG4_REG_CLR_START/STOP_DET + * register reads is issued after START condition. + */ + return ((reg_read(sc, IG4_REG_RAW_INTR_STAT) & + (IG4_INTR_START_DET | IG4_INTR_STOP_DET)) == IG4_INTR_START_DET); +} + +static int +ig4iic_xfer_abort(ig4iic_softc_t *sc) +{ + int error; + + /* Request send of STOP condition and flush of TX FIFO */ + set_controller(sc, IG4_I2C_ABORT | IG4_I2C_ENABLE); + /* + * Wait for the TX_ABRT interrupt with ABRTSRC_TRANSFER + * bit set in TX_ABRT_SOURCE register. + */ + error = wait_intr(sc, IG4_INTR_STOP_DET); + set_controller(sc, IG4_I2C_ENABLE); + + return (error == IIC_ESTATUS ? 0 : error); +} + /* * Amount of unread data before next burst to get better I2C bus utilization. * 2 bytes is enough in FAST mode. 8 bytes is better in FAST+ and HIGH modes. @@ -584,8 +613,27 @@ ig4iic_transfer(device_t dev, struct iic_msg *msgs, ui else error = ig4iic_write(sc, msgs[i].buf, msgs[i].len, rpstart, stop); - if (error != 0) + + if (error != 0) { + /* + * Send STOP condition if it's not done yet and flush + * both FIFOs. Do a controller soft reset if transfer + * abort is failed. + */ + if (ig4iic_xfer_is_started(sc) && + ig4iic_xfer_abort(sc) != 0) { + device_printf(sc->dev, "Failed to abort " + "transfer. Do the controller reset.\n"); + ig4iic_set_config(sc, true); + } else { + while (reg_read(sc, IG4_REG_I2C_STA) & + IG4_STATUS_RX_NOTEMPTY) + reg_read(sc, IG4_REG_DATA_CMD); + reg_read(sc, IG4_REG_TX_ABRT_SOURCE); + reg_read(sc, IG4_REG_CLR_INTR); + } break; + } rpstart = !stop; } @@ -843,7 +891,7 @@ ig4iic_get_config(ig4iic_softc_t *sc) } static int -ig4iic_set_config(ig4iic_softc_t *sc) +ig4iic_set_config(ig4iic_softc_t *sc, bool reset) { uint32_t v; @@ -851,10 +899,16 @@ ig4iic_set_config(ig4iic_softc_t *sc) if (sc->version == IG4_SKYLAKE && (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); + reset = true; + } + 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); + } else if (sc->version == IG4_SKYLAKE && reset) { reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL); reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL); - DELAY(1000); } if (sc->version == IG4_ATOM) @@ -922,6 +976,9 @@ ig4iic_set_config(ig4iic_softc_t *sc) IG4_CTL_RESTARTEN | (sc->cfg.bus_speed & IG4_CTL_SPEED_MASK)); + /* Force setting of the target address on the next transfer */ + sc->slave_valid = 0; + return (0); } @@ -938,7 +995,7 @@ ig4iic_attach(ig4iic_softc_t *sc) ig4iic_get_config(sc); - error = ig4iic_set_config(sc); + error = ig4iic_set_config(sc, false); if (error) goto done; @@ -949,19 +1006,6 @@ ig4iic_attach(ig4iic_softc_t *sc) goto done; } -#if 0 - /* - * Don't do this, it blows up the PCI config - */ - if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { - reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW); - reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW); - } else if (sc->version = IG4_SKYLAKE) { - reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL); - reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL); - } -#endif - if (set_controller(sc, IG4_I2C_ENABLE)) { device_printf(sc->dev, "controller error during attach-2\n"); error = ENXIO; @@ -1051,10 +1095,8 @@ int ig4iic_resume(ig4iic_softc_t *sc) int error; sx_xlock(&sc->call_lock); - if (ig4iic_set_config(sc)) + if (ig4iic_set_config(sc, sc->version == IG4_SKYLAKE)) device_printf(sc->dev, "controller error during resume\n"); - /* Force setting of the target address on the next transfer */ - sc->slave_valid = 0; sx_xunlock(&sc->call_lock); error = bus_generic_resume(sc->dev); Modified: head/sys/dev/ichiic/ig4_reg.h ============================================================================== --- head/sys/dev/ichiic/ig4_reg.h Sun Nov 3 21:07:12 2019 (r354314) +++ head/sys/dev/ichiic/ig4_reg.h Sun Nov 3 21:08:26 2019 (r354315) @@ -383,7 +383,9 @@ * I2C_EN - (RW) I2C Enable Register 22.2.22 * * ABORT Software can abort an I2C transfer by setting this - * bit. Hardware will clear the bit once the STOP has + * bit. In response, the controller issues the STOP + * condition over the I2C bus, followed by TX FIFO flush. + * Hardware will clear the bit once the STOP has * been detected. This bit can only be set while the * I2C interface is enabled. *
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911032108.xA3L8Quq072214>