---
hw/i2c/aspeed_i2c.c | 87 +++++++++++++++++++++++++++++++--------------
1 file changed, 61 insertions(+), 26 deletions(-)
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 1ee73a8f5e..fb3d6a5600 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -116,8 +116,6 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus,
hwaddr offset,
value = -1;
break;
}
-
- value = extract64(bus->dma_dram_offset, 0, 32);
break;
case A_I2CD_DMA_LEN:
if (!aic->has_dma) {
@@ -221,6 +219,64 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE);
}
+/*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0_0000_0000 to
+ * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
+static void aspeed_i2c_set_tx_dma_dram_offset(AspeedI2CBus *bus)
+{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+ uint32_t value;
+
+ assert(aic->has_dma);
+
+ if (aspeed_i2c_is_new_mode(bus->controller)) {
+ value = bus->regs[R_I2CM_DMA_TX_ADDR];
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR));
+ if (!aic->has_dma64) {
+ value = bus->regs[R_I2CM_DMA_TX_ADDR_HI];
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ }
+ } else {
+ value = bus->regs[R_I2CD_DMA_ADDR];
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
+ value & 0x3ffffffc);
+ }
+}
+
+static void aspeed_i2c_set_rx_dma_dram_offset(AspeedI2CBus *bus)
+{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+ uint32_t value;
+
+ assert(aic->has_dma);
+
+ if (aspeed_i2c_is_new_mode(bus->controller)) {
+ value = bus->regs[R_I2CM_DMA_RX_ADDR];
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR));
+ if (!aic->has_dma64) {
+ value = bus->regs[R_I2CM_DMA_RX_ADDR_HI];
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ }
+ } else {
+ value = bus->regs[R_I2CD_DMA_ADDR];
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
+ value & 0x3ffffffc);
+ }
+}
+
static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
{
MemTxResult result;
@@ -270,6 +326,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus)
if (aspeed_i2c_is_new_mode(bus->controller)) {
ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0);
}
+ aspeed_i2c_set_tx_dma_dram_offset(bus);
while (bus->regs[reg_dma_len]) {
uint8_t data;
ret = aspeed_i2c_dma_read(bus, &data);
@@ -335,6 +392,7 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0);
}
+ aspeed_i2c_set_rx_dma_dram_offset(bus);
while (bus->regs[reg_dma_len]) {
MemTxResult result;
@@ -401,6 +459,7 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
} else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) {
uint8_t data;
+ aspeed_i2c_set_tx_dma_dram_offset(bus);
aspeed_i2c_dma_read(bus, &data);
return data;
} else {
@@ -657,16 +716,10 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus,
hwaddr offset,
case A_I2CM_DMA_TX_ADDR:
bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
ADDR);
- bus->dma_dram_offset =
- deposit64(bus->dma_dram_offset, 0, 32,
- FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR));
break;
case A_I2CM_DMA_RX_ADDR:
bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR,
ADDR);
- bus->dma_dram_offset =
- deposit64(bus->dma_dram_offset, 0, 32,
- FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR));
break;
case A_I2CM_DMA_LEN:
w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) ||
@@ -748,15 +801,6 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus,
hwaddr offset,
qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
__func__);
break;
-
- /*
- * The AST2700 support the maximum DRAM size is 8 GB.
- * The DRAM offset range is from 0x0_0000_0000 to
- * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
- * saving the dram offset.
- * Therefore, save the high part physical address bit[1:0]
- * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
- */
case A_I2CM_DMA_TX_ADDR_HI:
if (!aic->has_dma64) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
@@ -766,8 +810,6 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus,
hwaddr offset,
bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
I2CM_DMA_TX_ADDR_HI,
ADDR_HI);
- bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
- extract32(value, 0, 2));
break;
case A_I2CM_DMA_RX_ADDR_HI:
if (!aic->has_dma64) {
@@ -778,8 +820,6 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus,
hwaddr offset,
bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
I2CM_DMA_RX_ADDR_HI,
ADDR_HI);
- bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
- extract32(value, 0, 2));
break;
case A_I2CS_DMA_TX_ADDR_HI:
qemu_log_mask(LOG_UNIMP,
@@ -795,8 +835,6 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus,
hwaddr offset,
bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
I2CS_DMA_RX_ADDR_HI,
ADDR_HI);
- bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
- extract32(value, 0, 2));
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@@ -887,9 +925,6 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus,
hwaddr offset,
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
-
- bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
- value & 0x3ffffffc);
break;
case A_I2CD_DMA_LEN: