AST2600/1030 provides a new register mode which is controlled by
I2CG0C[2]. If the I2CG0C[2] = 1, then I2C will switch to a new set of
register.

This commit supports new register mode with packet operation and DMA
enabled. Byte/buffer mode is not implemented.

Signed-off-by: Troy Lee <troy_...@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com>
Signed-off-by: Steven Lee <steven_...@aspeedtech.com>
---
 hw/i2c/aspeed_i2c.c         | 490 ++++++++++++++++++++++++++++++++++--
 hw/i2c/trace-events         |   7 +-
 include/hw/i2c/aspeed_i2c.h |   8 +
 3 files changed, 487 insertions(+), 18 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 03a4f5a910..f571c8bbca 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -37,6 +37,8 @@
                                                Assignment */
 #define I2C_CTRL_GLOBAL         0x0C        /* Global Control Register */
 #define   I2C_CTRL_SRAM_EN                 BIT(0)
+#define   I2C_CTRL_NEW_REG_MODE            BIT(2)
+#define I2C_NEW_DIV_GLOBAL      0x10
 
 /* I2C Device (Bus) Register */
 
@@ -145,6 +147,102 @@
 #define I2CD_DMA_ADDR           0x24       /* DMA Buffer Address */
 #define I2CD_DMA_LEN            0x28       /* DMA Transfer Length < 4KB */
 
