diff options
author | Kangheui Won <khwon@chromium.org> | 2020-11-09 17:49:48 +1100 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2020-11-16 11:00:57 +0000 |
commit | b2c39b563a29c1e7057faa40957345c2b0faecd5 (patch) | |
tree | 89e9ec1c80e6d11dbd6fb6d4f639599e6d7e4109 /src/drivers/i2c/designware | |
parent | 93231b45e4db858825d46fe8594200faf657df4d (diff) | |
download | coreboot-b2c39b563a29c1e7057faa40957345c2b0faecd5.tar.xz |
drivers/i2c/dw: Check for TX_ABORT in transfer
When the host sends data in i2c bus, device might not send ACK. It means
that data is not processed on the device side, but for now we don't
check for that condition thus wait for the response which will not come.
Designware i2c detect such situation and set TX_ABORT bit. Checking for
the bit will enable other layers to immediately retry rather than
wait-timeout-retry cycle.
BUG=b:168838505
BRANCH=zork
TEST=test on zork devices, now we see "Tx abort detected" instead of I2C
timeout for tpm initializtion.
Change-Id: Ib0163fbce55ccc99f677dbb096f67a58d2ef2bda
Signed-off-by: Kangheui Won <khwon@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/47360
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Diffstat (limited to 'src/drivers/i2c/designware')
-rw-r--r-- | src/drivers/i2c/designware/dw_i2c.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/src/drivers/i2c/designware/dw_i2c.c b/src/drivers/i2c/designware/dw_i2c.c index 3181e7a0cf..c0212c3e27 100644 --- a/src/drivers/i2c/designware/dw_i2c.c +++ b/src/drivers/i2c/designware/dw_i2c.c @@ -419,6 +419,15 @@ static int _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segments, /* Read to clear INTR_STAT_STOP_DET */ read32(®s->clear_stop_det_intr); + /* Check TX abort */ + if (read32(®s->raw_intr_stat) & INTR_STAT_TX_ABORT) { + printk(BIOS_ERR, "I2C TX abort detected (%08x)\n", + read32(®s->tx_abort_source)); + /* clear INTR_STAT_TX_ABORT */ + read32(®s->clear_tx_abrt_intr); + goto out; + } + /* Wait for the bus to go idle */ if (dw_i2c_wait_for_bus_idle(regs)) { printk(BIOS_ERR, "I2C timeout waiting for bus %u idle\n", bus); @@ -747,8 +756,8 @@ int dw_i2c_init(unsigned int bus, const struct dw_i2c_bus_config *bcfg) write32(®s->rx_thresh, 0); write32(®s->tx_thresh, 0); - /* Enable stop detection interrupt */ - write32(®s->intr_mask, INTR_STAT_STOP_DET); + /* Enable stop detection and TX abort interrupt */ + write32(®s->intr_mask, INTR_STAT_STOP_DET | INTR_STAT_TX_ABORT); printk(BIOS_INFO, "DW I2C bus %u at %p (%u KHz)\n", bus, regs, speed / KHz); |