@@ -696,9 +696,7 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
switch (offset) {
case A_I2CD_FUN_CTRL:
if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
- __func__);
- break;
+ i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]);
}
bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF;
break;
@@ -719,12 +717,15 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
bus->controller->intr_status &= ~(1 << bus->id);
qemu_irq_lower(aic->bus_get_irq(bus));
}
- if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
- M_RX_CMD) ||
- SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
- M_S_RX_CMD_LAST))) {
- aspeed_i2c_handle_rx_cmd(bus);
- aspeed_i2c_bus_raise_interrupt(bus);
+ if (handle_rx) {
+ if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) ||
+ SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
+ M_S_RX_CMD_LAST)) {
+ aspeed_i2c_handle_rx_cmd(bus);
+ aspeed_i2c_bus_raise_interrupt(bus);
+ } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) {
+ i2c_ack(bus->bus);
+ }
}
break;
case A_I2CD_DEV_ADDR:
@@ -1036,6 +1037,73 @@ static const TypeInfo aspeed_i2c_info = {
.abstract = true,
};
+static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
+{
+ BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
+ AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent);
+ uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+ uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
+ uint32_t value;
+
+ switch (event) {
+ case I2C_START_SEND_ASYNC:
+ value = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_byte_buf, TX_BUF);
+ SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, value << 1);
+
+ ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1);
+ SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
+
+ aspeed_i2c_set_state(bus, I2CD_STXD);
+
+ break;
+
+ case I2C_FINISH:
+ SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1);
+
+ aspeed_i2c_set_state(bus, I2CD_IDLE);
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ aspeed_i2c_bus_raise_interrupt(bus);
+
+ return 0;
+}
+
+static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
+{
+ BusState *qbus = qdev_get_parent_bus(DEVICE(slave));
+ AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent);
+ uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+ uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
+
+ SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
+ SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
+
+ aspeed_i2c_bus_raise_interrupt(bus);
+}
+
+static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ dc->desc = "Aspeed I2C Bus Slave";
+
+ sc->event = aspeed_i2c_bus_slave_event;
+ sc->send_async = aspeed_i2c_bus_slave_send_async;
+}
+
+static const TypeInfo aspeed_i2c_bus_slave_info = {
+ .name = TYPE_ASPEED_I2C_BUS_SLAVE,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(AspeedI2CBusSlave),
+ .class_init = aspeed_i2c_bus_slave_class_init,
+};
+
static void aspeed_i2c_bus_reset(DeviceState *dev)
{
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
@@ -1060,6 +1128,8 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
s->bus = i2c_init_bus(dev, name);
+ s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE,
+ 0xff);
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
s, name, aic->reg_size);
@@ -1219,6 +1289,7 @@ static const TypeInfo aspeed_1030_i2c_info = {
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_bus_info);
+ type_register_static(&aspeed_i2c_bus_slave_info);
type_register_static(&aspeed_i2c_info);
type_register_static(&aspeed_2400_i2c_info);
type_register_static(&aspeed_2500_i2c_info);
@@ -223,6 +223,9 @@ struct AspeedI2CBus {
struct AspeedI2CState *controller;
+ /* slave mode */
+ I2CSlave *slave;
+
MemoryRegion mr;
I2CBus *bus;
@@ -249,6 +252,11 @@ struct AspeedI2CState {
AddressSpace dram_as;
};
+#define TYPE_ASPEED_I2C_BUS_SLAVE "aspeed.i2c.slave"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBusSlave, ASPEED_I2C_BUS_SLAVE)
+struct AspeedI2CBusSlave {
+ I2CSlave i2c;
+};
struct AspeedI2CClass {
SysBusDeviceClass parent_class;