+/* New register mode */
+#define I2CC_M_S_FUNC_CTRL_REG  0x00
+#define   I2CC_SLAVE_ADDR_RX_EN     BIT(20)
+#define   I2CC_MASTER_RETRY_MASK    (0x3 << 18)
+#define   I2CC_MASTER_RETRY(x)      ((x & 0x3) << 18)
+#define   I2CC_BUS_AUTO_RELEASE     BIT(17)
+#define   I2CC_M_SDA_LOCK_EN        BIT(16)
+#define   I2CC_MULTI_MASTER_DIS     BIT(15)
+#define   I2CC_M_SCL_DRIVE_EN       BIT(14)
+#define   I2CC_MSB_STS              BIT(9)
+#define   I2CC_SDA_DRIVE_1T_EN      BIT(8)
+#define   I2CC_M_SDA_DRIVE_1T_EN    BIT(7)
+#define   I2CC_M_HIGH_SPEED_EN      BIT(6)
+#define   I2CC_SLAVE_EN             BIT(1)
+#define   I2CC_MASTER_EN            BIT(0)
+
+#define I2CC_M_S_CLK_AC_TIMING_REG 0x04
+#define I2CC_M_S_TX_RX_BUF_REG  0x08
+#define I2CC_M_X_POOL_BUF_CTRL_REG 0x0c
+#define I2CM_INT_CTRL_REG     0x10
+#define I2CM_INT_STS_REG      0x14
+#define   I2CM_PKT_OP_SM_SHIFT      28
+#define   I2CM_PKT_OP_SM_IDLE       0x0
+#define   I2CM_PKT_OP_SM_STARTH     0x1
+#define   I2CM_PKT_OP_SM_STARTW     0x2
+#define   I2CM_PKT_OP_SM_STARTR     0x3
+#define   I2CM_PKT_OP_SM_TXMCODE    0x4
+#define   I2CM_PKT_OP_SM_TXAW       0x5
+#define   I2CM_PKT_OP_SM_INIT       0x8
+#define   I2CM_PKT_OP_SM_TXD        0x9
+#define   I2CM_PKT_OP_SM_RXD        0xa
+#define   I2CM_PKT_OP_SM_STOP       0xb
+#define   I2CM_PKT_OP_SM_RETRY      0xc
+#define   I2CM_PKT_OP_SM_FAIL       0xd
+#define   I2CM_PKT_OP_SM_WAIT       0xe
+#define   I2CM_PKT_OP_SM_PASS       0xf
+#define   I2CM_PKT_TIMEOUT          BIT(18)
+#define   I2CM_PKT_ERROR            BIT(17)
+#define   I2CM_PKT_DONE             BIT(16)
+#define   I2CM_BUS_RECOVER_FAIL     BIT(15)
+#define   I2CM_SDA_DL_TO            BIT(14)
+#define   I2CM_BUS_RECOVER          BIT(13)
+#define   I2CM_SMBUS_ALT            BIT(12)
+#define   I2CM_SCL_LOW_TO           BIT(6)
+#define   I2CM_ABNORMAL             BIT(5)
+#define   I2CM_NORMAL_STOP          BIT(4)
+#define   I2CM_ARBIT_LOSS           BIT(3)
+#define   I2CM_RX_DONE              BIT(2)
+#define   I2CM_TX_NAK               BIT(1)
+#define   I2CM_TX_ACK               BIT(0)
+#define I2CM_CMD_STS_REG      0x18
+#define   I2CM_CMD_PKT_MODE           (1 << 16)
+
+#define   I2CM_PKT_EN               BIT(16)
+#define   I2CM_SDA_OE_OUT_DIR       BIT(15)
+#define   I2CM_SDA_O_OUT_DIR        BIT(14)
+#define   I2CM_SCL_OE_OUT_DIR       BIT(13)
+#define   I2CM_SCL_O_OUT_DIR        BIT(12)
+#define   I2CM_RECOVER_CMD_EN       BIT(11)
+#define   I2CM_RX_DMA_EN            BIT(9)
+#define   I2CM_TX_DMA_EN            BIT(8)
+/* Command Bit */
+#define   I2CM_RX_BUFF_EN           BIT(7)
+#define   I2CM_TX_BUFF_EN           BIT(6)
+#define   I2CM_STOP_CMD             BIT(5)
+#define   I2CM_RX_CMD_LAST          BIT(4)
+#define   I2CM_RX_CMD               BIT(3)
+#define   I2CM_TX_CMD               BIT(1)
+#define   I2CM_START_CMD            BIT(0)
+#define   I2CM_PKT_ADDR(x)          ((x & 0x7f) << 24)
+
+#define I2CM_DMA_LEN          0x1c
+#define I2CS_INT_CTRL_REG     0x20
+#define I2CS_INT_STS_REG      0x24
+#define I2CS_CMD_STS_REG      0x28
+#define I2CS_DMA_LEN          0x2c
+#define I2CM_DMA_TX_BUF       0x30
+#define I2CM_DMA_RX_BUF       0x34
+#define I2CS_DMA_TX_BUF       0x38
+#define I2CS_DMA_RX_BUF       0x3c
+#define I2CS_SA_REG           0x40
+#define I2CM_DMA_LEN_STS_REG  0x48
+#define I2CS_DMA_LEN_STS_REG  0x4c
+#define I2CC_DMA_OP_ADDR_REG  0x50
+#define I2CC_DMA_OP_LEN_REG   0x54
+
+static inline bool aspeed_i2c_ctrl_is_new_mode(AspeedI2CState *controller)
+{
+    return (controller->ctrl_global & I2C_CTRL_NEW_REG_MODE) == 
I2C_CTRL_NEW_REG_MODE;
+}
+
+static inline bool aspeed_i2c_bus_is_new_mode(AspeedI2CBus *bus)
+{
+    return aspeed_i2c_ctrl_is_new_mode(bus->controller);
+}
+
 static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
 {
     return bus->ctrl & I2CD_MASTER_EN;
@@ -155,6 +253,24 @@ static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus 
*bus)
     return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN);
 }
 
+static inline void aspeed_i2c_bus_raise_interrupt_new(AspeedI2CBus *bus)
+{
+    AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+
+    trace_aspeed_i2c_bus_raise_interrupt_new(bus->intr_status,
+          bus->intr_status & I2CM_TX_NAK ? "nak|" : "",
+          bus->intr_status & I2CM_TX_ACK ? "ack|" : "",
+          bus->intr_status & I2CM_RX_DONE ? "done|" : "",
+          bus->intr_status & I2CM_NORMAL_STOP ? "normal|" : "",
+          bus->intr_status & I2CM_ABNORMAL ? "abnormal|" : "",
+          bus->intr_status & I2CM_PKT_DONE ? "pkt" : "");
+
+    if (bus->intr_status) {
+        bus->controller->intr_status |= 1 << bus->id;
+        qemu_irq_raise(aic->bus_get_irq(bus));
+    }
+}
+
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
@@ -173,7 +289,68 @@ static inline void 
aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
     }
 }
 
