intel/fsp_baytrail: Fix I2C abort logic

A call to i2c_read() for a non-existent address followed by an i2c_read()
to a valid address results in a false abort status for the 2nd call.

i2c_read(1, 0x40, 0, buf, sizeof(buf)) => 0x2000000 (I2C_ERR_TIMEOUT)
i2c_read(1, 0x74, 0, buf, sizeof(buf)) => 0x4000000 (I2C_ERR_ABORT)

Because the abort status register is cleared on read and wait_tx_fifo()
reads it twice, the returned status does not contain the abort status.
Fixing that changed the 2nd read to reflect the abort status.

i2c_read(1, 0x40, 0, buf, sizeof(buf)) => 0x2000000 (I2C_ERR_TIMEOUT)
i2c_read(1, 0x74, 0, buf, sizeof(buf)) => 0x4000001 (I2C_ERR_ABORT)

Bit 0 indicates that the address was not acknowledged by any slave.
That's the abort status from the previous transaction.
So I added a read of the abort status before starting a transaction in
both i2c_read() and i2c_write().

i2c_read(1, 0x40, 0, buf, sizeof(buf)) => 0x2000000 (I2C_ERR_TIMEOUT)
i2c_read(1, 0x74, 0, buf, sizeof(buf)) => 0 (I2C_SUCCESS)

Tested on a Bay Trail E3845 SoC.

Change-Id: I39e4ff4206587267b6fceef58f4a567bf162fbbe
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
Reviewed-on: https://review.coreboot.org/14160
Tested-by: build bot (Jenkins)
Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
This commit is contained in:
Ben Gardner 2016-03-23 09:40:37 -05:00 committed by Martin Roth
parent 5aecd0e533
commit 77e351d9d1
1 changed files with 19 additions and 8 deletions

View File

@ -26,12 +26,13 @@
static int wait_tx_fifo(char *base_adr) static int wait_tx_fifo(char *base_adr)
{ {
int i; int i;
u32 as;
if (read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff) { as = read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff;
if (as) {
/* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */ /* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */
i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT)); i = read32(base_adr + I2C_CLR_TX_ABRT);
return I2C_ERR_ABORT | return I2C_ERR_ABORT | as;
(*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
} }
/* Wait here for a free slot in TX-FIFO */ /* Wait here for a free slot in TX-FIFO */
@ -51,11 +52,13 @@ static int wait_tx_fifo(char *base_adr)
static int wait_rx_fifo(char *base_adr) static int wait_rx_fifo(char *base_adr)
{ {
int i; int i;
if (read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff) { u32 as;
as = read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff;
if (as) {
/* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */ /* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */
i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT)); i = read32(base_adr + I2C_CLR_TX_ABRT);
return I2C_ERR_ABORT | return I2C_ERR_ABORT | as;
(*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
} }
/* Wait here for a received entry in RX-FIFO */ /* Wait here for a received entry in RX-FIFO */
@ -177,6 +180,10 @@ int i2c_read(unsigned bus, unsigned chip, unsigned addr,
stat = wait_for_idle(base_ptr); stat = wait_for_idle(base_ptr);
if (stat != I2C_SUCCESS) if (stat != I2C_SUCCESS)
return stat; return stat;
/* clear any abort status from a previous transaction */
read32(base_ptr + I2C_CLR_TX_ABRT);
/* Now we can program the desired slave address and start transfer */ /* Now we can program the desired slave address and start transfer */
write32(base_ptr + I2C_TARGET_ADR, chip & 0xff); write32(base_ptr + I2C_TARGET_ADR, chip & 0xff);
/* Send address inside slave to read from */ /* Send address inside slave to read from */
@ -232,6 +239,10 @@ int i2c_write(unsigned bus, unsigned chip, unsigned addr,
if (stat) { if (stat) {
return stat; return stat;
} }
/* clear any abort status from a previous transaction */
read32(base_ptr + I2C_CLR_TX_ABRT);
/* Program slave address to use for this transfer */ /* Program slave address to use for this transfer */
write32(base_ptr + I2C_TARGET_ADR, chip & 0xff); write32(base_ptr + I2C_TARGET_ADR, chip & 0xff);