[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 06/13] hw/i2c/aspeed: add slave device in old register mode
From: |
Peter Delevoryas |
Subject: |
[PATCH v2 06/13] hw/i2c/aspeed: add slave device in old register mode |
Date: |
Tue, 28 Jun 2022 20:36:27 -0700 |
From: Klaus Jensen <k.jensen@samsung.com>
Add slave mode functionality for the Aspeed I2C controller in old
register mode. This is implemented by realizing an I2C slave device
owned by the I2C controller and attached to its own bus.
The I2C slave device only implements asynchronous sends on the bus, so
slaves not supporting that will not be able to communicate with it.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[ clg: checkpatch fixes ]
Message-Id: <20220601210831.67259-6-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
hw/i2c/aspeed_i2c.c | 89 +++++++++++++++++++++++++++++++++----
include/hw/i2c/aspeed_i2c.h | 8 ++++
2 files changed, 88 insertions(+), 9 deletions(-)
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index c153a1a942..8a8514586f 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -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);
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 1398befc10..ba148b2f6d 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -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;
--
2.30.2
- [PATCH v2 00/13] hw/i2c/aspeed: Add new-registers DMA slave mode RX support, Peter Delevoryas, 2022/06/28
- [PATCH v2 01/13] hw/i2c/aspeed: Fix R_I2CD_FUN_CTRL reference, Peter Delevoryas, 2022/06/28
- [PATCH v2 03/13] hw/i2c/aspeed: Fix MASTER_EN missing error message, Peter Delevoryas, 2022/06/28
- [PATCH v2 02/13] hw/i2c/aspeed: Fix DMA len write-enable bit handling, Peter Delevoryas, 2022/06/28
- [PATCH v2 04/13] hw/i2c: support multiple masters, Peter Delevoryas, 2022/06/28
- [PATCH v2 05/13] hw/i2c: add asynchronous send, Peter Delevoryas, 2022/06/28
- [PATCH v2 06/13] hw/i2c/aspeed: add slave device in old register mode,
Peter Delevoryas <=
- [PATCH v2 08/13] hw/i2c/pmbus: Reset out buf after switching pages, Peter Delevoryas, 2022/06/28
- [PATCH v2 07/13] hw/i2c/aspeed: Add new-registers DMA slave mode RX support, Peter Delevoryas, 2022/06/28
- [PATCH v2 09/13] hw/i2c/pmbus: Add read-only IC_DEVICE_ID support, Peter Delevoryas, 2022/06/28