-static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
+static uint64_t aspeed_i2c_bus_read_new(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    AspeedI2CBus *bus = opaque;
+    uint64_t value = -1;
+
+    switch (offset) {
+    case I2CC_M_S_FUNC_CTRL_REG:
+        value = bus->ctrl;
+        break;
+    case I2CC_M_S_CLK_AC_TIMING_REG:
+        value = ((bus->timing[1] & 0x1F) << 24) | (bus->timing[1] & 0xFFFFF);
+        break;
+    case I2CM_INT_CTRL_REG:
+        value = bus->intr_ctrl;
+        break;
+    case I2CM_INT_STS_REG:
+        value = bus->intr_status;
+        break;
+    case I2CM_CMD_STS_REG:
+        value = bus->cmd;
+        break;
+    case I2CM_DMA_LEN:
+        value = bus->dma_len & 0x0fff;
+        break;
+    case I2CM_DMA_TX_BUF: case I2CM_DMA_RX_BUF:
+        value = bus->dma_addr;
+        break;
+    case I2CM_DMA_LEN_STS_REG:
+        value = bus->dma_len_tx | (bus->dma_len_rx << 16);
+        break;
+    case I2CC_M_S_TX_RX_BUF_REG:
+        /*
+         * TODO:
+         * [31:16] RO  Same as I2CD14[31:16]
+         * [15: 0] RW  Same as I2CD20[15: 0]
+         */
+        value = (i2c_bus_busy(bus->bus) << 16);
+        break;
+    case I2CC_M_X_POOL_BUF_CTRL_REG:
+    case I2CS_INT_CTRL_REG:
+    case I2CS_INT_STS_REG:
+    case I2CS_CMD_STS_REG:
+    case I2CS_DMA_LEN:
+    case I2CS_DMA_TX_BUF:
+    case I2CS_DMA_RX_BUF:
+    case I2CS_SA_REG:
+    case I2CS_DMA_LEN_STS_REG:
+    case I2CC_DMA_OP_ADDR_REG:
+    case I2CC_DMA_OP_LEN_REG:
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
+        value = -1;
+        break;
+    }
+
+    trace_aspeed_i2c_bus_read_new(bus->id, offset, size, value);
+    return value;
+}
+
+static uint64_t aspeed_i2c_bus_read_old(void *opaque, hwaddr offset,
                                     unsigned size)
 {
     AspeedI2CBus *bus = opaque;
@@ -227,19 +404,38 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr 
offset,
         break;
     }
 
-    trace_aspeed_i2c_bus_read(bus->id, offset, size, value);
+    trace_aspeed_i2c_bus_read_old(bus->id, offset, size, value);
     return value;
 }
 
+static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    AspeedI2CBus *bus = opaque;
+    if (aspeed_i2c_bus_is_new_mode(bus)) {
+        return aspeed_i2c_bus_read_new(opaque, offset, size);
+    } else {
+        return aspeed_i2c_bus_read_old(opaque, offset, size);
+    }
+}
+
 static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state)
 {
-    bus->cmd &= ~(I2CD_TX_STATE_MASK << I2CD_TX_STATE_SHIFT);
-    bus->cmd |= (state & I2CD_TX_STATE_MASK) << I2CD_TX_STATE_SHIFT;
+    if (aspeed_i2c_bus_is_new_mode(bus)) {
+        bus->tx_state_machine = state;
+    } else {
+        bus->cmd &= ~(I2CD_TX_STATE_MASK << I2CD_TX_STATE_SHIFT);
+        bus->cmd |= (state & I2CD_TX_STATE_MASK) << I2CD_TX_STATE_SHIFT;
+    }
 }
 
 static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
 {
-    return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
+    if (aspeed_i2c_bus_is_new_mode(bus)) {
+        return bus->tx_state_machine;
+    } else {
+        return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
+    }
 }
 
 static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
@@ -257,6 +453,27 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t 
*data)
 
     bus->dma_addr++;
     bus->dma_len--;
+    bus->dma_len_tx++;
+    return 0;
+}
+
+static int aspeed_i2c_dma_write(AspeedI2CBus *bus, uint8_t *data)
+{
+    MemTxResult result;
+    AspeedI2CState *s = bus->controller;
+
+    result = address_space_write(&s->dram_as, bus->dma_addr,
+                                 MEMTXATTRS_UNSPECIFIED, data, 1);
+
+    if (result != MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
+                      __func__, bus->dma_addr);
+        return -1;
+    }
+
+    bus->dma_addr++;
+    bus->dma_len--;
+    bus->dma_len_rx++;
     return 0;
 }
 
