From owner-svn-src-head@freebsd.org Sun Nov 3 21:08:27 2019 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 87D691A2F72; Sun, 3 Nov 2019 21:08:27 +0000 (UTC) (envelope-from wulf@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 475pSC2rgnz4FlN; Sun, 3 Nov 2019 21:08:27 +0000 (UTC) (envelope-from wulf@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 458C319B87; Sun, 3 Nov 2019 21:08:27 +0000 (UTC) (envelope-from wulf@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id xA3L8RPN072215; Sun, 3 Nov 2019 21:08:27 GMT (envelope-from wulf@FreeBSD.org) Received: (from wulf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id xA3L8Quq072214; Sun, 3 Nov 2019 21:08:26 GMT (envelope-from wulf@FreeBSD.org) Message-Id: <201911032108.xA3L8Quq072214@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: wulf set sender to wulf@FreeBSD.org using -f From: Vladimir Kondratyev Date: Sun, 3 Nov 2019 21:08:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354315 - head/sys/dev/ichiic X-SVN-Group: head X-SVN-Commit-Author: wulf X-SVN-Commit-Paths: head/sys/dev/ichiic X-SVN-Commit-Revision: 354315 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 03 Nov 2019 21:08:27 -0000 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. *