@samitouri / QOSamiQemu / commits / c880521fa5

hw/i2c/aspeed_i2c: Introduce dma_addr_lo_mask to unify DMA address handling

The Aspeed I2C controller has two register layouts. The AST2500 uses the old mode with a single DMA address register (I2CD_DMA_ADDR) where the address is 4-byte aligned and masked to 0x3ffffffc. >From AST2600 onwards, the new mode provides separate master TX/RX and slave RX DMA address registers (I2CM_DMA_TX_ADDR, I2CM_DMA_RX_ADDR, I2CS_DMA_RX_ADDR) with different address widths per SoC: AST2600 (new mode): 0x7fffffff - bits[30:0] AST1030 (new mode): 0x7fffffff - bits[30:0] AST1060 (new mode): 0x7fffffff - bits[30:0] AST2700 (new mode): 0xffffffff - bits[31:0] Introduce dma_addr_lo_mask as a per-class attribute and apply it uniformly when storing DMA address register writes and when loading the address into dma_dram_offset for both master and slave paths. This replaces the previous FIELD_EX32 extractions (which incorrectly stripped bit 31 on AST2700) and the hardcoded 0x3ffffffc literal in the old-mode path. Fixes: 1809ab6a67359e0876981cd05d2a50b2843eabad ("hw/i2c/aspeed: Add AST2700 support") Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260603040027.938816-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Jun 3, 2026 at 04:00 UTC c880521fa5b4b9ff56b1778df705e7ac6f260e1c
2 files changed +15 -14
hw/i2c/aspeed_i2c.c
+14 -10
@@ -236,7 +236,7 @@ static void aspeed_i2c_set_tx_dma_dram_offset(AspeedI2CBus *bus)
236 value = bus->regs[R_I2CM_DMA_TX_ADDR];
237 bus->dma_dram_offset =
238 deposit64(bus->dma_dram_offset, 0, 32,
239 - FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR));
239 + value & aic->dma_addr_lo_mask);
240 if (aic->has_dma64) {
241 value = bus->regs[R_I2CM_DMA_TX_ADDR_HI];
242 bus->dma_dram_offset =
@@ -246,7 +246,7 @@ static void aspeed_i2c_set_tx_dma_dram_offset(AspeedI2CBus *bus)
246 } else {
247 value = bus->regs[R_I2CD_DMA_ADDR];
248 bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
249 - value & 0x3ffffffc);
249 + value & aic->dma_addr_lo_mask);
250 }
251 }
252
@@ -261,7 +261,7 @@ static void aspeed_i2c_set_rx_dma_dram_offset(AspeedI2CBus *bus)
261 value = bus->regs[R_I2CM_DMA_RX_ADDR];
262 bus->dma_dram_offset =
263 deposit64(bus->dma_dram_offset, 0, 32,
264 - FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR));
264 + value & aic->dma_addr_lo_mask);
265 if (aic->has_dma64) {
266 value = bus->regs[R_I2CM_DMA_RX_ADDR_HI];
267 bus->dma_dram_offset =
@@ -271,7 +271,7 @@ static void aspeed_i2c_set_rx_dma_dram_offset(AspeedI2CBus *bus)
271 } else {
272 value = bus->regs[R_I2CD_DMA_ADDR];
273 bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
274 - value & 0x3ffffffc);
274 + value & aic->dma_addr_lo_mask);
275 }
276 }
277
@@ -735,12 +735,10 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
735 aspeed_i2c_bus_raise_interrupt(bus);
736 break;
737 case A_I2CM_DMA_TX_ADDR:
738 - bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
739 - ADDR);
738 + bus->regs[R_I2CM_DMA_TX_ADDR] = value & aic->dma_addr_lo_mask;
739 break;
740 case A_I2CM_DMA_RX_ADDR:
742 - bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR,
743 - ADDR);
741 + bus->regs[R_I2CM_DMA_RX_ADDR] = value & aic->dma_addr_lo_mask;
742 break;
743 case A_I2CM_DMA_LEN:
744 w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) ||
@@ -777,7 +775,7 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
775 bus->regs[R_I2CS_DEV_ADDR] = value;
776 break;
777 case A_I2CS_DMA_RX_ADDR:
780 - bus->regs[R_I2CS_DMA_RX_ADDR] = value;
778 + bus->regs[R_I2CS_DMA_RX_ADDR] = value & aic->dma_addr_lo_mask;
779 break;
780 case A_I2CS_DMA_LEN:
781 if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) {
@@ -1375,6 +1373,8 @@ static void aspeed_i2c_class_init(ObjectClass *klass, const void *data)
1373 static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
1374 enum i2c_event event)
1375 {
1376 + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
1377 +
1378 switch (event) {
1379 case I2C_START_SEND_ASYNC:
1380 if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) {
@@ -1385,7 +1385,7 @@ static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
1385 ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
1386 bus->dma_dram_offset =
1387 deposit64(bus->dma_dram_offset, 0, 32,
1388 - ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR));
1388 + bus->regs[R_I2CS_DMA_RX_ADDR] & aic->dma_addr_lo_mask);
1389 bus->regs[R_I2CC_DMA_LEN] =
1390 ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
1391 i2c_ack(bus->bus);
@@ -1608,6 +1608,7 @@ static void aspeed_2500_i2c_class_init(ObjectClass *klass, const void *data)
1608 aic->check_sram = true;
1609 aic->has_dma = true;
1610 aic->mem_size = 0x1000;
1611 + aic->dma_addr_lo_mask = 0x3ffffffc;
1612 }
1613
1614 static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus)
@@ -1631,6 +1632,7 @@ static void aspeed_2600_i2c_class_init(ObjectClass *klass, const void *data)
1632 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
1633 aic->has_dma = true;
1634 aic->mem_size = 0x1000;
1635 + aic->dma_addr_lo_mask = 0x7fffffff;
1636 }
1637
1638 static void aspeed_1030_i2c_class_init(ObjectClass *klass, const void *data)
@@ -1649,6 +1651,7 @@ static void aspeed_1030_i2c_class_init(ObjectClass *klass, const void *data)
1651 aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
1652 aic->has_dma = true;
1653 aic->mem_size = 0x10000;
1654 + aic->dma_addr_lo_mask = 0x7fffffff;
1655 }
1656
1657 static void aspeed_2700_i2c_class_init(ObjectClass *klass, const void *data)
@@ -1670,6 +1673,7 @@ static void aspeed_2700_i2c_class_init(ObjectClass *klass, const void *data)
1673 aic->has_dma = true;
1674 aic->mem_size = 0x2000;
1675 aic->has_dma64 = true;
1676 + aic->dma_addr_lo_mask = 0xffffffff;
1677 }
1678
1679 static const TypeInfo aspeed_i2c_types[] = {
include/hw/i2c/aspeed_i2c.h
+1 -4
@@ -209,13 +209,9 @@ REG32(I2CS_DMA_LEN, 0x2c)
209 FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
210 FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11)
211 REG32(I2CM_DMA_TX_ADDR, 0x30)
212 - FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31)
212 REG32(I2CM_DMA_RX_ADDR, 0x34)
214 - FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31)
213 REG32(I2CS_DMA_TX_ADDR, 0x38)
216 - FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31)
214 REG32(I2CS_DMA_RX_ADDR, 0x3c)
218 - FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31)
215 REG32(I2CS_DEV_ADDR, 0x40)
216 REG32(I2CM_DMA_LEN_STS, 0x48)
217 FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13)
@@ -303,6 +299,7 @@ struct AspeedI2CClass {
299 bool has_share_pool;
300 uint64_t mem_size;
301 bool has_dma64;
302 + uint32_t dma_addr_lo_mask;
303 };
304
305 static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)