|
@@ -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);
|