summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorGuenter Roeck2018-09-25 15:02:31 +0200
committerPeter Maydell2018-09-25 15:14:07 +0200
commitbb626e5b43df996a19b53cb6033b25d83f7b2e73 (patch)
tree28bcc994833126369ce0298eb53ffacec9ccb38e /hw
parentaspeed/i2c: Handle receive command in separate function (diff)
downloadqemu-bb626e5b43df996a19b53cb6033b25d83f7b2e73.tar.gz
qemu-bb626e5b43df996a19b53cb6033b25d83f7b2e73.tar.xz
qemu-bb626e5b43df996a19b53cb6033b25d83f7b2e73.zip
aspeed/i2c: Fix receive done interrupt handling
The AST2500 datasheet says: I2CD10 Interrupt Status Register bit 2 Receive Done Interrupt status S/W needs to clear this status bit to allow next data receiving The Rx interrupt done interrupt status bit needs to be cleared explicitly before the next byte can be received, and must therefore not be auto-cleared. Also, receiving the next byte must be delayed until the bit has been cleared. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Cédric Le Goater <clg@kaod.org> Message-id: 20180914063506.20815-4-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/i2c/aspeed_i2c.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index ce16efc136..a2dfa82760 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -252,7 +252,8 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
aspeed_i2c_set_state(bus, I2CD_MACTIVE);
}
- if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) {
+ if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) &&
+ !(bus->intr_status & I2CD_INTR_RX_DONE)) {
aspeed_i2c_handle_rx_cmd(bus);
}
@@ -274,6 +275,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
AspeedI2CBus *bus = opaque;
+ bool handle_rx;
switch (offset) {
case I2CD_FUN_CTRL_REG:
@@ -294,11 +296,17 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
bus->intr_ctrl = value & 0x7FFF;
break;
case I2CD_INTR_STS_REG:
+ handle_rx = (bus->intr_status & I2CD_INTR_RX_DONE) &&
+ (value & I2CD_INTR_RX_DONE);
bus->intr_status &= ~(value & 0x7FFF);
if (!bus->intr_status) {
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(bus->controller->irq);
}
+ if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) {
+ aspeed_i2c_handle_rx_cmd(bus);
+ aspeed_i2c_bus_raise_interrupt(bus);
+ }
break;
case I2CD_DEV_ADDR_REG:
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",