sb/intel/common: SMBus execute_command()
Implement the common start of transaction. Fixes a problem where smbus_wait_until_active() can miss SMBHSTSTS_HOST_BUSY being set, if transaction completes very fast. Or if we are single-stepping or executing under SerialIce emulation. Change-Id: Icb27d7d6a1c54968950ca292dbae05415f97e461 Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Reviewed-on: https://review.coreboot.org/c/21119 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
This commit is contained in:
parent
957511cd92
commit
a2dcf735e4
|
@ -101,19 +101,31 @@ static int setup_command(unsigned int smbus_base, u8 ctrl, u8 xmitadd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smbus_wait_until_active(u16 smbus_base)
|
static int execute_command(unsigned int smbus_base)
|
||||||
{
|
{
|
||||||
unsigned long loops;
|
unsigned int loops = SMBUS_TIMEOUT;
|
||||||
loops = SMBUS_TIMEOUT;
|
u8 status;
|
||||||
|
|
||||||
|
/* Start the command. */
|
||||||
|
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
||||||
|
smbus_base + SMBHSTCTL);
|
||||||
|
|
||||||
|
/* Poll for it to start. */
|
||||||
do {
|
do {
|
||||||
unsigned char val;
|
|
||||||
smbus_delay();
|
smbus_delay();
|
||||||
val = inb(smbus_base + SMBHSTSTAT);
|
|
||||||
if ((val & SMBHSTSTS_HOST_BUSY)) {
|
/* If we poll too slow, we could miss HOST_BUSY flag
|
||||||
break;
|
* set and detect INTR or x_ERR flags instead here.
|
||||||
}
|
*/
|
||||||
} while (--loops);
|
status = inb(smbus_base + SMBHSTSTAT);
|
||||||
return loops ? 0 : -1;
|
status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
|
||||||
|
} while (--loops && status == 0);
|
||||||
|
|
||||||
|
if (loops == 0)
|
||||||
|
return recover_master(smbus_base,
|
||||||
|
SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smbus_wait_until_done(u16 smbus_base)
|
static int smbus_wait_until_done(u16 smbus_base)
|
||||||
|
@ -149,12 +161,9 @@ int do_smbus_read_byte(unsigned int smbus_base, u8 device,
|
||||||
outb(0, smbus_base + SMBHSTDAT0);
|
outb(0, smbus_base + SMBHSTDAT0);
|
||||||
|
|
||||||
/* Start the command */
|
/* Start the command */
|
||||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
ret = execute_command(smbus_base);
|
||||||
smbus_base + SMBHSTCTL);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
/* poll for it to start */
|
|
||||||
if (smbus_wait_until_active(smbus_base) < 0)
|
|
||||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
|
||||||
|
|
||||||
/* Poll for transaction completion */
|
/* Poll for transaction completion */
|
||||||
if (smbus_wait_until_done(smbus_base) < 0)
|
if (smbus_wait_until_done(smbus_base) < 0)
|
||||||
|
@ -190,12 +199,9 @@ int do_smbus_write_byte(unsigned int smbus_base, u8 device,
|
||||||
outb(data, smbus_base + SMBHSTDAT0);
|
outb(data, smbus_base + SMBHSTDAT0);
|
||||||
|
|
||||||
/* Start the command */
|
/* Start the command */
|
||||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
ret = execute_command(smbus_base);
|
||||||
smbus_base + SMBHSTCTL);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
/* poll for it to start */
|
|
||||||
if (smbus_wait_until_active(smbus_base) < 0)
|
|
||||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
|
||||||
|
|
||||||
/* Poll for transaction completion */
|
/* Poll for transaction completion */
|
||||||
if (smbus_wait_until_done(smbus_base) < 0)
|
if (smbus_wait_until_done(smbus_base) < 0)
|
||||||
|
@ -236,12 +242,9 @@ int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
|
||||||
outb(0, smbus_base + SMBHSTDAT0);
|
outb(0, smbus_base + SMBHSTDAT0);
|
||||||
|
|
||||||
/* Start the command */
|
/* Start the command */
|
||||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
ret = execute_command(smbus_base);
|
||||||
smbus_base + SMBHSTCTL);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
/* poll for it to start */
|
|
||||||
if (smbus_wait_until_active(smbus_base) < 0)
|
|
||||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
|
||||||
|
|
||||||
/* Poll for transaction completion */
|
/* Poll for transaction completion */
|
||||||
do {
|
do {
|
||||||
|
@ -306,12 +309,9 @@ int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
|
||||||
outb(*buf++, smbus_base + SMBBLKDAT);
|
outb(*buf++, smbus_base + SMBBLKDAT);
|
||||||
|
|
||||||
/* Start the command */
|
/* Start the command */
|
||||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
ret = execute_command(smbus_base);
|
||||||
smbus_base + SMBHSTCTL);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
/* poll for it to start */
|
|
||||||
if (smbus_wait_until_active(smbus_base) < 0)
|
|
||||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
|
||||||
|
|
||||||
/* Poll for transaction completion */
|
/* Poll for transaction completion */
|
||||||
do {
|
do {
|
||||||
|
@ -367,12 +367,9 @@ int do_i2c_block_read(unsigned int smbus_base, u8 device,
|
||||||
outb(offset, smbus_base + SMBHSTDAT1);
|
outb(offset, smbus_base + SMBHSTDAT1);
|
||||||
|
|
||||||
/* Start the command */
|
/* Start the command */
|
||||||
outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
|
ret = execute_command(smbus_base);
|
||||||
smbus_base + SMBHSTCTL);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
/* poll for it to start */
|
|
||||||
if (smbus_wait_until_active(smbus_base) < 0)
|
|
||||||
return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
|
|
||||||
|
|
||||||
/* Poll for transaction completion */
|
/* Poll for transaction completion */
|
||||||
do {
|
do {
|
||||||
|
|
Loading…
Reference in New Issue