summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorKangheui Won <khwon@chromium.org>2020-11-09 17:49:48 +1100
committerPatrick Georgi <pgeorgi@google.com>2020-11-16 11:00:57 +0000
commitb2c39b563a29c1e7057faa40957345c2b0faecd5 (patch)
tree89e9ec1c80e6d11dbd6fb6d4f639599e6d7e4109 /src/drivers
parent93231b45e4db858825d46fe8594200faf657df4d (diff)
downloadcoreboot-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')
-rw-r--r--src/drivers/i2c/designware/dw_i2c.c13
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(&regs->clear_stop_det_intr);
+ /* Check TX abort */
+ if (read32(&regs->raw_intr_stat) & INTR_STAT_TX_ABORT) {
+ printk(BIOS_ERR, "I2C TX abort detected (%08x)\n",
+ read32(&regs->tx_abort_source));
+ /* clear INTR_STAT_TX_ABORT */
+ read32(&regs->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(&regs->rx_thresh, 0);
write32(&regs->tx_thresh, 0);
- /* Enable stop detection interrupt */
- write32(&regs->intr_mask, INTR_STAT_STOP_DET);
+ /* Enable stop detection and TX abort interrupt */
+ write32(&regs->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);