@@ -361,17 +578,29 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 
-    if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
-        uint8_t *pool_base = aic->bus_pool_base(bus);
+    if (aspeed_i2c_bus_is_new_mode(bus)) {
+        if (bus->cmd & I2CM_CMD_PKT_MODE) {
+            return (bus->cmd & 0x7F000000) >> 23 |
+                   (bus->cmd & I2CM_RX_CMD ? 0x01 : 0x00);
+        } else {
+            /* TODO: Support other mode */
+            qemu_log_mask(LOG_UNIMP, "%s: New register mode with cmd=%08x\n",
+                          __func__, bus->cmd);
+            return 0xFF;
+        }
+    } else {
+        if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
+            uint8_t *pool_base = aic->bus_pool_base(bus);
 
-        return pool_base[0];
-    } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
-        uint8_t data;
+            return pool_base[0];
+        } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
+            uint8_t data;
 
-        aspeed_i2c_dma_read(bus, &data);
-        return data;
-    } else {
-        return bus->buf;
+            aspeed_i2c_dma_read(bus, &data);
+            return data;
+        } else {
+            return bus->buf;
+        }
     }
 }
 
@@ -425,6 +654,106 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
     trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status);
 }
 
+/*
+ * This cmd handler only process new register set with packet mode
+ */
+static void aspeed_i2c_bus_handle_cmd_new(AspeedI2CBus *bus, uint64_t value)
+{
+    uint32_t cmd_done = 0;
+
+    if (bus->cmd & I2CM_CMD_PKT_MODE) {
+        bus->intr_status |= I2CM_PKT_DONE;
+        bus->dma_len_tx = 0;
+        bus->dma_len_rx = 0;
+    }
+
+    if (bus->cmd & I2CM_START_CMD) {
+        /* Send I2C_START event */
+        uint8_t addr = aspeed_i2c_get_addr(bus);
+        if (aspeed_i2c_get_state(bus) == I2CM_PKT_OP_SM_IDLE) {
+            if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
+                                   extract32(addr, 0, 1))) {
+                bus->intr_status |= I2CM_TX_NAK | I2CM_PKT_ERROR;
+            }
+
+            if (addr & 0x01) {
+                aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_STARTR);
+            } else {
+                aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_STARTW);
+            }
+        }
+        cmd_done |= I2CM_START_CMD;
+    }
+
+    if (bus->cmd & I2CM_TX_CMD) {
+        /* Send through DMA */
+        if (bus->cmd & I2CM_TX_DMA_EN) {
+            while (bus->dma_len) {
+                uint8_t data;
+                int ret;
+                aspeed_i2c_dma_read(bus, &data);
+                trace_aspeed_i2c_bus_send("DMA", bus->dma_len, bus->dma_len, 
data);
+                ret = i2c_send(bus->bus, data);
+                if (ret) {
+                    break;
+                }
+            }
+            bus->intr_status |= I2CM_TX_ACK;
+            cmd_done |= I2CM_TX_DMA_EN;
+        } else {
+            /* TODO: Support Byte/Buffer mode */
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Only support DMA\n",  
__func__);
+        }
+        aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_TXD);
+        cmd_done |= I2CM_TX_CMD;
+    }
+
+    if (bus->cmd & I2CM_RX_CMD) {
+        uint8_t addr = aspeed_i2c_get_addr(bus);
+        if (bus->cmd & I2CM_START_CMD &&
+            aspeed_i2c_get_state(bus) != I2CM_PKT_OP_SM_STARTR) {
+            /* Repeated Start */
+            i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 
extract32(addr, 0, 1));
+            aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_STARTR);
+        }
+        if (bus->cmd & I2CM_RX_DMA_EN) {
+            /* Write to DMA */
+            while (bus->dma_len) {
+                uint8_t data;
+                data = i2c_recv(bus->bus);
+                if (aspeed_i2c_dma_write(bus, &data)) {
+                    break;
+                }
+            }
+            cmd_done |= I2CM_RX_DMA_EN;
+        }
+        aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_RXD);
+        cmd_done |= I2CM_RX_CMD;
+    }
+
+    if (bus->cmd & I2CM_RX_CMD_LAST) {
+        i2c_nack(bus->bus);
+        bus->intr_status |= I2CM_RX_DONE;
+        cmd_done |= I2CM_RX_CMD_LAST;
+    }
+
+    if (bus->cmd & I2CM_STOP_CMD) {
+        aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_STOP);
+        /* Send I2C_END Event */
+        i2c_end_transfer(bus->bus);
+        aspeed_i2c_set_state(bus, I2CM_PKT_OP_SM_IDLE);
+        bus->intr_status |= I2CM_NORMAL_STOP;
+        cmd_done |= I2CM_STOP_CMD;
+    }
+
+    if (bus->cmd & I2CM_CMD_PKT_MODE) {
+        bus->intr_status |= I2CM_PKT_DONE;
+        cmd_done |= 0x7F000000 | I2CM_CMD_PKT_MODE;
+    }
+
+    bus->cmd &= ~cmd_done;
+}
+
 /*
  * The state machine needs some refinement. It is only used to track
  * invalid STOP commands for the moment.
@@ -523,14 +852,103 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, 
uint64_t value)
     }
 }
 
-static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
+static void aspeed_i2c_bus_write_new(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    AspeedI2CBus *bus = opaque;
+    AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+    trace_aspeed_i2c_bus_write_new(bus->id, offset, size, value);
+
+    switch (offset) {
+    case I2CC_M_S_FUNC_CTRL_REG:
+        if (value & I2CD_SLAVE_EN) {
+            qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
+                          __func__);
+            break;
+        }
+        bus->ctrl = value & 0x007FFFFF;
+        break;
+    case I2CC_M_S_CLK_AC_TIMING_REG:
+        bus->timing[0] = value & 0x000FFF0F;
+        bus->timing[1] = (value & 0x1F000000) >> 24;
+        break;
+    case I2CC_M_S_TX_RX_BUF_REG:
+        bus->buf = value & 0xFF;
+        break;
+    case I2CM_INT_CTRL_REG:
+        bus->intr_ctrl = value & 0x77FFF;
+        break;
+    case I2CM_INT_STS_REG:
+        if (value & I2CM_PKT_DONE) {
+            bus->intr_status &= ~(0x7E07F);
+        } else {
+            bus->intr_status &= ~(value & 0x7F07F);
+        }
+        if (1 || !(bus->intr_status & 0x7F07F)) {
+            bus->controller->intr_status &= ~(1 << bus->id);
+            qemu_irq_lower(aic->bus_get_irq(bus));
+        }
+        break;
+    case I2CM_CMD_STS_REG:
+        if (!aspeed_i2c_bus_is_enabled(bus)) {
+            break;
+        }
+        if (!aspeed_i2c_bus_is_master(bus)) {
+            qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
+                            __func__);
+            break;
+        }
+        bus->cmd = value;
+        aspeed_i2c_bus_handle_cmd_new(bus, value);
+        aspeed_i2c_bus_raise_interrupt_new(bus);
+        break;
+    case I2CM_DMA_LEN:
+        if (!aic->has_dma) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
+            break;
+        }
+        /* 0 = 1 byte, 1 = 2 bytes, 4095 = 4096 bytes */
+        if (value & 0x00008000) {
+            bus->dma_len = (value & 0xfff) + 1;
+        } else if (value & 0x80000000) {
+            bus->dma_len = ((value >> 16) & 0xfff) + 1;
+        }
+        break;
+    case I2CM_DMA_TX_BUF: case I2CM_DMA_RX_BUF:
+        if (!aic->has_dma) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
+            break;
+        }
+        bus->dma_addr = value & 0x7fffffff;
+        break;
+    case I2CM_DMA_LEN_STS_REG:
+        bus->dma_len_tx = 0;
+        bus->dma_len_rx = 0;
+        break;
+    case I2CC_M_X_POOL_BUF_CTRL_REG:
+    case I2CS_INT_CTRL_REG:
+    case I2CS_INT_STS_REG:
+    case I2CS_CMD_STS_REG:
+    case I2CS_DMA_LEN:
+    case I2CS_DMA_TX_BUF:
+    case I2CS_DMA_RX_BUF:
+    case I2CS_SA_REG:
+    case I2CS_DMA_LEN_STS_REG:
+    case I2CC_DMA_OP_ADDR_REG:
+    case I2CC_DMA_OP_LEN_REG:
+    default:
+        break;
+    }
+}
+
+static void aspeed_i2c_bus_write_old(void *opaque, hwaddr offset,
                                  uint64_t value, unsigned size)
 {
     AspeedI2CBus *bus = opaque;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     bool handle_rx;
 
-    trace_aspeed_i2c_bus_write(bus->id, offset, size, value);
+    trace_aspeed_i2c_bus_write_old(bus->id, offset, size, value);
 
     switch (offset) {
     case I2CD_FUN_CTRL_REG:
@@ -622,6 +1040,17 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr 
offset,
     }
 }
 
