From 57097130d5e4880e39ce8f63eba6f11d7c51e94c Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Mon, 11 Apr 2022 17:10:09 -0500 Subject: drivers/i2c/dw_i2c: Adjust to handle 0-byte transfers 0-byte writes can be used as a way to probe/check presence of an i2c device, so adjust _dw_i2c_transfer() to immediately set the STOP bit and raise logger level for TX abort messages when the segment length is zero. Adjust dw_i2c_transfer() to allow zero-segment-length messages to be passed thru to _dw_i2c_transfer(). Tested as part of entire i2c-detect patch train. Change-Id: I518e849f4c476c264a1464886b1853af66c0b29d Signed-off-by: Matt DeVillier Reviewed-on: https://review.coreboot.org/c/coreboot/+/63561 Tested-by: build bot (Jenkins) Reviewed-by: Martin L Roth Reviewed-by: Tim Wawrzynczak --- src/drivers/i2c/designware/dw_i2c.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/i2c/designware/dw_i2c.c b/src/drivers/i2c/designware/dw_i2c.c index 761fa914b4..fdedf63b56 100644 --- a/src/drivers/i2c/designware/dw_i2c.c +++ b/src/drivers/i2c/designware/dw_i2c.c @@ -358,6 +358,7 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm struct dw_i2c_regs *regs; size_t byte; enum cb_err ret = CB_ERR; + bool seg_zero_len = segments->len == 0; regs = (struct dw_i2c_regs *)dw_i2c_base_address(bus); if (!regs) { @@ -374,6 +375,10 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm dw_i2c_enable(regs); + if (seg_zero_len) + /* stop immediately */ + write32(®s->cmd_data, CMD_DATA_STOP); + /* Process each segment */ while (count--) { if (CONFIG(DRIVERS_I2C_DESIGNWARE_DEBUG)) { @@ -424,8 +429,8 @@ static enum cb_err _dw_i2c_transfer(unsigned int bus, const struct i2c_msg *segm /* 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)); + printk(seg_zero_len ? BIOS_SPEW : 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; @@ -462,7 +467,7 @@ static enum cb_err dw_i2c_transfer(unsigned int bus, const struct i2c_msg *msg, size_t start; uint16_t addr; - if (count == 0 || !msg) + if (!msg) return -1; /* Break up the transfers at the differing slave address boundary. */ -- cgit v1.2.3