Merge tag 'pull-aspeed-20240916' of https://github.com/legoater/qemu into staging
aspeed queue:
* I2C support for AST2700
* Coverity fixes
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmbofzEACgkQUaNDx8/7
# 7KHo4g//RtzY1oM+5xbX7LA4Nb45EJtAs9+UvbvDF7++NF9Nd4VThdoyBSvzyqd8
# 9Z35Mfoh1xce7+Qz/QtobbRkPLKtq7rfmj4lCkXZRGR/0nbDteqyLOqDM/E/GSBc
# mEaMG9sT2L1t9SrKOYIhgoPSpS0kpJ0YHfMLt5DcTjLQ1g8OB7ByzOPoPSBzTPAf
# QLL/v0GTxdqQPRhcZJKGclkjeVwBtFpo1rbDe/tHfFKC51g3cROGyQEswuPxRqDB
# Y3CQ0WC7awqSg7WAUwTfyb6LNSmYoiycGKv/gi06kc/mxjpf2qQ2khX4diiPoOj0
# Ak1b/dv2DWKE8LDYw7ew44UdPyIhGhgFeYeJ1olz5oLUcdcd4PuBWBvLUgpJKEfk
# HRXcJyhat3rwWGYzrdCJbBPN6CPncWjyifg1X6jK6Eu4wnfdpB9m64xFg8TpALaz
# SRZGg0ahldBwU6jjDO3x/RMWzKCtzwAjDuLfxSlqDGPx5OL+0dDDEa+xj45VzzBZ
# aT5Kcy9ga9DgRUw4wds3NHz9uCxwXoktDkW3vKMeMdftAf6er+Inhe8FHer/JSh4
# wuCxUDYIUSate5QoVucHAAM3DqOCQ1ascugufluXAR4StJ/u2b3SXU881C7v4crP
# NDncQEsWgya+Ykv9lXgulDxZrc8qsSmj4aoRNtJHaGsxmb4RwSY=
# =NyK5
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 16 Sep 2024 19:55:45 BST
# gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1
* tag 'pull-aspeed-20240916' of https://github.com/legoater/qemu:
machine_aspeed.py: Update to test I2C for AST2700
aspeed: Add tmp105 in i2c bus 0 for AST2700
aspeed/soc: Support I2C for AST2700
aspeed/soc: Introduce a new API to get the device irq
hw/i2c/aspeed: Add support for 64 bit addresses
hw/i2c/aspeed: Add support for Tx/Rx buffer 64 bit addresses
hw/i2c/aspeed: Add AST2700 support
hw/i2c/aspeed: Introduce a new dma_dram_offset attribute in AspeedI2Cbus
hw/i2c/aspeed: Support discontinuous poll buffer memory region of I2C bus
hw/i2c/aspeed: Introduce a new bus pool buffer attribute in AspeedI2Cbus
hw/i2c/aspeed: Support discontinuous register memory region of I2C bus
hw/gpio/aspeed_gpio: Avoid shift into sign bit
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index fd5603f..3d13b16 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1650,6 +1650,15 @@
}
#ifdef TARGET_AARCH64
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = bmc->soc;
+
+ /* LM75 is compatible with TMP105 driver */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+ TYPE_TMP105, 0x4d);
+}
+
static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1664,6 +1673,7 @@
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
amc->uart_default = ASPEED_DEV_UART12;
+ amc->i2c_init = ast2700_evb_i2c_init;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4257b5e..761ee11 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -61,6 +61,7 @@
[ASPEED_GIC_DIST] = 0x12200000,
[ASPEED_GIC_REDIST] = 0x12280000,
[ASPEED_DEV_ADC] = 0x14C00000,
+ [ASPEED_DEV_I2C] = 0x14C0F000,
};
#define AST2700_MAX_IRQ 288
@@ -193,6 +194,27 @@
return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
}
+static qemu_irq aspeed_soc_ast2700_get_irq_index(AspeedSoCState *s, int dev,
+ int index)
+{
+ Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+ if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+ assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+ return qdev_get_gpio_in(DEVICE(&a->intc.orgates[i]),
+ aspeed_soc_ast2700_gic_intcmap[i].ptr[dev] + index);
+ }
+ }
+
+ /*
+ * Invalid orgate index, device irq should be 128 to 136.
+ */
+ g_assert_not_reached();
+}
+
static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
unsigned int size)
{
@@ -348,6 +370,9 @@
snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
object_initialize_child(obj, "adc", &s->adc, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+ object_initialize_child(obj, "i2c", &s->i2c, typename);
}
/*
@@ -431,6 +456,7 @@
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
g_autofree char *sram_name = NULL;
+ qemu_irq irq;
/* Default boot region (SPI memory or ROMs) */
memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -613,6 +639,25 @@
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
+ /* I2C */
+ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+ for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+ /*
+ * The AST2700 I2C controller has one source INTC per bus.
+ * I2C buses interrupt are connected to GICINT130_INTC
+ * from bit 0 to bit 15.
+ * I2C bus 0 is connected to GICINT130_INTC at bit 0.
+ * I2C bus 15 is connected to GICINT130_INTC at bit 15.
+ */
+ irq = aspeed_soc_ast2700_get_irq_index(s, ASPEED_DEV_I2C, i);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+ }
+
create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 3e7b35c..7175666 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -281,7 +281,7 @@
diff &= mode_mask;
if (diff) {
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
- uint32_t mask = 1 << gpio;
+ uint32_t mask = 1U << gpio;
/* If the gpio needs to be updated... */
if (!(diff & mask)) {
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index f198913..3ae22cb 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
value = -1;
+ break;
}
+
+ value = extract64(bus->dma_dram_offset, 0, 32);
break;
case A_I2CD_DMA_LEN:
if (!aic->has_dma) {
@@ -137,6 +140,7 @@
static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
unsigned size)
{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
switch (offset) {
@@ -150,9 +154,7 @@
case A_I2CM_DMA_TX_ADDR:
case A_I2CM_DMA_RX_ADDR:
case A_I2CM_DMA_LEN_STS:
- case A_I2CC_DMA_ADDR:
case A_I2CC_DMA_LEN:
-
case A_I2CS_DEV_ADDR:
case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DMA_LEN:
@@ -161,11 +163,24 @@
case A_I2CS_DMA_LEN_STS:
/* Value is already set, don't do anything. */
break;
+ case A_I2CC_DMA_ADDR:
+ value = extract64(bus->dma_dram_offset, 0, 32);
+ break;
case A_I2CS_INTR_STS:
break;
case A_I2CM_CMD:
value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
break;
+ case A_I2CM_DMA_TX_ADDR_HI:
+ case A_I2CM_DMA_RX_ADDR_HI:
+ case A_I2CS_DMA_TX_ADDR_HI:
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ value = -1;
+ }
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -210,18 +225,18 @@
{
MemTxResult result;
AspeedI2CState *s = bus->controller;
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+ result = address_space_read(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM read failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return -1;
}
- bus->regs[reg_dma_addr]++;
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
return 0;
}
@@ -291,7 +306,6 @@
uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
RX_SIZE) + 1;
@@ -323,14 +337,17 @@
data = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
bus->regs[reg_dma_len], data);
- result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+ result = address_space_write(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM write failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return;
}
- bus->regs[reg_dma_addr]++;
+
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
/* In new mode, keep track of how many bytes we RXed */
if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +653,18 @@
case A_I2CM_DMA_TX_ADDR:
bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_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));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
TX_BUF_LEN) + 1;
break;
case A_I2CM_DMA_RX_ADDR:
bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_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));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
RX_BUF_LEN) + 1;
break;
@@ -721,6 +742,56 @@
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",
+ __func__);
+ break;
+ }
+ 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) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ 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,
+ "%s: Slave mode DMA TX Addr high is not implemented\n",
+ __func__);
+ break;
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ 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",
__func__, offset);
@@ -811,7 +882,8 @@
break;
}
- bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc;
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
+ value & 0x3ffffffc);
break;
case A_I2CD_DMA_LEN:
@@ -941,12 +1013,49 @@
},
};
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ uint64_t ret = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+ }
+
+ return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+ }
+}
+
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+ .read = aspeed_i2c_bus_pool_read,
+ .write = aspeed_i2c_bus_pool_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
static const VMStateDescription aspeed_i2c_bus_vmstate = {
.name = TYPE_ASPEED_I2C,
- .version_id = 5,
- .minimum_version_id = 5,
+ .version_id = 6,
+ .minimum_version_id = 6,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+ VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
+ VMSTATE_UINT64(dma_dram_offset, AspeedI2CBus),
VMSTATE_END_OF_LIST()
}
};
@@ -996,7 +1105,21 @@
* 0x140 ... 0x17F: Device 5
* 0x180 ... 0x1BF: Device 6
* 0x1C0 ... 0x1FF: Device 7
- * 0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
+ * 0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ * 0x210 ... 0x21F: Device 2 buffer
+ * 0x220 ... 0x22F: Device 3 buffer
+ * 0x230 ... 0x23F: Device 4 buffer
+ * 0x240 ... 0x24F: Device 5 buffer
+ * 0x250 ... 0x25F: Device 6 buffer
+ * 0x260 ... 0x26F: Device 7 buffer
+ * 0x270 ... 0x27F: Device 8 buffer
+ * 0x280 ... 0x28F: Device 9 buffer
+ * 0x290 ... 0x29F: Device 10 buffer
+ * 0x2A0 ... 0x2AF: Device 11 buffer
+ * 0x2B0 ... 0x2BF: Device 12 buffer
+ * 0x2C0 ... 0x2CF: Device 13 buffer
+ * 0x2D0 ... 0x2DF: Device 14 buffer
+ * 0x2E0 ... 0x2FF: Reserved
* 0x300 ... 0x33F: Device 8
* 0x340 ... 0x37F: Device 9
* 0x380 ... 0x3BF: Device 10
@@ -1005,6 +1128,76 @@
* 0x440 ... 0x47F: Device 13
* 0x480 ... 0x4BF: Device 14
* 0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ * 0x000 ... 0x07F: Global Register
+ * 0x080 ... 0x0FF: Device 1
+ * 0x100 ... 0x17F: Device 2
+ * 0x180 ... 0x1FF: Device 3
+ * 0x200 ... 0x27F: Device 4
+ * 0x280 ... 0x2FF: Device 5
+ * 0x300 ... 0x37F: Device 6
+ * 0x380 ... 0x3FF: Device 7
+ * 0x400 ... 0x47F: Device 8
+ * 0x480 ... 0x4FF: Device 9
+ * 0x500 ... 0x57F: Device 10
+ * 0x580 ... 0x5FF: Device 11
+ * 0x600 ... 0x67F: Device 12
+ * 0x680 ... 0x6FF: Device 13
+ * 0x700 ... 0x77F: Device 14
+ * 0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ * 0x800 ... 0x87F: Device 16
+ * 0xC00 ... 0xC1F: Device 1 buffer
+ * 0xC20 ... 0xC3F: Device 2 buffer
+ * 0xC40 ... 0xC5F: Device 3 buffer
+ * 0xC60 ... 0xC7F: Device 4 buffer
+ * 0xC80 ... 0xC9F: Device 5 buffer
+ * 0xCA0 ... 0xCBF: Device 6 buffer
+ * 0xCC0 ... 0xCDF: Device 7 buffer
+ * 0xCE0 ... 0xCFF: Device 8 buffer
+ * 0xD00 ... 0xD1F: Device 9 buffer
+ * 0xD20 ... 0xD3F: Device 10 buffer
+ * 0xD40 ... 0xD5F: Device 11 buffer
+ * 0xD60 ... 0xD7F: Device 12 buffer
+ * 0xD80 ... 0xD9F: Device 13 buffer
+ * 0xDA0 ... 0xDBF: Device 14 buffer
+ * 0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
+ * 0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ * 0x000 ... 0x0FF: Global Register
+ * 0x100 ... 0x17F: Device 0
+ * 0x1A0 ... 0x1BF: Device 0 buffer
+ * 0x200 ... 0x27F: Device 1
+ * 0x2A0 ... 0x2BF: Device 1 buffer
+ * 0x300 ... 0x37F: Device 2
+ * 0x3A0 ... 0x3BF: Device 2 buffer
+ * 0x400 ... 0x47F: Device 3
+ * 0x4A0 ... 0x4BF: Device 3 buffer
+ * 0x500 ... 0x57F: Device 4
+ * 0x5A0 ... 0x5BF: Device 4 buffer
+ * 0x600 ... 0x67F: Device 5
+ * 0x6A0 ... 0x6BF: Device 5 buffer
+ * 0x700 ... 0x77F: Device 6
+ * 0x7A0 ... 0x7BF: Device 6 buffer
+ * 0x800 ... 0x87F: Device 7
+ * 0x8A0 ... 0x8BF: Device 7 buffer
+ * 0x900 ... 0x97F: Device 8
+ * 0x9A0 ... 0x9BF: Device 8 buffer
+ * 0xA00 ... 0xA7F: Device 9
+ * 0xAA0 ... 0xABF: Device 9 buffer
+ * 0xB00 ... 0xB7F: Device 10
+ * 0xBA0 ... 0xBBF: Device 10 buffer
+ * 0xC00 ... 0xC7F: Device 11
+ * 0xCA0 ... 0xCBF: Device 11 buffer
+ * 0xD00 ... 0xD7F: Device 12
+ * 0xDA0 ... 0xDBF: Device 12 buffer
+ * 0xE00 ... 0xE7F: Device 13
+ * 0xEA0 ... 0xEBF: Device 13 buffer
+ * 0xF00 ... 0xF7F: Device 14
+ * 0xFA0 ... 0xFBF: Device 14 buffer
+ * 0x1000 ... 0x107F: Device 15
+ * 0x10A0 ... 0x10BF: Device 15 buffer
*/
static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
{
@@ -1012,6 +1205,8 @@
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedI2CState *s = ASPEED_I2C(dev);
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+ uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+ uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1034,14 +1229,23 @@
return;
}
- memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+ memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
&s->busses[i].mr);
}
- memory_region_init_io(&s->pool_iomem, OBJECT(s),
- &aspeed_i2c_share_pool_ops, s,
- "aspeed.i2c-share-pool", aic->pool_size);
- memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem);
+ if (aic->has_share_pool) {
+ memory_region_init_io(&s->pool_iomem, OBJECT(s),
+ &aspeed_i2c_share_pool_ops, s,
+ "aspeed.i2c-share-pool", aic->pool_size);
+ memory_region_add_subregion(&s->iomem, aic->pool_base,
+ &s->pool_iomem);
+ } else {
+ for (i = 0; i < aic->num_busses; i++) {
+ memory_region_add_subregion(&s->iomem,
+ aic->pool_base + (pool_offset * i),
+ &s->busses[i].mr_pool);
+ }
+ }
if (aic->has_dma) {
if (!s->dram_mr) {
@@ -1092,8 +1296,9 @@
return -1;
}
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
- bus->regs[R_I2CC_DMA_ADDR] =
- ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] =
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
i2c_ack(bus->bus);
@@ -1159,10 +1364,10 @@
static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
{
assert(address_space_write(&bus->controller->dram_as,
- bus->regs[R_I2CC_DMA_ADDR],
+ bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
- bus->regs[R_I2CC_DMA_ADDR]++;
+ bus->dma_dram_offset++;
bus->regs[R_I2CC_DMA_LEN]--;
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
@@ -1217,6 +1422,7 @@
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
AspeedI2CClass *aic;
g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id);
+ g_autofree char *pool_name = g_strdup_printf("%s.pool", name);
if (!s->controller) {
error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set");
@@ -1234,6 +1440,10 @@
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
s, name, aic->reg_size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
+
+ memory_region_init_io(&s->mr_pool, OBJECT(s), &aspeed_i2c_bus_pool_ops,
+ s, pool_name, aic->pool_size);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr_pool);
}
static Property aspeed_i2c_bus_properties[] = {
@@ -1286,6 +1496,7 @@
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq;
+ aic->has_share_pool = true;
aic->pool_size = 0x800;
aic->pool_base = 0x800;
aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base;
@@ -1305,7 +1516,7 @@
static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus)
{
- return &bus->controller->share_pool[bus->id * 0x10];
+ return bus->pool;
}
static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
@@ -1319,7 +1530,7 @@
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq;
- aic->pool_size = 0x100;
+ aic->pool_size = 0x10;
aic->pool_base = 0x200;
aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->check_sram = true;
@@ -1338,11 +1549,6 @@
return bus->irq;
}
-static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus)
-{
- return &bus->controller->share_pool[bus->id * 0x20];
-}
-
static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1354,9 +1560,9 @@
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
aic->mem_size = 0x1000;
}
@@ -1378,9 +1584,9 @@
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
aic->mem_size = 0x10000;
}
@@ -1391,6 +1597,33 @@
.class_init = aspeed_1030_i2c_class_init,
};
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 I2C Controller";
+
+ aic->num_busses = 16;
+ aic->reg_size = 0x80;
+ aic->reg_gap_size = 0x80;
+ aic->gap = -1; /* no gap */
+ aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+ aic->pool_size = 0x20;
+ aic->pool_gap_size = 0xe0;
+ aic->pool_base = 0x1a0;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+ aic->has_dma = true;
+ aic->mem_size = 0x2000;
+ aic->has_dma64 = true;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+ .name = TYPE_ASPEED_2700_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2700_i2c_class_init,
+};
+
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_bus_info);
@@ -1400,6 +1633,7 @@
type_register_static(&aspeed_2500_i2c_info);
type_register_static(&aspeed_2600_i2c_info);
type_register_static(&aspeed_1030_i2c_info);
+ type_register_static(&aspeed_2700_i2c_info);
}
type_init(aspeed_i2c_register_types)
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index fad5e92..2c4c81b 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -31,12 +31,14 @@
#define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
#define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
#define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030"
+#define TYPE_ASPEED_2700_I2C TYPE_ASPEED_I2C "-ast2700"
OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
#define ASPEED_I2C_NR_BUSSES 16
#define ASPEED_I2C_SHARE_POOL_SIZE 0x800
+#define ASPEED_I2C_BUS_POOL_SIZE 0x20
#define ASPEED_I2C_OLD_NUM_REG 11
-#define ASPEED_I2C_NEW_NUM_REG 22
+#define ASPEED_I2C_NEW_NUM_REG 28
#define A_I2CD_M_STOP_CMD BIT(5)
#define A_I2CD_M_RX_CMD BIT(3)
@@ -225,6 +227,15 @@
FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13)
REG32(I2CC_DMA_ADDR, 0x50)
REG32(I2CC_DMA_LEN, 0x54)
+/* DMA 64bits */
+REG32(I2CM_DMA_TX_ADDR_HI, 0x60)
+ FIELD(I2CM_DMA_TX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CM_DMA_RX_ADDR_HI, 0x64)
+ FIELD(I2CM_DMA_RX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CS_DMA_TX_ADDR_HI, 0x68)
+ FIELD(I2CS_DMA_TX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CS_DMA_RX_ADDR_HI, 0x6c)
+ FIELD(I2CS_DMA_RX_ADDR_HI, ADDR_HI, 0, 7)
struct AspeedI2CState;
@@ -239,12 +250,15 @@
I2CSlave *slave;
MemoryRegion mr;
+ MemoryRegion mr_pool;
I2CBus *bus;
uint8_t id;
qemu_irq irq;
uint32_t regs[ASPEED_I2C_NEW_NUM_REG];
+ uint8_t pool[ASPEED_I2C_BUS_POOL_SIZE];
+ uint64_t dma_dram_offset;
};
struct AspeedI2CState {
@@ -275,15 +289,19 @@
uint8_t num_busses;
uint8_t reg_size;
+ uint32_t reg_gap_size;
uint8_t gap;
qemu_irq (*bus_get_irq)(AspeedI2CBus *);
uint64_t pool_size;
hwaddr pool_base;
+ uint32_t pool_gap_size;
uint8_t *(*bus_pool_base)(AspeedI2CBus *);
bool check_sram;
bool has_dma;
+ bool has_share_pool;
uint64_t mem_size;
+ bool has_dma64;
};
static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
@@ -363,14 +381,6 @@
return R_I2CD_DMA_LEN;
}
-static inline uint32_t aspeed_i2c_bus_dma_addr_offset(AspeedI2CBus *bus)
-{
- if (aspeed_i2c_is_new_mode(bus->controller)) {
- return R_I2CC_DMA_ADDR;
- }
- return R_I2CD_DMA_ADDR;
-}
-
static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
{
return SHARED_ARRAY_FIELD_EX32(bus->regs, aspeed_i2c_bus_ctrl_offset(bus),
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index c0b01e8..4e144bd 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -433,9 +433,25 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self):
f'loader,addr=0x430000000,cpu-num={i}')
self.vm.add_args('-smp', str(num_cpu))
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
+
self.ssh_connect('root', '0penBmc', False)
+ self.ssh_command('dmesg -c > /dev/null')
+
+ self.ssh_command_output_contains(
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device '
+ '&& dmesg -c',
+ 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d');
+
+ self.ssh_command_output_contains(
+ 'cat /sys/class/hwmon/hwmon20/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ self.ssh_command_output_contains(
+ 'cat /sys/class/hwmon/hwmon20/temp1_input', '18000')
class AST2x00MachineMMC(QemuSystemTest):