+static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    AspeedI2CBus *bus = opaque;
+    if (aspeed_i2c_bus_is_new_mode(bus)) {
+        return aspeed_i2c_bus_write_new(opaque, offset, value, size);
+    } else {
+        return aspeed_i2c_bus_write_old(opaque, offset, value, size);
+    }
+}
+
 static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
                                    unsigned size)
 {
@@ -632,6 +1061,8 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr 
offset,
         return s->intr_status;
     case I2C_CTRL_GLOBAL:
         return s->ctrl_global;
+    case I2C_NEW_DIV_GLOBAL:
+        return s->new_divider;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
                       __func__, offset);
@@ -650,6 +1081,9 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr 
offset,
     case I2C_CTRL_GLOBAL:
         s->ctrl_global = value;
         break;
+    case I2C_NEW_DIV_GLOBAL:
+        s->new_divider = value;
+        break;
     case I2C_CTRL_STATUS:
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@@ -1013,6 +1447,29 @@ static const TypeInfo aspeed_2600_i2c_info = {
     .class_init = aspeed_2600_i2c_class_init,
 };
 
+static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+    dc->desc = "ASPEED 1030 I2C Controller";
+
+    aic->num_busses = 14;
+    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_base = 0xC00;
+    aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+    aic->has_dma = true;
+}
+
+static const TypeInfo aspeed_1030_i2c_info = {
+    .name = TYPE_ASPEED_1030_I2C,
+    .parent = TYPE_ASPEED_I2C,
+    .class_init = aspeed_1030_i2c_class_init,
+};
+
 static void aspeed_i2c_register_types(void)
 {
     type_register_static(&aspeed_i2c_bus_info);
@@ -1020,6 +1477,7 @@ static void aspeed_i2c_register_types(void)
     type_register_static(&aspeed_2400_i2c_info);
     type_register_static(&aspeed_2500_i2c_info);
     type_register_static(&aspeed_2600_i2c_info);
+    type_register_static(&aspeed_1030_i2c_info);
 }
 
 type_init(aspeed_i2c_register_types)
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 7d8907c1ee..eec3568082 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -10,8 +10,11 @@ i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) 
data:0x%02x"
 
 aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, 
uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x"
 aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const 
char *str2, const char *str3, const char *str4, const char *str5) "handled 
intr=0x%x %s%s%s%s%s"
-aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t 
value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
-aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t 
value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
+aspeed_i2c_bus_raise_interrupt_new(uint32_t intr_status, const char *str1, 
const char *str2, const char *str3, const char *str4, const char *str5, const 
char *str6) "handled intr=0x%x %s%s%s%s%s%s"
+aspeed_i2c_bus_read_old(uint32_t busid, uint64_t offset, unsigned size, 
uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
+aspeed_i2c_bus_read_new(uint32_t busid, uint64_t offset, unsigned size, 
uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
+aspeed_i2c_bus_write_old(uint32_t busid, uint64_t offset, unsigned size, 
uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
+aspeed_i2c_bus_write_new(uint32_t busid, uint64_t offset, unsigned size, 
uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
 aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send 
%d/%d 0x%02x"
 aspeed_i2c_bus_recv(const char *mode, int i, int count, uint8_t byte) "%s recv 
%d/%d 0x%02x"
 
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 4b9be09274..bcd15850d0 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -29,6 +29,7 @@
 #define TYPE_ASPEED_2400_I2C TYPE_ASPEED_I2C "-ast2400"
 #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"
 OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 
 #define ASPEED_I2C_NR_BUSSES 16
@@ -58,6 +59,12 @@ struct AspeedI2CBus {
     uint32_t pool_ctrl;
     uint32_t dma_addr;
     uint32_t dma_len;
+
+    uint8_t tx_state_machine;
+    uint32_t intr_ctrl_slave;
+    uint32_t intr_status_slave;
+    uint32_t dma_len_tx;
+    uint32_t dma_len_rx;
 };
 
 struct AspeedI2CState {
@@ -68,6 +75,7 @@ struct AspeedI2CState {
 
     uint32_t intr_status;
     uint32_t ctrl_global;
+    uint32_t new_divider;
     MemoryRegion pool_iomem;
     uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
 
-- 
2.25.1


Reply via email to