All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode
@ 2022-06-06 15:07 Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 01/21] hw/registerfields: Add shared fields macros Cédric Le Goater
                   ` (21 more replies)
  0 siblings, 22 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Hello,

Here is a series aggregating recent changes proposed on the Aspeed
ast2600 I2C controller model. 

First comes a large set of changes converting the model to use the
registerfield interface and adding the I2C new register mode
(Joe). Since this is complex to review, extra tests are added to the
acceptance test suite to check that I2C devices are still functional
in the ast2600-evb machine. These tests use small buildroot images
available on GH. 

The ast1030 and ast2600 SoC share the same I2C logic. This series adds
I2C support to the ast1030 now that new register mode is supported.
There was a previous proposal from Troy doing the same but Joe's
patchset covers the same need (and converts the model to registerfield)

Follows a proposal from Klaus adding support for multi master in the
I2C core and the Aspeed I2C model, for the old register mode only. The
new register mode still needs to be addressed but this shouldn't take
too long once old register mode is merged.

Last, I have added the I2C echo device and test provided by Klaus. I
think it would be interesting to keep them for tests. Please, tell me.

Thanks,

C.

Cédric Le Goater (7):
  test/avocado/machine_aspeed.py: Move OpenBMC tests
  test/avocado/machine_aspeed.py: Add tests using buildroot images
  test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb
  test/avocado/machine_aspeed.py: Add an I2C RTC test
  aspeed/i2c: Add ast1030 controller models
  aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always
  test/avocado/machine_aspeed.py: Add I2C slave tests

Joe Komlodi (7):
  hw/registerfields: Add shared fields macros
  aspeed: i2c: Add ctrl_global_rsvd property
  aspeed: i2c: Migrate to registerfields API
  aspeed: i2c: Use reg array instead of individual vars
  aspeed: i2c: Add new mode support
  aspeed: i2c: Add PKT_DONE IRQ to trace
  aspeed: i2c: Move regs and helpers to header file

Klaus Jensen (6):
  hw/i2c/aspeed: rework raise interrupt trace event
  hw/i2c/aspeed: add DEV_ADDR in old register mode
  hw/i2c: support multiple masters
  hw/i2c: add asynchronous send
  hw/i2c/aspeed: add slave device in old register mode
  hw/misc: add a toy i2c echo device [DO NOT PULL]

Troy Lee (1):
  aspeed: Add I2C buses to AST1030 model

 include/hw/i2c/aspeed_i2c.h         | 299 ++++++++-
 include/hw/i2c/i2c.h                |  30 +
 include/hw/registerfields.h         |  70 +++
 hw/arm/aspeed.c                     |  13 +
 hw/arm/aspeed_ast10x0.c             |  18 +
 hw/arm/aspeed_ast2600.c             |   2 +
 hw/arm/pxa2xx.c                     |   2 +
 hw/display/sii9022.c                |   2 +
 hw/display/ssd0303.c                |   2 +
 hw/i2c/aspeed_i2c.c                 | 901 ++++++++++++++++++----------
 hw/i2c/core.c                       |  70 ++-
 hw/i2c/smbus_slave.c                |   4 +
 hw/misc/i2c-echo.c                  | 162 +++++
 hw/nvram/eeprom_at24c.c             |   2 +
 hw/sensor/lsm303dlhc_mag.c          |   2 +
 hw/i2c/trace-events                 |   4 +-
 hw/misc/meson.build                 |   2 +
 tests/avocado/boot_linux_console.py |  43 --
 tests/avocado/machine_aspeed.py     | 128 ++++
 19 files changed, 1393 insertions(+), 363 deletions(-)
 create mode 100644 hw/misc/i2c-echo.c

-- 
2.35.3



^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 01/21] hw/registerfields: Add shared fields macros
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property Cédric Le Goater
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

Occasionally a peripheral will have different operating modes, where the
MMIO layout changes, but some of the register fields have the same offsets
and behaviors.

To help support this, we add SHARED_FIELD_XX macros that create SHIFT,
LENGTH, and MASK macros for the fields that are shared across registers,
and accessors for these fields.

An example use may look as follows:
There is a peripheral with registers REG_MODE1 and REG_MODE2 at
different addreses, and both have a field FIELD1 initialized by
SHARED_FIELD().

Depending on what mode the peripheral is operating in, the user could
extract FIELD1 via
SHARED_ARRAY_FIELD_EX32(s->regs, R_REG_MODE1, FIELD1)
or
SHARED_ARRAY_FIELD_EX32(s->regs, R_REG_MODE2, FIELD1)

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: Id3dc53e7d2f8741c95697cbae69a81bb699fa3cb
Message-Id: <20220331043248.2237838-2-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/registerfields.h | 70 +++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h
index 3a88e135d025..1330ca77de61 100644
--- a/include/hw/registerfields.h
+++ b/include/hw/registerfields.h
@@ -154,4 +154,74 @@
 #define ARRAY_FIELD_DP64(regs, reg, field, val)                           \
     (regs)[R_ ## reg] = FIELD_DP64((regs)[R_ ## reg], reg, field, val);
 
+
+/*
+ * These macros can be used for defining and extracting fields that have the
+ * same bit position across multiple registers.
+ */
+
+/* Define shared SHIFT, LENGTH, and MASK constants */
+#define SHARED_FIELD(name, shift, length)   \
+    enum { name ## _ ## SHIFT = (shift)};   \
+    enum { name ## _ ## LENGTH = (length)}; \
+    enum { name ## _ ## MASK = MAKE_64BIT_MASK(shift, length)};
+
+/* Extract a shared field */
+#define SHARED_FIELD_EX8(storage, field) \
+    extract8((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX16(storage, field) \
+    extract16((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX32(storage, field) \
+    extract32((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX64(storage, field) \
+    extract64((storage), field ## _SHIFT, field ## _LENGTH)
+
+/* Extract a shared field from a register array */
+#define SHARED_ARRAY_FIELD_EX32(regs, offset, field) \
+    SHARED_FIELD_EX32((regs)[(offset)], field)
+#define SHARED_ARRAY_FIELD_EX64(regs, offset, field) \
+    SHARED_FIELD_EX64((regs)[(offset)], field)
+
+/* Deposit a shared field */
+#define SHARED_FIELD_DP8(storage, field, val) ({                        \
+    struct {                                                            \
+        unsigned int v:field ## _LENGTH;                                \
+    } _v = { .v = val };                                                \
+    uint8_t _d;                                                         \
+    _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+    _d; })
+
+#define SHARED_FIELD_DP16(storage, field, val) ({                       \
+    struct {                                                            \
+        unsigned int v:field ## _LENGTH;                                \
+    } _v = { .v = val };                                                \
+    uint16_t _d;                                                        \
+    _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+    _d; })
+
+#define SHARED_FIELD_DP32(storage, field, val) ({                       \
+    struct {                                                            \
+        unsigned int v:field ## _LENGTH;                                \
+    } _v = { .v = val };                                                \
+    uint32_t _d;                                                        \
+    _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+    _d; })
+
+#define SHARED_FIELD_DP64(storage, field, val) ({                       \
+    struct {                                                            \
+        uint64_t v:field ## _LENGTH;                                    \
+    } _v = { .v = val };                                                \
+    uint64_t _d;                                                        \
+    _d = deposit64((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+    _d; })
+
+/* Deposit a shared field to a register array */
+#define SHARED_ARRAY_FIELD_DP32(regs, offset, field, val) \
+    (regs)[(offset)] = SHARED_FIELD_DP32((regs)[(offset)], field, val);
+#define SHARED_ARRAY_FIELD_DP64(regs, offset, field, val) \
+    (regs)[(offset)] = SHARED_FIELD_DP64((regs)[(offset)], field, val);
+
 #endif
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 01/21] hw/registerfields: Add shared fields macros Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-07  0:05   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 03/21] aspeed: i2c: Migrate to registerfields API Cédric Le Goater
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

The Aspeed I2C controller is used across other SKUs that have different
reserved bits for the ctrl_global_rsvd register.

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: I606c5933c527274a9d2b0afe559b2e895767636c
Message-Id: <20220331043248.2237838-3-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h | 2 ++
 hw/arm/aspeed_ast2600.c     | 2 ++
 hw/i2c/aspeed_i2c.c         | 4 ++++
 3 files changed, 8 insertions(+)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 4b9be09274c7..3912fcc3ff53 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -71,6 +71,8 @@ struct AspeedI2CState {
     MemoryRegion pool_iomem;
     uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
 
+    uint32_t ctrl_global_rsvd;
+
     AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
     MemoryRegion *dram_mr;
     AddressSpace dram_as;
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index b0a4199b6960..cc57c8b437d8 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -375,6 +375,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
     aspeed_soc_uart_init(s);
 
     /* I2C */
+    object_property_set_int(OBJECT(&s->i2c), "ctrl-global-rsvd", 0xfffc3e00,
+                            &error_abort);
     object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
                              &error_abort);
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 03a4f5a91010..97eb9d57929c 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -648,6 +648,7 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
 
     switch (offset) {
     case I2C_CTRL_GLOBAL:
+        value &= ~s->ctrl_global_rsvd;
         s->ctrl_global = value;
         break;
     case I2C_CTRL_STATUS:
@@ -730,6 +731,7 @@ static const VMStateDescription aspeed_i2c_vmstate = {
     .minimum_version_id = 2,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(intr_status, AspeedI2CState),
+        VMSTATE_UINT32(ctrl_global_rsvd, AspeedI2CState),
         VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
                              ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
                              AspeedI2CBus),
@@ -828,6 +830,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
 static Property aspeed_i2c_properties[] = {
     DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr,
                      TYPE_MEMORY_REGION, MemoryRegion *),
+    DEFINE_PROP_UINT32("ctrl-global-rsvd", AspeedI2CState, ctrl_global_rsvd,
+                       0xfffffffe),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 03/21] aspeed: i2c: Migrate to registerfields API
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 01/21] hw/registerfields: Add shared fields macros Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 23:29   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars Cédric Le Goater
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

This cleans up some of the field accessing, setting, and clearing
bitwise operations, and wraps them in macros instead.

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: I33018d6325fa04376e7c29dc4a49ab389a8e333a
Message-Id: <20220331043248.2237838-4-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/i2c/aspeed_i2c.c | 393 ++++++++++++++++++++++----------------------
 1 file changed, 196 insertions(+), 197 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 97eb9d57929c..be81a798cc35 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -28,70 +28,61 @@
 #include "hw/i2c/aspeed_i2c.h"
 #include "hw/irq.h"
 #include "hw/qdev-properties.h"
+#include "hw/registerfields.h"
 #include "trace.h"
 
 /* I2C Global Register */
-
-#define I2C_CTRL_STATUS         0x00        /* Device Interrupt Status */
-#define I2C_CTRL_ASSIGN         0x08        /* Device Interrupt Target
-                                               Assignment */
-#define I2C_CTRL_GLOBAL         0x0C        /* Global Control Register */
-#define   I2C_CTRL_SRAM_EN                 BIT(0)
+REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */
+REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */
+REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */
+    FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1)
 
 /* I2C Device (Bus) Register */
-
-#define I2CD_FUN_CTRL_REG       0x00       /* I2CD Function Control  */
-#define   I2CD_POOL_PAGE_SEL(x)            (((x) >> 20) & 0x7)  /* AST2400 */
-#define   I2CD_M_SDA_LOCK_EN               (0x1 << 16)
-#define   I2CD_MULTI_MASTER_DIS            (0x1 << 15)
-#define   I2CD_M_SCL_DRIVE_EN              (0x1 << 14)
-#define   I2CD_MSB_STS                     (0x1 << 9)
-#define   I2CD_SDA_DRIVE_1T_EN             (0x1 << 8)
-#define   I2CD_M_SDA_DRIVE_1T_EN           (0x1 << 7)
-#define   I2CD_M_HIGH_SPEED_EN             (0x1 << 6)
-#define   I2CD_DEF_ADDR_EN                 (0x1 << 5)
-#define   I2CD_DEF_ALERT_EN                (0x1 << 4)
-#define   I2CD_DEF_ARP_EN                  (0x1 << 3)
-#define   I2CD_DEF_GCALL_EN                (0x1 << 2)
-#define   I2CD_SLAVE_EN                    (0x1 << 1)
-#define   I2CD_MASTER_EN                   (0x1)
-
-#define I2CD_AC_TIMING_REG1     0x04       /* Clock and AC Timing Control #1 */
-#define I2CD_AC_TIMING_REG2     0x08       /* Clock and AC Timing Control #1 */
-#define I2CD_INTR_CTRL_REG      0x0c       /* I2CD Interrupt Control */
-#define I2CD_INTR_STS_REG       0x10       /* I2CD Interrupt Status */
-
-#define   I2CD_INTR_SLAVE_ADDR_MATCH       (0x1 << 31) /* 0: addr1 1: addr2 */
-#define   I2CD_INTR_SLAVE_ADDR_RX_PENDING  (0x1 << 30)
-/* bits[19-16] Reserved */
-
-/* All bits below are cleared by writing 1 */
-#define   I2CD_INTR_SLAVE_INACTIVE_TIMEOUT (0x1 << 15)
-#define   I2CD_INTR_SDA_DL_TIMEOUT         (0x1 << 14)
-#define   I2CD_INTR_BUS_RECOVER_DONE       (0x1 << 13)
-#define   I2CD_INTR_SMBUS_ALERT            (0x1 << 12) /* Bus [0-3] only */
-#define   I2CD_INTR_SMBUS_ARP_ADDR         (0x1 << 11) /* Removed */
-#define   I2CD_INTR_SMBUS_DEV_ALERT_ADDR   (0x1 << 10) /* Removed */
-#define   I2CD_INTR_SMBUS_DEF_ADDR         (0x1 << 9)  /* Removed */
-#define   I2CD_INTR_GCALL_ADDR             (0x1 << 8)  /* Removed */
-#define   I2CD_INTR_SLAVE_ADDR_RX_MATCH    (0x1 << 7)  /* use RX_DONE */
-#define   I2CD_INTR_SCL_TIMEOUT            (0x1 << 6)
-#define   I2CD_INTR_ABNORMAL               (0x1 << 5)
-#define   I2CD_INTR_NORMAL_STOP            (0x1 << 4)
-#define   I2CD_INTR_ARBIT_LOSS             (0x1 << 3)
-#define   I2CD_INTR_RX_DONE                (0x1 << 2)
-#define   I2CD_INTR_TX_NAK                 (0x1 << 1)
-#define   I2CD_INTR_TX_ACK                 (0x1 << 0)
-
-#define I2CD_CMD_REG            0x14       /* I2CD Command/Status */
-#define   I2CD_SDA_OE                      (0x1 << 28)
-#define   I2CD_SDA_O                       (0x1 << 27)
-#define   I2CD_SCL_OE                      (0x1 << 26)
-#define   I2CD_SCL_O                       (0x1 << 25)
-#define   I2CD_TX_TIMING                   (0x1 << 24)
-#define   I2CD_TX_STATUS                   (0x1 << 23)
-
-#define   I2CD_TX_STATE_SHIFT              19 /* Tx State Machine */
+REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control  */
+    FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */
+    FIELD(I2CD_FUN_CTRL, M_SDA_LOCK_EN, 16, 1)
+    FIELD(I2CD_FUN_CTRL, MULTI_MASTER_DIS, 15, 1)
+    FIELD(I2CD_FUN_CTRL, M_SCL_DRIVE_EN, 14, 1)
+    FIELD(I2CD_FUN_CTRL, MSB_STS, 9, 1)
+    FIELD(I2CD_FUN_CTRL, SDA_DRIVE_IT_EN, 8, 1)
+    FIELD(I2CD_FUN_CTRL, M_SDA_DRIVE_IT_EN, 7, 1)
+    FIELD(I2CD_FUN_CTRL, M_HIGH_SPEED_EN, 6, 1)
+    FIELD(I2CD_FUN_CTRL, DEF_ADDR_EN, 5, 1)
+    FIELD(I2CD_FUN_CTRL, DEF_ALERT_EN, 4, 1)
+    FIELD(I2CD_FUN_CTRL, DEF_ARP_EN, 3, 1)
+    FIELD(I2CD_FUN_CTRL, DEF_GCALL_EN, 2, 1)
+    FIELD(I2CD_FUN_CTRL, SLAVE_EN, 1, 1)
+    FIELD(I2CD_FUN_CTRL, MASTER_EN, 0, 1)
+REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */
+REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */
+REG32(I2CD_INTR_CTRL, 0x0C)  /* I2CD Interrupt Control */
+REG32(I2CD_INTR_STS, 0x10)   /* I2CD Interrupt Status */
+    FIELD(I2CD_INTR_STS, SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
+    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_PENDING, 29, 1)
+    FIELD(I2CD_INTR_STS, SLAVE_INACTIVE_TIMEOUT, 15, 1)
+    FIELD(I2CD_INTR_STS, SDA_DL_TIMEOUT, 14, 1)
+    FIELD(I2CD_INTR_STS, BUS_RECOVER_DONE, 13, 1)
+    FIELD(I2CD_INTR_STS, SMBUS_ALERT, 12, 1)            /* Bus [0-3] only */
+    FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1)         /* Removed */
+    FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1)   /* Removed */
+    FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1)          /* Removed */
+    FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1)              /* Removed */
+    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)     /* use RX_DONE */
+    FIELD(I2CD_INTR_STS, SCL_TIMEOUT, 6, 1)
+    FIELD(I2CD_INTR_STS, ABNORMAL, 5, 1)
+    FIELD(I2CD_INTR_STS, NORMAL_STOP, 4, 1)
+    FIELD(I2CD_INTR_STS, ARBIT_LOSS, 3, 1)
+    FIELD(I2CD_INTR_STS, RX_DONE, 2, 1)
+    FIELD(I2CD_INTR_STS, TX_NAK, 1, 1)
+    FIELD(I2CD_INTR_STS, TX_ACK, 0, 1)
+REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
+    FIELD(I2CD_CMD, SDA_OE, 28, 1)
+    FIELD(I2CD_CMD, SDA_O, 27, 1)
+    FIELD(I2CD_CMD, SCL_OE, 26, 1)
+    FIELD(I2CD_CMD, SCL_O, 25, 1)
+    FIELD(I2CD_CMD, TX_TIMING, 23, 2)
+    FIELD(I2CD_CMD, TX_STATE, 19, 4)
+/* Tx State Machine */
 #define   I2CD_TX_STATE_MASK                  0xf
 #define     I2CD_IDLE                         0x0
 #define     I2CD_MACTIVE                      0x8
@@ -108,51 +99,47 @@
 #define     I2CD_STXD                         0x6
 #define     I2CD_SRXACK                       0x7
 #define     I2CD_RECOVER                      0x3
-
-#define   I2CD_SCL_LINE_STS                (0x1 << 18)
-#define   I2CD_SDA_LINE_STS                (0x1 << 17)
-#define   I2CD_BUS_BUSY_STS                (0x1 << 16)
-#define   I2CD_SDA_OE_OUT_DIR              (0x1 << 15)
-#define   I2CD_SDA_O_OUT_DIR               (0x1 << 14)
-#define   I2CD_SCL_OE_OUT_DIR              (0x1 << 13)
-#define   I2CD_SCL_O_OUT_DIR               (0x1 << 12)
-#define   I2CD_BUS_RECOVER_CMD_EN          (0x1 << 11)
-#define   I2CD_S_ALT_EN                    (0x1 << 10)
-
-/* Command Bit */
-#define   I2CD_RX_DMA_ENABLE               (0x1 << 9)
-#define   I2CD_TX_DMA_ENABLE               (0x1 << 8)
-#define   I2CD_RX_BUFF_ENABLE              (0x1 << 7)
-#define   I2CD_TX_BUFF_ENABLE              (0x1 << 6)
-#define   I2CD_M_STOP_CMD                  (0x1 << 5)
-#define   I2CD_M_S_RX_CMD_LAST             (0x1 << 4)
-#define   I2CD_M_RX_CMD                    (0x1 << 3)
-#define   I2CD_S_TX_CMD                    (0x1 << 2)
-#define   I2CD_M_TX_CMD                    (0x1 << 1)
-#define   I2CD_M_START_CMD                 (0x1)
-
-#define I2CD_DEV_ADDR_REG       0x18       /* Slave Device Address */
-#define I2CD_POOL_CTRL_REG      0x1c       /* Pool Buffer Control */
-#define   I2CD_POOL_RX_COUNT(x)            (((x) >> 24) & 0xff)
-#define   I2CD_POOL_RX_SIZE(x)             ((((x) >> 16) & 0xff) + 1)
-#define   I2CD_POOL_TX_COUNT(x)            ((((x) >> 8) & 0xff) + 1)
-#define   I2CD_POOL_OFFSET(x)              (((x) & 0x3f) << 2)  /* AST2400 */
-#define I2CD_BYTE_BUF_REG       0x20       /* Transmit/Receive Byte Buffer */
-#define   I2CD_BYTE_BUF_TX_SHIFT           0
-#define   I2CD_BYTE_BUF_TX_MASK            0xff
-#define   I2CD_BYTE_BUF_RX_SHIFT           8
-#define   I2CD_BYTE_BUF_RX_MASK            0xff
-#define I2CD_DMA_ADDR           0x24       /* DMA Buffer Address */
-#define I2CD_DMA_LEN            0x28       /* DMA Transfer Length < 4KB */
+    FIELD(I2CD_CMD, SCL_LINE_STS, 18, 1)
+    FIELD(I2CD_CMD, SDA_LINE_STS, 17, 1)
+    FIELD(I2CD_CMD, BUS_BUSY_STS, 16, 1)
+    FIELD(I2CD_CMD, SDA_OE_OUT_DIR, 15, 1)
+    FIELD(I2CD_CMD, SDA_O_OUT_DIR, 14, 1)
+    FIELD(I2CD_CMD, SCL_OE_OUT_DIR, 13, 1)
+    FIELD(I2CD_CMD, SCL_O_OUT_DIR, 12, 1)
+    FIELD(I2CD_CMD, BUS_RECOVER_CMD_EN, 11, 1)
+    FIELD(I2CD_CMD, S_ALT_EN, 10, 1)
+    /* Command Bits */
+    FIELD(I2CD_CMD, RX_DMA_EN, 9, 1)
+    FIELD(I2CD_CMD, TX_DMA_EN, 8, 1)
+    FIELD(I2CD_CMD, RX_BUFF_EN, 7, 1)
+    FIELD(I2CD_CMD, TX_BUFF_EN, 6, 1)
+    FIELD(I2CD_CMD, M_STOP_CMD, 5, 1)
+    FIELD(I2CD_CMD, M_S_RX_CMD_LAST, 4, 1)
+    FIELD(I2CD_CMD, M_RX_CMD, 3, 1)
+    FIELD(I2CD_CMD, S_TX_CMD, 2, 1)
+    FIELD(I2CD_CMD, M_TX_CMD, 1, 1)
+    FIELD(I2CD_CMD, M_START_CMD, 0, 1)
+REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
+REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
+    FIELD(I2CD_POOL_CTRL, RX_COUNT, 24, 5)
+    FIELD(I2CD_POOL_CTRL, RX_SIZE, 16, 5)
+    FIELD(I2CD_POOL_CTRL, TX_COUNT, 9, 5)
+    FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
+REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
+    FIELD(I2CD_BYTE_BUF, RX_BUF, 8, 8)
+    FIELD(I2CD_BYTE_BUF, TX_BUF, 0, 8)
+REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */
+REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
 
 static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
 {
-    return bus->ctrl & I2CD_MASTER_EN;
+    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN);
 }
 
 static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
 {
-    return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN);
+    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN) ||
+           FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, SLAVE_EN);
 }
 
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
@@ -160,11 +147,13 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 
     trace_aspeed_i2c_bus_raise_interrupt(bus->intr_status,
-          bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "",
-          bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "",
-          bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "",
-          bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "",
-          bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : "");
+        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_NAK) ? "nak|" : "",
+        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_ACK) ? "ack|" : "",
+        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) ? "done|" : "",
+        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, NORMAL_STOP) ? "normal|"
+                                                                 : "",
+        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, ABNORMAL) ? "abnormal"
+                                                              : "");
 
     bus->intr_status &= bus->intr_ctrl;
     if (bus->intr_status) {
@@ -181,38 +170,38 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
     uint64_t value = -1;
 
     switch (offset) {
-    case I2CD_FUN_CTRL_REG:
+    case A_I2CD_FUN_CTRL:
         value = bus->ctrl;
         break;
-    case I2CD_AC_TIMING_REG1:
+    case A_I2CD_AC_TIMING1:
         value = bus->timing[0];
         break;
-    case I2CD_AC_TIMING_REG2:
+    case A_I2CD_AC_TIMING2:
         value = bus->timing[1];
         break;
-    case I2CD_INTR_CTRL_REG:
+    case A_I2CD_INTR_CTRL:
         value = bus->intr_ctrl;
         break;
-    case I2CD_INTR_STS_REG:
+    case A_I2CD_INTR_STS:
         value = bus->intr_status;
         break;
-    case I2CD_POOL_CTRL_REG:
+    case A_I2CD_POOL_CTRL:
         value = bus->pool_ctrl;
         break;
-    case I2CD_BYTE_BUF_REG:
+    case A_I2CD_BYTE_BUF:
         value = bus->buf;
         break;
-    case I2CD_CMD_REG:
+    case A_I2CD_CMD:
         value = bus->cmd | (i2c_bus_busy(bus->bus) << 16);
         break;
-    case I2CD_DMA_ADDR:
+    case A_I2CD_DMA_ADDR:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
         }
         value = bus->dma_addr;
         break;
-    case I2CD_DMA_LEN:
+    case A_I2CD_DMA_LEN:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
@@ -233,13 +222,12 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
 
 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;
+    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_STATE, state);
 }
 
 static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
 {
-    return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
+    return FIELD_EX32(bus->cmd, I2CD_CMD, TX_STATE);
 }
 
 static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
@@ -265,21 +253,21 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     int ret = -1;
     int i;
+    int pool_tx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
 
-    if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
-        for (i = pool_start; i < I2CD_POOL_TX_COUNT(bus->pool_ctrl); i++) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
+        for (i = pool_start; i < pool_tx_count; i++) {
             uint8_t *pool_base = aic->bus_pool_base(bus);
 
-            trace_aspeed_i2c_bus_send("BUF", i + 1,
-                                      I2CD_POOL_TX_COUNT(bus->pool_ctrl),
+            trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count,
                                       pool_base[i]);
             ret = i2c_send(bus->bus, pool_base[i]);
             if (ret) {
                 break;
             }
         }
-        bus->cmd &= ~I2CD_TX_BUFF_ENABLE;
-    } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_BUFF_EN, 0);
+    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
         while (bus->dma_len) {
             uint8_t data;
             aspeed_i2c_dma_read(bus, &data);
@@ -289,7 +277,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
                 break;
             }
         }
-        bus->cmd &= ~I2CD_TX_DMA_ENABLE;
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_DMA_EN, 0);
     } else {
         trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, bus->buf);
         ret = i2c_send(bus->bus, bus->buf);
@@ -304,22 +292,22 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
     uint8_t data;
     int i;
+    int pool_rx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT);
 
-    if (bus->cmd & I2CD_RX_BUFF_ENABLE) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
-        for (i = 0; i < I2CD_POOL_RX_SIZE(bus->pool_ctrl); i++) {
+        for (i = 0; i < pool_rx_count; i++) {
             pool_base[i] = i2c_recv(bus->bus);
-            trace_aspeed_i2c_bus_recv("BUF", i + 1,
-                                      I2CD_POOL_RX_SIZE(bus->pool_ctrl),
+            trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count,
                                       pool_base[i]);
         }
 
         /* Update RX count */
-        bus->pool_ctrl &= ~(0xff << 24);
-        bus->pool_ctrl |= (i & 0xff) << 24;
-        bus->cmd &= ~I2CD_RX_BUFF_ENABLE;
-    } else if (bus->cmd & I2CD_RX_DMA_ENABLE) {
+        bus->pool_ctrl = FIELD_DP32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT,
+                                    i & 0xff);
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_BUFF_EN, 0);
+    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
         uint8_t data;
 
         while (bus->dma_len) {
@@ -337,11 +325,11 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
             bus->dma_addr++;
             bus->dma_len--;
         }
-        bus->cmd &= ~I2CD_RX_DMA_ENABLE;
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_DMA_EN, 0);
     } else {
         data = i2c_recv(bus->bus);
         trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->buf);
-        bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
+        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, RX_BUF, data);
     }
 }
 
@@ -349,11 +337,12 @@ static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
 {
     aspeed_i2c_set_state(bus, I2CD_MRXD);
     aspeed_i2c_bus_recv(bus);
-    bus->intr_status |= I2CD_INTR_RX_DONE;
-    if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
+    bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS, RX_DONE, 1);
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) {
         i2c_nack(bus->bus);
     }
-    bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST);
+    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_RX_CMD, 0);
+    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST, 0);
     aspeed_i2c_set_state(bus, I2CD_MACTIVE);
 }
 
@@ -361,11 +350,11 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 
-    if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
         return pool_base[0];
-    } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
+    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
         uint8_t data;
 
         aspeed_i2c_dma_read(bus, &data);
@@ -379,7 +368,10 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
 {
     AspeedI2CState *s = bus->controller;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
-
+    bool dma_en = FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)  ||
+                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)  ||
+                  FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ||
+                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN);
     if (!aic->check_sram) {
         return true;
     }
@@ -388,9 +380,7 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
      * AST2500: SRAM must be enabled before using the Buffer Pool or
      * DMA mode.
      */
-    if (!(s->ctrl_global & I2C_CTRL_SRAM_EN) &&
-        (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE |
-                     I2CD_RX_BUFF_ENABLE | I2CD_TX_BUFF_ENABLE))) {
+    if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) {
         qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__);
         return false;
     }
@@ -402,25 +392,24 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
 {
     g_autofree char *cmd_flags = NULL;
     uint32_t count;
-
-    if (bus->cmd & (I2CD_RX_BUFF_ENABLE | I2CD_RX_BUFF_ENABLE)) {
-        count = I2CD_POOL_TX_COUNT(bus->pool_ctrl);
-    } else if (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_RX_DMA_ENABLE)) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
+        count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
+    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
         count = bus->dma_len;
     } else { /* BYTE mode */
         count = 1;
     }
 
     cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
-                                bus->cmd & I2CD_M_START_CMD ? "start|" : "",
-                                bus->cmd & I2CD_RX_DMA_ENABLE ? "rxdma|" : "",
-                                bus->cmd & I2CD_TX_DMA_ENABLE ? "txdma|" : "",
-                                bus->cmd & I2CD_RX_BUFF_ENABLE ? "rxbuf|" : "",
-                                bus->cmd & I2CD_TX_BUFF_ENABLE ? "txbuf|" : "",
-                                bus->cmd & I2CD_M_TX_CMD ? "tx|" : "",
-                                bus->cmd & I2CD_M_RX_CMD ? "rx|" : "",
-                                bus->cmd & I2CD_M_S_RX_CMD_LAST ? "last|" : "",
-                                bus->cmd & I2CD_M_STOP_CMD ? "stop" : "");
+             FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD) ? "start|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN) ? "rxdma|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN) ? "txdma|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ? "rxbuf|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN) ? "txbuf|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD) ? "tx|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ? "rx|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST) ? "last|" : "",
+             FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD) ? "stop" : "");
 
     trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status);
 }
@@ -444,7 +433,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_bus_cmd_dump(bus);
     }
 
-    if (bus->cmd & I2CD_M_START_CMD) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD)) {
         uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
             I2CD_MSTARTR : I2CD_MSTART;
         uint8_t addr;
@@ -455,21 +444,23 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
 
         if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
                                extract32(addr, 0, 1))) {
-            bus->intr_status |= I2CD_INTR_TX_NAK;
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          TX_NAK, 1);
         } else {
-            bus->intr_status |= I2CD_INTR_TX_ACK;
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          TX_ACK, 1);
         }
 
-        bus->cmd &= ~I2CD_M_START_CMD;
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_START_CMD, 0);
 
         /*
          * The START command is also a TX command, as the slave
          * address is sent on the bus. Drop the TX flag if nothing
          * else needs to be sent in this sequence.
          */
-        if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
-            if (I2CD_POOL_TX_COUNT(bus->pool_ctrl) == 1) {
-                bus->cmd &= ~I2CD_M_TX_CMD;
+        if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
+            if (FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT) == 1) {
+                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
             } else {
                 /*
                  * Increase the start index in the TX pool buffer to
@@ -477,12 +468,12 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
                  */
                 pool_start++;
             }
-        } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
+        } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
             if (bus->dma_len == 0) {
-                bus->cmd &= ~I2CD_M_TX_CMD;
+                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
             }
         } else {
-            bus->cmd &= ~I2CD_M_TX_CMD;
+            bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
         }
 
         /* No slave found */
@@ -492,33 +483,38 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if (bus->cmd & I2CD_M_TX_CMD) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD)) {
         aspeed_i2c_set_state(bus, I2CD_MTXD);
         if (aspeed_i2c_bus_send(bus, pool_start)) {
-            bus->intr_status |= (I2CD_INTR_TX_NAK);
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          TX_NAK, 1);
             i2c_end_transfer(bus->bus);
         } else {
-            bus->intr_status |= I2CD_INTR_TX_ACK;
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          TX_ACK, 1);
         }
-        bus->cmd &= ~I2CD_M_TX_CMD;
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) &&
-        !(bus->intr_status & I2CD_INTR_RX_DONE)) {
+    if ((FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
+         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) &&
+        !FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE)) {
         aspeed_i2c_handle_rx_cmd(bus);
     }
 
-    if (bus->cmd & I2CD_M_STOP_CMD) {
+    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD)) {
         if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__);
-            bus->intr_status |= I2CD_INTR_ABNORMAL;
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          ABNORMAL, 1);
         } else {
             aspeed_i2c_set_state(bus, I2CD_MSTOP);
             i2c_end_transfer(bus->bus);
-            bus->intr_status |= I2CD_INTR_NORMAL_STOP;
+            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
+                                          NORMAL_STOP, 1);
         }
-        bus->cmd &= ~I2CD_M_STOP_CMD;
+        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_STOP_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_IDLE);
     }
 }
@@ -533,49 +529,50 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
     trace_aspeed_i2c_bus_write(bus->id, offset, size, value);
 
     switch (offset) {
-    case I2CD_FUN_CTRL_REG:
-        if (value & I2CD_SLAVE_EN) {
+    case A_I2CD_FUN_CTRL:
+        if (FIELD_EX32(value, I2CD_FUN_CTRL, SLAVE_EN)) {
             qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
                           __func__);
             break;
         }
         bus->ctrl = value & 0x0071C3FF;
         break;
-    case I2CD_AC_TIMING_REG1:
+    case A_I2CD_AC_TIMING1:
         bus->timing[0] = value & 0xFFFFF0F;
         break;
-    case I2CD_AC_TIMING_REG2:
+    case A_I2CD_AC_TIMING2:
         bus->timing[1] = value & 0x7;
         break;
-    case I2CD_INTR_CTRL_REG:
+    case A_I2CD_INTR_CTRL:
         bus->intr_ctrl = value & 0x7FFF;
         break;
-    case I2CD_INTR_STS_REG:
-        handle_rx = (bus->intr_status & I2CD_INTR_RX_DONE) &&
-                (value & I2CD_INTR_RX_DONE);
+    case A_I2CD_INTR_STS:
+        handle_rx = FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) &&
+                    FIELD_EX32(value, I2CD_INTR_STS, RX_DONE);
         bus->intr_status &= ~(value & 0x7FFF);
         if (!bus->intr_status) {
             bus->controller->intr_status &= ~(1 << bus->id);
             qemu_irq_lower(aic->bus_get_irq(bus));
         }
-        if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) {
+        if (handle_rx && (FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
+                         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST))) {
             aspeed_i2c_handle_rx_cmd(bus);
             aspeed_i2c_bus_raise_interrupt(bus);
         }
         break;
-    case I2CD_DEV_ADDR_REG:
+    case A_I2CD_DEV_ADDR:
         qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
                       __func__);
         break;
-    case I2CD_POOL_CTRL_REG:
+    case A_I2CD_POOL_CTRL:
         bus->pool_ctrl &= ~0xffffff;
         bus->pool_ctrl |= (value & 0xffffff);
         break;
 
-    case I2CD_BYTE_BUF_REG:
-        bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT;
+    case A_I2CD_BYTE_BUF:
+        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, TX_BUF, value);
         break;
-    case I2CD_CMD_REG:
+    case A_I2CD_CMD:
         if (!aspeed_i2c_bus_is_enabled(bus)) {
             break;
         }
@@ -587,7 +584,8 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         }
 
         if (!aic->has_dma &&
-            value & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE)) {
+            (FIELD_EX32(value, I2CD_CMD, RX_DMA_EN) ||
+             FIELD_EX32(value, I2CD_CMD, TX_DMA_EN))) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
         }
@@ -595,7 +593,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         aspeed_i2c_bus_handle_cmd(bus, value);
         aspeed_i2c_bus_raise_interrupt(bus);
         break;
-    case I2CD_DMA_ADDR:
+    case A_I2CD_DMA_ADDR:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
@@ -604,7 +602,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         bus->dma_addr = value & 0x3ffffffc;
         break;
 
-    case I2CD_DMA_LEN:
+    case A_I2CD_DMA_LEN:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
@@ -628,9 +626,9 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
     AspeedI2CState *s = opaque;
 
     switch (offset) {
-    case I2C_CTRL_STATUS:
+    case A_I2C_CTRL_STATUS:
         return s->intr_status;
-    case I2C_CTRL_GLOBAL:
+    case A_I2C_CTRL_GLOBAL:
         return s->ctrl_global;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@@ -647,11 +645,11 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
     AspeedI2CState *s = opaque;
 
     switch (offset) {
-    case I2C_CTRL_GLOBAL:
+    case A_I2C_CTRL_GLOBAL:
         value &= ~s->ctrl_global_rsvd;
         s->ctrl_global = value;
         break;
-    case I2C_CTRL_STATUS:
+    case A_I2C_CTRL_STATUS:
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
                       __func__, offset);
@@ -923,9 +921,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
 static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
 {
     uint8_t *pool_page =
-        &bus->controller->pool[I2CD_POOL_PAGE_SEL(bus->ctrl) * 0x100];
+        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
+                                          POOL_PAGE_SEL) * 0x100];
 
-    return &pool_page[I2CD_POOL_OFFSET(bus->pool_ctrl)];
+    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
 }
 
 static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (2 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 03/21] aspeed: i2c: Migrate to registerfields API Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 23:49   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 05/21] aspeed: i2c: Add new mode support Cédric Le Goater
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

Using a register array will allow us to represent old-mode and new-mode
I2C registers by using the same underlying register array, instead of
adding an entire new set of variables to represent new mode.

As part of this, we also do additional cleanup to use ARRAY_FIELD_
macros instead of FIELD_ macros on registers.

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: Ib94996b17c361b8490c042b43c99d8abc69332e3
Message-Id: <20220331043248.2237838-5-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h |  11 +-
 hw/i2c/aspeed_i2c.c         | 286 +++++++++++++++++-------------------
 2 files changed, 133 insertions(+), 164 deletions(-)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 3912fcc3ff53..e9f83a954096 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -33,6 +33,7 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 
 #define ASPEED_I2C_NR_BUSSES 16
 #define ASPEED_I2C_MAX_POOL_SIZE 0x800
+#define ASPEED_I2C_OLD_NUM_REG 11
 
 struct AspeedI2CState;
 
@@ -49,15 +50,7 @@ struct AspeedI2CBus {
     uint8_t id;
     qemu_irq irq;
 
-    uint32_t ctrl;
-    uint32_t timing[2];
-    uint32_t intr_ctrl;
-    uint32_t intr_status;
-    uint32_t cmd;
-    uint32_t buf;
-    uint32_t pool_ctrl;
-    uint32_t dma_addr;
-    uint32_t dma_len;
+    uint32_t regs[ASPEED_I2C_OLD_NUM_REG];
 };
 
 struct AspeedI2CState {
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index be81a798cc35..e93805515082 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -133,30 +133,30 @@ REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
 
 static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
 {
-    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN);
+    return ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, MASTER_EN);
 }
 
 static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
 {
-    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN) ||
-           FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, SLAVE_EN);
+    return ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, MASTER_EN) ||
+           ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, SLAVE_EN);
 }
 
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 
-    trace_aspeed_i2c_bus_raise_interrupt(bus->intr_status,
-        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_NAK) ? "nak|" : "",
-        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_ACK) ? "ack|" : "",
-        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) ? "done|" : "",
-        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, NORMAL_STOP) ? "normal|"
-                                                                 : "",
-        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, ABNORMAL) ? "abnormal"
-                                                              : "");
-
-    bus->intr_status &= bus->intr_ctrl;
-    if (bus->intr_status) {
+    trace_aspeed_i2c_bus_raise_interrupt(bus->regs[R_I2CD_INTR_STS],
+          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, TX_NAK) ? "nak|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, TX_ACK) ? "ack|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE) ? "done|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, NORMAL_STOP) ? "normal|"
+                                                                  : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, ABNORMAL) ? "abnormal"
+                                                               : "");
+
+    bus->regs[R_I2CD_INTR_STS] &= bus->regs[R_I2CD_INTR_CTRL];
+    if (bus->regs[R_I2CD_INTR_STS]) {
         bus->controller->intr_status |= 1 << bus->id;
         qemu_irq_raise(aic->bus_get_irq(bus));
     }
@@ -167,46 +167,33 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
 {
     AspeedI2CBus *bus = opaque;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
-    uint64_t value = -1;
+    uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
 
     switch (offset) {
     case A_I2CD_FUN_CTRL:
-        value = bus->ctrl;
-        break;
     case A_I2CD_AC_TIMING1:
-        value = bus->timing[0];
-        break;
     case A_I2CD_AC_TIMING2:
-        value = bus->timing[1];
-        break;
     case A_I2CD_INTR_CTRL:
-        value = bus->intr_ctrl;
-        break;
     case A_I2CD_INTR_STS:
-        value = bus->intr_status;
-        break;
     case A_I2CD_POOL_CTRL:
-        value = bus->pool_ctrl;
-        break;
     case A_I2CD_BYTE_BUF:
-        value = bus->buf;
+        /* Value is already set, don't do anything. */
         break;
     case A_I2CD_CMD:
-        value = bus->cmd | (i2c_bus_busy(bus->bus) << 16);
+        value = FIELD_DP32(value, I2CD_CMD, BUS_BUSY_STS,
+                           i2c_bus_busy(bus->bus));
         break;
     case A_I2CD_DMA_ADDR:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
-            break;
+            value = -1;
         }
-        value = bus->dma_addr;
         break;
     case A_I2CD_DMA_LEN:
         if (!aic->has_dma) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
-            break;
+            value = -1;
         }
-        value = bus->dma_len;
         break;
 
     default:
@@ -222,12 +209,12 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
 
 static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state)
 {
-    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_STATE, state);
+    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_STATE, state);
 }
 
 static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
 {
-    return FIELD_EX32(bus->cmd, I2CD_CMD, TX_STATE);
+    return ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_STATE);
 }
 
 static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
@@ -235,16 +222,16 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
     MemTxResult result;
     AspeedI2CState *s = bus->controller;
 
-    result = address_space_read(&s->dram_as, bus->dma_addr,
+    result = address_space_read(&s->dram_as, bus->regs[R_I2CD_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);
+                      __func__, bus->regs[R_I2CD_DMA_ADDR]);
         return -1;
     }
 
-    bus->dma_addr++;
-    bus->dma_len--;
+    bus->regs[R_I2CD_DMA_ADDR]++;
+    bus->regs[R_I2CD_DMA_LEN]--;
     return 0;
 }
 
@@ -253,9 +240,9 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     int ret = -1;
     int i;
-    int pool_tx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
+    int pool_tx_count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT);
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
         for (i = pool_start; i < pool_tx_count; i++) {
             uint8_t *pool_base = aic->bus_pool_base(bus);
 
@@ -266,21 +253,23 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
                 break;
             }
         }
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_BUFF_EN, 0);
-    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
-        while (bus->dma_len) {
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_BUFF_EN, 0);
+    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
+        while (bus->regs[R_I2CD_DMA_LEN]) {
             uint8_t data;
             aspeed_i2c_dma_read(bus, &data);
-            trace_aspeed_i2c_bus_send("DMA", bus->dma_len, bus->dma_len, data);
+            trace_aspeed_i2c_bus_send("DMA", bus->regs[R_I2CD_DMA_LEN],
+                                      bus->regs[R_I2CD_DMA_LEN], data);
             ret = i2c_send(bus->bus, data);
             if (ret) {
                 break;
             }
         }
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_DMA_EN, 0);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_DMA_EN, 0);
     } else {
-        trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, bus->buf);
-        ret = i2c_send(bus->bus, bus->buf);
+        trace_aspeed_i2c_bus_send("BYTE", pool_start, 1,
+                                  bus->regs[R_I2CD_BYTE_BUF]);
+        ret = i2c_send(bus->bus, bus->regs[R_I2CD_BYTE_BUF]);
     }
 
     return ret;
@@ -292,9 +281,9 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
     uint8_t data;
     int i;
-    int pool_rx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT);
+    int pool_rx_count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, RX_COUNT);
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
         for (i = 0; i < pool_rx_count; i++) {
@@ -304,32 +293,33 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
         }
 
         /* Update RX count */
-        bus->pool_ctrl = FIELD_DP32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT,
-                                    i & 0xff);
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_BUFF_EN, 0);
-    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
+        ARRAY_FIELD_DP32(bus->regs, I2CD_POOL_CTRL, RX_COUNT, i & 0xff);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, RX_BUFF_EN, 0);
+    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)) {
         uint8_t data;
 
-        while (bus->dma_len) {
+        while (bus->regs[R_I2CD_DMA_LEN]) {
             MemTxResult result;
 
             data = i2c_recv(bus->bus);
-            trace_aspeed_i2c_bus_recv("DMA", bus->dma_len, bus->dma_len, data);
-            result = address_space_write(&s->dram_as, bus->dma_addr,
+            trace_aspeed_i2c_bus_recv("DMA", bus->regs[R_I2CD_DMA_LEN],
+                                      bus->regs[R_I2CD_DMA_LEN], data);
+            result = address_space_write(&s->dram_as,
+                                         bus->regs[R_I2CD_DMA_ADDR],
                                          MEMTXATTRS_UNSPECIFIED, &data, 1);
             if (result != MEMTX_OK) {
                 qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
-                              __func__, bus->dma_addr);
+                              __func__, bus->regs[R_I2CD_DMA_ADDR]);
                 return;
             }
-            bus->dma_addr++;
-            bus->dma_len--;
+            bus->regs[R_I2CD_DMA_ADDR]++;
+            bus->regs[R_I2CD_DMA_LEN]--;
         }
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_DMA_EN, 0);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, RX_DMA_EN, 0);
     } else {
         data = i2c_recv(bus->bus);
-        trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->buf);
-        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, RX_BUF, data);
+        trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[R_I2CD_BYTE_BUF]);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_BYTE_BUF, RX_BUF, data);
     }
 }
 
@@ -337,12 +327,12 @@ static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
 {
     aspeed_i2c_set_state(bus, I2CD_MRXD);
     aspeed_i2c_bus_recv(bus);
-    bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS, RX_DONE, 1);
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) {
+    ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, RX_DONE, 1);
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST)) {
         i2c_nack(bus->bus);
     }
-    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_RX_CMD, 0);
-    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST, 0);
+    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_RX_CMD, 0);
+    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST, 0);
     aspeed_i2c_set_state(bus, I2CD_MACTIVE);
 }
 
@@ -350,17 +340,17 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
         return pool_base[0];
-    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
+    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
         uint8_t data;
 
         aspeed_i2c_dma_read(bus, &data);
         return data;
     } else {
-        return bus->buf;
+        return bus->regs[R_I2CD_BYTE_BUF];
     }
 }
 
@@ -368,10 +358,10 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
 {
     AspeedI2CState *s = bus->controller;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
-    bool dma_en = FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)  ||
-                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)  ||
-                  FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ||
-                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN);
+    bool dma_en = ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)  ||
+                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)  ||
+                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN) ||
+                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN);
     if (!aic->check_sram) {
         return true;
     }
@@ -392,26 +382,27 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
 {
     g_autofree char *cmd_flags = NULL;
     uint32_t count;
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
-        count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
-    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
-        count = bus->dma_len;
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN)) {
+        count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT);
+    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)) {
+        count = bus->regs[R_I2CD_DMA_LEN];
     } else { /* BYTE mode */
         count = 1;
     }
 
     cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
-             FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD) ? "start|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN) ? "rxdma|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN) ? "txdma|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ? "rxbuf|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN) ? "txbuf|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD) ? "tx|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ? "rx|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST) ? "last|" : "",
-             FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD) ? "stop" : "");
-
-    trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status);
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_START_CMD) ? "start|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN) ? "rxdma|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN) ? "txdma|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN) ? "rxbuf|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN) ? "txbuf|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_TX_CMD) ? "tx|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ? "rx|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST) ? "last|" : "",
+          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_STOP_CMD) ? "stop" : "");
+
+    trace_aspeed_i2c_bus_cmd(bus->regs[R_I2CD_CMD], cmd_flags, count,
+                             bus->regs[R_I2CD_INTR_STS]);
 }
 
 /*
@@ -422,8 +413,8 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
 {
     uint8_t pool_start = 0;
 
-    bus->cmd &= ~0xFFFF;
-    bus->cmd |= value & 0xFFFF;
+    bus->regs[R_I2CD_CMD] &= ~0xFFFF;
+    bus->regs[R_I2CD_CMD] |= value & 0xFFFF;
 
     if (!aspeed_i2c_check_sram(bus)) {
         return;
@@ -433,7 +424,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_bus_cmd_dump(bus);
     }
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_START_CMD)) {
         uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
             I2CD_MSTARTR : I2CD_MSTART;
         uint8_t addr;
@@ -444,23 +435,21 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
 
         if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
                                extract32(addr, 0, 1))) {
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          TX_NAK, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_NAK, 1);
         } else {
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          TX_ACK, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_ACK, 1);
         }
 
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_START_CMD, 0);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_START_CMD, 0);
 
         /*
          * The START command is also a TX command, as the slave
          * address is sent on the bus. Drop the TX flag if nothing
          * else needs to be sent in this sequence.
          */
-        if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
-            if (FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT) == 1) {
-                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
+        if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
+            if (ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT) == 1) {
+                ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
             } else {
                 /*
                  * Increase the start index in the TX pool buffer to
@@ -468,12 +457,12 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
                  */
                 pool_start++;
             }
-        } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
-            if (bus->dma_len == 0) {
-                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
+        } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
+            if (bus->regs[R_I2CD_DMA_LEN] == 0) {
+                ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
             }
         } else {
-            bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
         }
 
         /* No slave found */
@@ -483,38 +472,34 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_TX_CMD)) {
         aspeed_i2c_set_state(bus, I2CD_MTXD);
         if (aspeed_i2c_bus_send(bus, pool_start)) {
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          TX_NAK, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_NAK, 1);
             i2c_end_transfer(bus->bus);
         } else {
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          TX_ACK, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_ACK, 1);
         }
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if ((FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
-         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) &&
-        !FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE)) {
+    if ((ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ||
+         ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST)) &&
+        !ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE)) {
         aspeed_i2c_handle_rx_cmd(bus);
     }
 
-    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD)) {
+    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_STOP_CMD)) {
         if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__);
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          ABNORMAL, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, ABNORMAL, 1);
         } else {
             aspeed_i2c_set_state(bus, I2CD_MSTOP);
             i2c_end_transfer(bus->bus);
-            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
-                                          NORMAL_STOP, 1);
+            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, NORMAL_STOP, 1);
         }
-        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_STOP_CMD, 0);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_STOP_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_IDLE);
     }
 }
@@ -535,27 +520,27 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
                           __func__);
             break;
         }
-        bus->ctrl = value & 0x0071C3FF;
+        bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF;
         break;
     case A_I2CD_AC_TIMING1:
-        bus->timing[0] = value & 0xFFFFF0F;
+        bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F;
         break;
     case A_I2CD_AC_TIMING2:
-        bus->timing[1] = value & 0x7;
+        bus->regs[R_I2CD_AC_TIMING2] = value & 0x7;
         break;
     case A_I2CD_INTR_CTRL:
-        bus->intr_ctrl = value & 0x7FFF;
+        bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF;
         break;
     case A_I2CD_INTR_STS:
-        handle_rx = FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) &&
+        handle_rx = ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE) &&
                     FIELD_EX32(value, I2CD_INTR_STS, RX_DONE);
-        bus->intr_status &= ~(value & 0x7FFF);
-        if (!bus->intr_status) {
+        bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF);
+        if (!bus->regs[R_I2CD_INTR_STS]) {
             bus->controller->intr_status &= ~(1 << bus->id);
             qemu_irq_lower(aic->bus_get_irq(bus));
         }
-        if (handle_rx && (FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
-                         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST))) {
+        if (handle_rx && (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ||
+                      ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST))) {
             aspeed_i2c_handle_rx_cmd(bus);
             aspeed_i2c_bus_raise_interrupt(bus);
         }
@@ -565,12 +550,12 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
                       __func__);
         break;
     case A_I2CD_POOL_CTRL:
-        bus->pool_ctrl &= ~0xffffff;
-        bus->pool_ctrl |= (value & 0xffffff);
+        bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff;
+        bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff);
         break;
 
     case A_I2CD_BYTE_BUF:
-        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, TX_BUF, value);
+        ARRAY_FIELD_DP32(bus->regs, I2CD_BYTE_BUF, TX_BUF, value);
         break;
     case A_I2CD_CMD:
         if (!aspeed_i2c_bus_is_enabled(bus)) {
@@ -599,7 +584,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
             break;
         }
 
-        bus->dma_addr = value & 0x3ffffffc;
+        bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc;
         break;
 
     case A_I2CD_DMA_LEN:
@@ -608,8 +593,8 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
             break;
         }
 
-        bus->dma_len = value & 0xfff;
-        if (!bus->dma_len) {
+        bus->regs[R_I2CD_DMA_LEN] = value & 0xfff;
+        if (!bus->regs[R_I2CD_DMA_LEN]) {
             qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n",  __func__);
         }
         break;
@@ -706,19 +691,10 @@ static const MemoryRegionOps aspeed_i2c_pool_ops = {
 
 static const VMStateDescription aspeed_i2c_bus_vmstate = {
     .name = TYPE_ASPEED_I2C,
-    .version_id = 3,
-    .minimum_version_id = 3,
+    .version_id = 4,
+    .minimum_version_id = 4,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, AspeedI2CBus),
-        VMSTATE_UINT32(ctrl, AspeedI2CBus),
-        VMSTATE_UINT32_ARRAY(timing, AspeedI2CBus, 2),
-        VMSTATE_UINT32(intr_ctrl, AspeedI2CBus),
-        VMSTATE_UINT32(intr_status, AspeedI2CBus),
-        VMSTATE_UINT32(cmd, AspeedI2CBus),
-        VMSTATE_UINT32(buf, AspeedI2CBus),
-        VMSTATE_UINT32(pool_ctrl, AspeedI2CBus),
-        VMSTATE_UINT32(dma_addr, AspeedI2CBus),
-        VMSTATE_UINT32(dma_len, AspeedI2CBus),
+        VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_OLD_NUM_REG),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -858,12 +834,12 @@ static void aspeed_i2c_bus_reset(DeviceState *dev)
 {
     AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
 
-    s->intr_ctrl = 0;
-    s->intr_status = 0;
-    s->cmd = 0;
-    s->buf = 0;
-    s->dma_addr = 0;
-    s->dma_len = 0;
+    s->regs[R_I2CD_INTR_CTRL] = 0;
+    s->regs[R_I2CD_INTR_STS] = 0;
+    s->regs[R_I2CD_CMD] = 0;
+    s->regs[R_I2CD_BYTE_BUF] = 0;
+    s->regs[R_I2CD_DMA_ADDR] = 0;
+    s->regs[R_I2CD_DMA_LEN] = 0;
     i2c_end_transfer(s->bus);
 }
 
@@ -921,10 +897,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
 static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
 {
     uint8_t *pool_page =
-        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
-                                          POOL_PAGE_SEL) * 0x100];
+        &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
+                                                POOL_PAGE_SEL) * 0x100];
 
-    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
+    return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
 }
 
 static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 05/21] aspeed: i2c: Add new mode support
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (3 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 06/21] aspeed: i2c: Add PKT_DONE IRQ to trace Cédric Le Goater
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

On AST2600, I2C has a secondary mode, called "new mode", which changes
the layout of registers, adds some minor behavior changes, and
introduces a new way to transfer data called "packet mode".

Most of the bit positions of the fields are the same between old and new
mode, so we use SHARED_FIELD_XX macros to reuse most of the code between
the different modes.

For packet mode, most of the command behavior is the same compared to
other modes, but there are some minor changes to how interrupts are
handled compared to other modes.

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: I072f8301964f623afc74af1fe50c12e5caef199e
Message-Id: <20220331043248.2237838-6-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h |   4 +-
 hw/i2c/aspeed_i2c.c         | 844 +++++++++++++++++++++++++++---------
 2 files changed, 653 insertions(+), 195 deletions(-)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index e9f83a954096..86b18d6751ca 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -34,6 +34,7 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 #define ASPEED_I2C_NR_BUSSES 16
 #define ASPEED_I2C_MAX_POOL_SIZE 0x800
 #define ASPEED_I2C_OLD_NUM_REG 11
+#define ASPEED_I2C_NEW_NUM_REG 22
 
 struct AspeedI2CState;
 
@@ -50,7 +51,7 @@ struct AspeedI2CBus {
     uint8_t id;
     qemu_irq irq;
 
-    uint32_t regs[ASPEED_I2C_OLD_NUM_REG];
+    uint32_t regs[ASPEED_I2C_NEW_NUM_REG];
 };
 
 struct AspeedI2CState {
@@ -61,6 +62,7 @@ struct AspeedI2CState {
 
     uint32_t intr_status;
     uint32_t ctrl_global;
+    uint32_t new_clk_divider;
     MemoryRegion pool_iomem;
     uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
 
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index e93805515082..948d8dc2bb11 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -31,141 +31,302 @@
 #include "hw/registerfields.h"
 #include "trace.h"
 
+/* Tx State Machine */
+#define   I2CD_TX_STATE_MASK                  0xf
+#define     I2CD_IDLE                         0x0
+#define     I2CD_MACTIVE                      0x8
+#define     I2CD_MSTART                       0x9
+#define     I2CD_MSTARTR                      0xa
+#define     I2CD_MSTOP                        0xb
+#define     I2CD_MTXD                         0xc
+#define     I2CD_MRXACK                       0xd
+#define     I2CD_MRXD                         0xe
+#define     I2CD_MTXACK                       0xf
+#define     I2CD_SWAIT                        0x1
+#define     I2CD_SRXD                         0x4
+#define     I2CD_STXACK                       0x5
+#define     I2CD_STXD                         0x6
+#define     I2CD_SRXACK                       0x7
+#define     I2CD_RECOVER                      0x3
+
 /* I2C Global Register */
 REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */
 REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */
 REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */
+    FIELD(I2C_CTRL_GLOBAL, REG_MODE, 2, 1)
     FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1)
+REG32(I2C_CTRL_NEW_CLK_DIVIDER, 0x10) /* New mode clock divider */
 
-/* I2C Device (Bus) Register */
+/* I2C Old Mode Device (Bus) Register */
 REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control  */
     FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */
-    FIELD(I2CD_FUN_CTRL, M_SDA_LOCK_EN, 16, 1)
-    FIELD(I2CD_FUN_CTRL, MULTI_MASTER_DIS, 15, 1)
-    FIELD(I2CD_FUN_CTRL, M_SCL_DRIVE_EN, 14, 1)
-    FIELD(I2CD_FUN_CTRL, MSB_STS, 9, 1)
-    FIELD(I2CD_FUN_CTRL, SDA_DRIVE_IT_EN, 8, 1)
-    FIELD(I2CD_FUN_CTRL, M_SDA_DRIVE_IT_EN, 7, 1)
-    FIELD(I2CD_FUN_CTRL, M_HIGH_SPEED_EN, 6, 1)
-    FIELD(I2CD_FUN_CTRL, DEF_ADDR_EN, 5, 1)
-    FIELD(I2CD_FUN_CTRL, DEF_ALERT_EN, 4, 1)
-    FIELD(I2CD_FUN_CTRL, DEF_ARP_EN, 3, 1)
-    FIELD(I2CD_FUN_CTRL, DEF_GCALL_EN, 2, 1)
-    FIELD(I2CD_FUN_CTRL, SLAVE_EN, 1, 1)
-    FIELD(I2CD_FUN_CTRL, MASTER_EN, 0, 1)
+    SHARED_FIELD(M_SDA_LOCK_EN, 16, 1)
+    SHARED_FIELD(MULTI_MASTER_DIS, 15, 1)
+    SHARED_FIELD(M_SCL_DRIVE_EN, 14, 1)
+    SHARED_FIELD(MSB_STS, 9, 1)
+    SHARED_FIELD(SDA_DRIVE_IT_EN, 8, 1)
+    SHARED_FIELD(M_SDA_DRIVE_IT_EN, 7, 1)
+    SHARED_FIELD(M_HIGH_SPEED_EN, 6, 1)
+    SHARED_FIELD(DEF_ADDR_EN, 5, 1)
+    SHARED_FIELD(DEF_ALERT_EN, 4, 1)
+    SHARED_FIELD(DEF_ARP_EN, 3, 1)
+    SHARED_FIELD(DEF_GCALL_EN, 2, 1)
+    SHARED_FIELD(SLAVE_EN, 1, 1)
+    SHARED_FIELD(MASTER_EN, 0, 1)
 REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */
 REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */
 REG32(I2CD_INTR_CTRL, 0x0C)  /* I2CD Interrupt Control */
 REG32(I2CD_INTR_STS, 0x10)   /* I2CD Interrupt Status */
-    FIELD(I2CD_INTR_STS, SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
-    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_PENDING, 29, 1)
-    FIELD(I2CD_INTR_STS, SLAVE_INACTIVE_TIMEOUT, 15, 1)
-    FIELD(I2CD_INTR_STS, SDA_DL_TIMEOUT, 14, 1)
-    FIELD(I2CD_INTR_STS, BUS_RECOVER_DONE, 13, 1)
-    FIELD(I2CD_INTR_STS, SMBUS_ALERT, 12, 1)            /* Bus [0-3] only */
+    SHARED_FIELD(SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
+    SHARED_FIELD(SLAVE_ADDR_RX_PENDING, 29, 1)
+    SHARED_FIELD(SLAVE_INACTIVE_TIMEOUT, 15, 1)
+    SHARED_FIELD(SDA_DL_TIMEOUT, 14, 1)
+    SHARED_FIELD(BUS_RECOVER_DONE, 13, 1)
+    SHARED_FIELD(SMBUS_ALERT, 12, 1)                    /* Bus [0-3] only */
     FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1)         /* Removed */
     FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1)   /* Removed */
     FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1)          /* Removed */
     FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1)              /* Removed */
     FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)     /* use RX_DONE */
-    FIELD(I2CD_INTR_STS, SCL_TIMEOUT, 6, 1)
-    FIELD(I2CD_INTR_STS, ABNORMAL, 5, 1)
-    FIELD(I2CD_INTR_STS, NORMAL_STOP, 4, 1)
-    FIELD(I2CD_INTR_STS, ARBIT_LOSS, 3, 1)
-    FIELD(I2CD_INTR_STS, RX_DONE, 2, 1)
-    FIELD(I2CD_INTR_STS, TX_NAK, 1, 1)
-    FIELD(I2CD_INTR_STS, TX_ACK, 0, 1)
+    SHARED_FIELD(SCL_TIMEOUT, 6, 1)
+    SHARED_FIELD(ABNORMAL, 5, 1)
+    SHARED_FIELD(NORMAL_STOP, 4, 1)
+    SHARED_FIELD(ARBIT_LOSS, 3, 1)
+    SHARED_FIELD(RX_DONE, 2, 1)
+    SHARED_FIELD(TX_NAK, 1, 1)
+    SHARED_FIELD(TX_ACK, 0, 1)
 REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
-    FIELD(I2CD_CMD, SDA_OE, 28, 1)
-    FIELD(I2CD_CMD, SDA_O, 27, 1)
-    FIELD(I2CD_CMD, SCL_OE, 26, 1)
-    FIELD(I2CD_CMD, SCL_O, 25, 1)
-    FIELD(I2CD_CMD, TX_TIMING, 23, 2)
-    FIELD(I2CD_CMD, TX_STATE, 19, 4)
-/* Tx State Machine */
-#define   I2CD_TX_STATE_MASK                  0xf
-#define     I2CD_IDLE                         0x0
-#define     I2CD_MACTIVE                      0x8
-#define     I2CD_MSTART                       0x9
-#define     I2CD_MSTARTR                      0xa
-#define     I2CD_MSTOP                        0xb
-#define     I2CD_MTXD                         0xc
-#define     I2CD_MRXACK                       0xd
-#define     I2CD_MRXD                         0xe
-#define     I2CD_MTXACK                       0xf
-#define     I2CD_SWAIT                        0x1
-#define     I2CD_SRXD                         0x4
-#define     I2CD_STXACK                       0x5
-#define     I2CD_STXD                         0x6
-#define     I2CD_SRXACK                       0x7
-#define     I2CD_RECOVER                      0x3
-    FIELD(I2CD_CMD, SCL_LINE_STS, 18, 1)
-    FIELD(I2CD_CMD, SDA_LINE_STS, 17, 1)
-    FIELD(I2CD_CMD, BUS_BUSY_STS, 16, 1)
-    FIELD(I2CD_CMD, SDA_OE_OUT_DIR, 15, 1)
-    FIELD(I2CD_CMD, SDA_O_OUT_DIR, 14, 1)
-    FIELD(I2CD_CMD, SCL_OE_OUT_DIR, 13, 1)
-    FIELD(I2CD_CMD, SCL_O_OUT_DIR, 12, 1)
-    FIELD(I2CD_CMD, BUS_RECOVER_CMD_EN, 11, 1)
-    FIELD(I2CD_CMD, S_ALT_EN, 10, 1)
+    SHARED_FIELD(SDA_OE, 28, 1)
+    SHARED_FIELD(SDA_O, 27, 1)
+    SHARED_FIELD(SCL_OE, 26, 1)
+    SHARED_FIELD(SCL_O, 25, 1)
+    SHARED_FIELD(TX_TIMING, 23, 2)
+    SHARED_FIELD(TX_STATE, 19, 4)
+    SHARED_FIELD(SCL_LINE_STS, 18, 1)
+    SHARED_FIELD(SDA_LINE_STS, 17, 1)
+    SHARED_FIELD(BUS_BUSY_STS, 16, 1)
+    SHARED_FIELD(SDA_OE_OUT_DIR, 15, 1)
+    SHARED_FIELD(SDA_O_OUT_DIR, 14, 1)
+    SHARED_FIELD(SCL_OE_OUT_DIR, 13, 1)
+    SHARED_FIELD(SCL_O_OUT_DIR, 12, 1)
+    SHARED_FIELD(BUS_RECOVER_CMD_EN, 11, 1)
+    SHARED_FIELD(S_ALT_EN, 10, 1)
     /* Command Bits */
-    FIELD(I2CD_CMD, RX_DMA_EN, 9, 1)
-    FIELD(I2CD_CMD, TX_DMA_EN, 8, 1)
-    FIELD(I2CD_CMD, RX_BUFF_EN, 7, 1)
-    FIELD(I2CD_CMD, TX_BUFF_EN, 6, 1)
-    FIELD(I2CD_CMD, M_STOP_CMD, 5, 1)
-    FIELD(I2CD_CMD, M_S_RX_CMD_LAST, 4, 1)
-    FIELD(I2CD_CMD, M_RX_CMD, 3, 1)
-    FIELD(I2CD_CMD, S_TX_CMD, 2, 1)
-    FIELD(I2CD_CMD, M_TX_CMD, 1, 1)
-    FIELD(I2CD_CMD, M_START_CMD, 0, 1)
+    SHARED_FIELD(RX_DMA_EN, 9, 1)
+    SHARED_FIELD(TX_DMA_EN, 8, 1)
+    SHARED_FIELD(RX_BUFF_EN, 7, 1)
+    SHARED_FIELD(TX_BUFF_EN, 6, 1)
+    SHARED_FIELD(M_STOP_CMD, 5, 1)
+    SHARED_FIELD(M_S_RX_CMD_LAST, 4, 1)
+    SHARED_FIELD(M_RX_CMD, 3, 1)
+    SHARED_FIELD(S_TX_CMD, 2, 1)
+    SHARED_FIELD(M_TX_CMD, 1, 1)
+    SHARED_FIELD(M_START_CMD, 0, 1)
 REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
 REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
-    FIELD(I2CD_POOL_CTRL, RX_COUNT, 24, 5)
-    FIELD(I2CD_POOL_CTRL, RX_SIZE, 16, 5)
-    FIELD(I2CD_POOL_CTRL, TX_COUNT, 9, 5)
+    SHARED_FIELD(RX_COUNT, 24, 5)
+    SHARED_FIELD(RX_SIZE, 16, 5)
+    SHARED_FIELD(TX_COUNT, 9, 5)
     FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
 REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
-    FIELD(I2CD_BYTE_BUF, RX_BUF, 8, 8)
-    FIELD(I2CD_BYTE_BUF, TX_BUF, 0, 8)
+    SHARED_FIELD(RX_BUF, 8, 8)
+    SHARED_FIELD(TX_BUF, 0, 8)
 REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */
 REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
 
+/* I2C New Mode Device (Bus) Register */
+REG32(I2CC_FUN_CTRL, 0x0)
+    FIELD(I2CC_FUN_CTRL, RB_EARLY_DONE_EN, 22, 1)
+    FIELD(I2CC_FUN_CTRL, DMA_DIS_AUTO_RECOVER, 21, 1)
+    FIELD(I2CC_FUN_CTRL, S_SAVE_ADDR, 20, 1)
+    FIELD(I2CC_FUN_CTRL, M_PKT_RETRY_CNT, 18, 2)
+    /* 17:0 shared with I2CD_FUN_CTRL[17:0] */
+REG32(I2CC_AC_TIMING, 0x04)
+REG32(I2CC_MS_TXRX_BYTE_BUF, 0x08)
+    /* 31:16 shared with I2CD_CMD[31:16] */
+    /* 15:0  shared with I2CD_BYTE_BUF[15:0] */
+REG32(I2CC_POOL_CTRL, 0x0c)
+    /* 31:0 shared with I2CD_POOL_CTRL[31:0] */
+REG32(I2CM_INTR_CTRL, 0x10)
+REG32(I2CM_INTR_STS, 0x14)
+    FIELD(I2CM_INTR_STS, PKT_STATE, 28, 4)
+    FIELD(I2CM_INTR_STS, PKT_CMD_TIMEOUT, 18, 1)
+    FIELD(I2CM_INTR_STS, PKT_CMD_FAIL, 17, 1)
+    FIELD(I2CM_INTR_STS, PKT_CMD_DONE, 16, 1)
+    FIELD(I2CM_INTR_STS, BUS_RECOVER_FAIL, 15, 1)
+    /* 14:0 shared with I2CD_INTR_STS[14:0] */
+REG32(I2CM_CMD, 0x18)
+    FIELD(I2CM_CMD, W1_CTRL, 31, 1)
+    FIELD(I2CM_CMD, PKT_DEV_ADDR, 24, 7)
+    FIELD(I2CM_CMD, HS_MASTER_MODE_LSB, 17, 3)
+    FIELD(I2CM_CMD, PKT_OP_EN, 16, 1)
+    /* 15:0 shared with I2CD_CMD[15:0] */
+REG32(I2CM_DMA_LEN, 0x1c)
+    FIELD(I2CM_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
+    FIELD(I2CM_DMA_LEN, RX_BUF_LEN, 16, 11)
+    FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
+    FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
+REG32(I2CS_INTR_CTRL, 0x20)
+REG32(I2CS_INTR_STS, 0x24)
+    /* 31:29 shared with I2CD_INTR_STS[31:29] */
+    FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR3_NAK, 22, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR2_NAK, 21, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR1_NAK, 20, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR_INDICATOR, 18, 2)
+    FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
+    FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
+    /* 14:0 shared with I2CD_INTR_STS[14:0] */
+REG32(I2CS_CMD, 0x28)
+    FIELD(I2CS_CMD, W1_CTRL, 31, 1)
+    FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
+    FIELD(I2CS_CMD, PKT_MODE_EN, 16, 1)
+    FIELD(I2CS_CMD, AUTO_NAK_INACTIVE_ADDR, 15, 1)
+    FIELD(I2CS_CMD, AUTO_NAK_ACTIVE_ADDR, 14, 1)
+    /* 13:0 shared with I2CD_CMD[13:0] */
+REG32(I2CS_DMA_LEN, 0x2c)
+    FIELD(I2CS_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
+    FIELD(I2CS_DMA_LEN, RX_BUF_LEN, 16, 11)
+    FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
+    FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11)
+REG32(I2CM_DMA_TX_ADDR, 0x30)
+    FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31)
+REG32(I2CM_DMA_RX_ADDR, 0x34)
+    FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DMA_TX_ADDR, 0x38)
+    FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DMA_RX_ADDR, 0x3c)
+    FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DEV_ADDR, 0x40)
+REG32(I2CM_DMA_LEN_STS, 0x48)
+    FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13)
+    FIELD(I2CM_DMA_LEN_STS, TX_LEN, 0, 13)
+REG32(I2CS_DMA_LEN_STS, 0x4c)
+    FIELD(I2CS_DMA_LEN_STS, RX_LEN, 16, 13)
+    FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13)
+REG32(I2CC_DMA_ADDR, 0x50)
+REG32(I2CC_DMA_LEN, 0x54)
+
+static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
+{
+    return FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, REG_MODE);
+}
+
+static inline bool aspeed_i2c_bus_pkt_mode_en(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_OP_EN);
+    }
+    return false;
+}
+
+static inline uint32_t aspeed_i2c_bus_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_FUN_CTRL;
+    }
+    return R_I2CD_FUN_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_CMD;
+    }
+    return R_I2CD_CMD;
+}
+
+static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_INTR_CTRL;
+    }
+    return R_I2CD_INTR_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_intr_sts_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_INTR_STS;
+    }
+    return R_I2CD_INTR_STS;
+}
+
+static inline uint32_t aspeed_i2c_bus_pool_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_POOL_CTRL;
+    }
+    return R_I2CD_POOL_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_byte_buf_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_MS_TXRX_BYTE_BUF;
+    }
+    return R_I2CD_BYTE_BUF;
+}
+
+static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_DMA_LEN;
+    }
+    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 ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, MASTER_EN);
+    return SHARED_ARRAY_FIELD_EX32(bus->regs, aspeed_i2c_bus_ctrl_offset(bus),
+                                   MASTER_EN);
 }
 
 static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
 {
-    return ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, MASTER_EN) ||
-           ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, SLAVE_EN);
+    uint32_t ctrl_reg = aspeed_i2c_bus_ctrl_offset(bus);
+    return SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, MASTER_EN) ||
+           SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, SLAVE_EN);
 }
 
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
-
-    trace_aspeed_i2c_bus_raise_interrupt(bus->regs[R_I2CD_INTR_STS],
-          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, TX_NAK) ? "nak|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, TX_ACK) ? "ack|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE) ? "done|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, NORMAL_STOP) ? "normal|"
+    uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+    uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus);
+    bool raise_irq;
+
+    trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts],
+        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? "nak|" : "",
+        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? "ack|" : "",
+        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? "done|"
                                                                   : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, ABNORMAL) ? "abnormal"
-                                                               : "");
-
-    bus->regs[R_I2CD_INTR_STS] &= bus->regs[R_I2CD_INTR_CTRL];
-    if (bus->regs[R_I2CD_INTR_STS]) {
+        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ?
+                                                                "normal|" : "",
+        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? "abnormal"
+                                                                   : "");
+    raise_irq = bus->regs[reg_intr_sts] & bus->regs[intr_ctrl_reg];
+    /* In packet mode we don't mask off INTR_STS */
+    if (!aspeed_i2c_bus_pkt_mode_en(bus)) {
+        bus->regs[reg_intr_sts] &= bus->regs[intr_ctrl_reg];
+    }
+    if (raise_irq) {
         bus->controller->intr_status |= 1 << bus->id;
         qemu_irq_raise(aic->bus_get_irq(bus));
     }
 }
 
-static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
-                                    unsigned size)
+static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
+                                        unsigned size)
 {
-    AspeedI2CBus *bus = opaque;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
 
@@ -180,8 +341,7 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
         /* Value is already set, don't do anything. */
         break;
     case A_I2CD_CMD:
-        value = FIELD_DP32(value, I2CD_CMD, BUS_BUSY_STS,
-                           i2c_bus_busy(bus->bus));
+        value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
         break;
     case A_I2CD_DMA_ADDR:
         if (!aic->has_dma) {
@@ -207,31 +367,86 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
     return value;
 }
 
+static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
+                                        unsigned size)
+{
+    uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
+
+    switch (offset) {
+    case A_I2CC_FUN_CTRL:
+    case A_I2CC_AC_TIMING:
+    case A_I2CC_POOL_CTRL:
+    case A_I2CM_INTR_CTRL:
+    case A_I2CM_INTR_STS:
+    case A_I2CC_MS_TXRX_BYTE_BUF:
+    case A_I2CM_DMA_LEN:
+    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:
+        /* Value is already set, don't do anything. */
+        break;
+    case A_I2CM_CMD:
+        value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
+        value = -1;
+        break;
+    }
+
+    trace_aspeed_i2c_bus_read(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_is_new_mode(bus->controller)) {
+        return aspeed_i2c_bus_new_read(bus, offset, size);
+    }
+    return aspeed_i2c_bus_old_read(bus, offset, size);
+}
+
 static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state)
 {
-    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_STATE, state);
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE,
+                                state);
+    } else {
+        SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state);
+    }
 }
 
 static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
 {
-    return ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_STATE);
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF,
+                                       TX_STATE);
+    }
+    return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE);
 }
 
 static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
 {
     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[R_I2CD_DMA_ADDR],
+    result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
                                 MEMTXATTRS_UNSPECIFIED, data, 1);
     if (result != MEMTX_OK) {
         qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
-                      __func__, bus->regs[R_I2CD_DMA_ADDR]);
+                      __func__, bus->regs[reg_dma_addr]);
         return -1;
     }
 
-    bus->regs[R_I2CD_DMA_ADDR]++;
-    bus->regs[R_I2CD_DMA_LEN]--;
+    bus->regs[reg_dma_addr]++;
+    bus->regs[reg_dma_len]--;
     return 0;
 }
 
@@ -240,9 +455,14 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     int ret = -1;
     int i;
-    int pool_tx_count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT);
-
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    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);
+    int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
+                                                TX_COUNT);
+
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) {
         for (i = pool_start; i < pool_tx_count; i++) {
             uint8_t *pool_base = aic->bus_pool_base(bus);
 
@@ -253,23 +473,33 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
                 break;
             }
         }
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_BUFF_EN, 0);
-    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
-        while (bus->regs[R_I2CD_DMA_LEN]) {
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0);
+    } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) {
+        /* In new mode, clear how many bytes we TXed */
+        if (aspeed_i2c_is_new_mode(bus->controller)) {
+            ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0);
+        }
+        while (bus->regs[reg_dma_len]) {
             uint8_t data;
             aspeed_i2c_dma_read(bus, &data);
-            trace_aspeed_i2c_bus_send("DMA", bus->regs[R_I2CD_DMA_LEN],
-                                      bus->regs[R_I2CD_DMA_LEN], data);
+            trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len],
+                                      bus->regs[reg_dma_len], data);
             ret = i2c_send(bus->bus, data);
             if (ret) {
                 break;
             }
+            /* In new mode, keep track of how many bytes we TXed */
+            if (aspeed_i2c_is_new_mode(bus->controller)) {
+                ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN,
+                                 ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS,
+                                                  TX_LEN) + 1);
+            }
         }
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, TX_DMA_EN, 0);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0);
     } else {
         trace_aspeed_i2c_bus_send("BYTE", pool_start, 1,
-                                  bus->regs[R_I2CD_BYTE_BUF]);
-        ret = i2c_send(bus->bus, bus->regs[R_I2CD_BYTE_BUF]);
+                                  bus->regs[reg_byte_buf]);
+        ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]);
     }
 
     return ret;
@@ -281,9 +511,15 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
     uint8_t data;
     int i;
-    int pool_rx_count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, RX_COUNT);
-
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN)) {
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    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_COUNT);
+
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
         for (i = 0; i < pool_rx_count; i++) {
@@ -293,64 +529,82 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
         }
 
         /* Update RX count */
-        ARRAY_FIELD_DP32(bus->regs, I2CD_POOL_CTRL, RX_COUNT, i & 0xff);
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, RX_BUFF_EN, 0);
-    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)) {
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0);
+    } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) {
         uint8_t data;
+        /* In new mode, clear how many bytes we RXed */
+        if (aspeed_i2c_is_new_mode(bus->controller)) {
+            ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0);
+        }
 
-        while (bus->regs[R_I2CD_DMA_LEN]) {
+        while (bus->regs[reg_dma_len]) {
             MemTxResult result;
 
             data = i2c_recv(bus->bus);
-            trace_aspeed_i2c_bus_recv("DMA", bus->regs[R_I2CD_DMA_LEN],
-                                      bus->regs[R_I2CD_DMA_LEN], data);
-            result = address_space_write(&s->dram_as,
-                                         bus->regs[R_I2CD_DMA_ADDR],
+            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],
                                          MEMTXATTRS_UNSPECIFIED, &data, 1);
             if (result != MEMTX_OK) {
                 qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
-                              __func__, bus->regs[R_I2CD_DMA_ADDR]);
+                              __func__, bus->regs[reg_dma_addr]);
                 return;
             }
-            bus->regs[R_I2CD_DMA_ADDR]++;
-            bus->regs[R_I2CD_DMA_LEN]--;
+            bus->regs[reg_dma_addr]++;
+            bus->regs[reg_dma_len]--;
+            /* In new mode, keep track of how many bytes we RXed */
+            if (aspeed_i2c_is_new_mode(bus->controller)) {
+                ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN,
+                                 ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS,
+                                                  RX_LEN) + 1);
+            }
         }
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, RX_DMA_EN, 0);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0);
     } else {
         data = i2c_recv(bus->bus);
-        trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[R_I2CD_BYTE_BUF]);
-        ARRAY_FIELD_DP32(bus->regs, I2CD_BYTE_BUF, RX_BUF, data);
+        trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data);
     }
 }
 
 static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
 {
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+
     aspeed_i2c_set_state(bus, I2CD_MRXD);
     aspeed_i2c_bus_recv(bus);
-    ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, RX_DONE, 1);
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST)) {
+    SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1);
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) {
         i2c_nack(bus->bus);
     }
-    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_RX_CMD, 0);
-    ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST, 0);
+    SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0);
+    SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0);
     aspeed_i2c_set_state(bus, I2CD_MACTIVE);
 }
 
 static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+    uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
 
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
+    if (aspeed_i2c_bus_pkt_mode_en(bus)) {
+        return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) |
+                SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD);
+    }
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) {
         uint8_t *pool_base = aic->bus_pool_base(bus);
 
         return pool_base[0];
-    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
+    } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) {
         uint8_t data;
 
         aspeed_i2c_dma_read(bus, &data);
         return data;
     } else {
-        return bus->regs[R_I2CD_BYTE_BUF];
+        return bus->regs[reg_byte_buf];
     }
 }
 
@@ -358,10 +612,11 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
 {
     AspeedI2CState *s = bus->controller;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
-    bool dma_en = ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)  ||
-                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)  ||
-                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN) ||
-                  ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN);
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)  ||
+                  SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)  ||
+                  SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ||
+                  SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN);
     if (!aic->check_sram) {
         return true;
     }
@@ -382,27 +637,31 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
 {
     g_autofree char *cmd_flags = NULL;
     uint32_t count;
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN)) {
-        count = ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT);
-    } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN)) {
-        count = bus->regs[R_I2CD_DMA_LEN];
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
+    uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+    uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) {
+        count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT);
+    } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) {
+        count = bus->regs[reg_dma_len];
     } else { /* BYTE mode */
         count = 1;
     }
 
     cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_START_CMD) ? "start|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_DMA_EN) ? "rxdma|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN) ? "txdma|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, RX_BUFF_EN) ? "rxbuf|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN) ? "txbuf|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_TX_CMD) ? "tx|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ? "rx|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST) ? "last|" : "",
-          ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_STOP_CMD) ? "stop" : "");
-
-    trace_aspeed_i2c_bus_cmd(bus->regs[R_I2CD_CMD], cmd_flags, count,
-                             bus->regs[R_I2CD_INTR_STS]);
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "",
+    SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : "");
+
+    trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count,
+                             bus->regs[reg_intr_sts]);
 }
 
 /*
@@ -412,9 +671,10 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
 static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
 {
     uint8_t pool_start = 0;
-
-    bus->regs[R_I2CD_CMD] &= ~0xFFFF;
-    bus->regs[R_I2CD_CMD] |= value & 0xFFFF;
+    uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
+    uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus);
+    uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
+    uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
 
     if (!aspeed_i2c_check_sram(bus)) {
         return;
@@ -424,7 +684,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_bus_cmd_dump(bus);
     }
 
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_START_CMD)) {
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) {
         uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
             I2CD_MSTARTR : I2CD_MSTART;
         uint8_t addr;
@@ -432,24 +692,30 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
         aspeed_i2c_set_state(bus, state);
 
         addr = aspeed_i2c_get_addr(bus);
-
         if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
                                extract32(addr, 0, 1))) {
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_NAK, 1);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1);
+            if (aspeed_i2c_bus_pkt_mode_en(bus)) {
+                ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1);
+            }
         } else {
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_ACK, 1);
+            /* START doesn't set TX_ACK in packet mode */
+            if (!aspeed_i2c_bus_pkt_mode_en(bus)) {
+                SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1);
+            }
         }
 
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_START_CMD, 0);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0);
 
         /*
          * The START command is also a TX command, as the slave
          * address is sent on the bus. Drop the TX flag if nothing
          * else needs to be sent in this sequence.
          */
-        if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_BUFF_EN)) {
-            if (ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, TX_COUNT) == 1) {
-                ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
+        if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) {
+            if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT)
+                == 1) {
+                SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0);
             } else {
                 /*
                  * Increase the start index in the TX pool buffer to
@@ -457,57 +723,216 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
                  */
                 pool_start++;
             }
-        } else if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, TX_DMA_EN)) {
-            if (bus->regs[R_I2CD_DMA_LEN] == 0) {
-                ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
+        } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) {
+            if (bus->regs[reg_dma_len] == 0) {
+                SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0);
             }
         } else {
-            ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0);
         }
 
         /* No slave found */
         if (!i2c_bus_busy(bus->bus)) {
+            if (aspeed_i2c_bus_pkt_mode_en(bus)) {
+                ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1);
+                ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1);
+            }
             return;
         }
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_TX_CMD)) {
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) {
         aspeed_i2c_set_state(bus, I2CD_MTXD);
         if (aspeed_i2c_bus_send(bus, pool_start)) {
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_NAK, 1);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1);
             i2c_end_transfer(bus->bus);
         } else {
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, TX_ACK, 1);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1);
         }
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_TX_CMD, 0);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_MACTIVE);
     }
 
-    if ((ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ||
-         ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST)) &&
-        !ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE)) {
+    if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ||
+         SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) &&
+        !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) {
         aspeed_i2c_handle_rx_cmd(bus);
     }
 
-    if (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_STOP_CMD)) {
+    if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) {
         if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__);
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, ABNORMAL, 1);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1);
+            if (aspeed_i2c_bus_pkt_mode_en(bus)) {
+                ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1);
+            }
         } else {
             aspeed_i2c_set_state(bus, I2CD_MSTOP);
             i2c_end_transfer(bus->bus);
-            ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, NORMAL_STOP, 1);
+            SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1);
         }
-        ARRAY_FIELD_DP32(bus->regs, I2CD_CMD, M_STOP_CMD, 0);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0);
         aspeed_i2c_set_state(bus, I2CD_IDLE);
     }
+
+    if (aspeed_i2c_bus_pkt_mode_en(bus)) {
+        ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1);
+    }
 }
 
-static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
-                                 uint64_t value, unsigned size)
+static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
+                                     uint64_t value, unsigned size)
+{
+    AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
+    bool handle_rx;
+    bool w1t;
+
+    trace_aspeed_i2c_bus_write(bus->id, offset, size, value);
+
+    switch (offset) {
+    case A_I2CC_FUN_CTRL:
+        if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
+            qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
+                          __func__);
+            break;
+        }
+        bus->regs[R_I2CD_FUN_CTRL] = value & 0x007dc3ff;
+        break;
+    case A_I2CC_AC_TIMING:
+        bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff;
+        break;
+    case A_I2CC_MS_TXRX_BYTE_BUF:
+        SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF,
+                                value);
+        break;
+    case A_I2CC_POOL_CTRL:
+        bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff;
+        bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff);
+        break;
+    case A_I2CM_INTR_CTRL:
+        bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f;
+        break;
+    case A_I2CM_INTR_STS:
+        handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE)
+                    && SHARED_FIELD_EX32(value, RX_DONE);
+
+        /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */
+        if (aspeed_i2c_bus_pkt_mode_en(bus) &&
+           FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) {
+            bus->regs[R_I2CM_INTR_STS] &= 0xf0001000;
+            if (!bus->regs[R_I2CM_INTR_STS]) {
+                bus->controller->intr_status &= ~(1 << bus->id);
+                qemu_irq_lower(aic->bus_get_irq(bus));
+            }
+            break;
+        }
+        bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f);
+        if (!bus->regs[R_I2CM_INTR_STS]) {
+            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_I2CM_CMD,
+                                                  M_RX_CMD) ||
+                          SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD,
+                                                  M_S_RX_CMD_LAST))) {
+            aspeed_i2c_handle_rx_cmd(bus);
+            aspeed_i2c_bus_raise_interrupt(bus);
+        }
+        break;
+    case A_I2CM_CMD:
+        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;
+        }
+
+        if (!aic->has_dma &&
+            (SHARED_FIELD_EX32(value, RX_DMA_EN) ||
+             SHARED_FIELD_EX32(value, TX_DMA_EN))) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
+            break;
+        }
+
+        if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) {
+            qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n",
+                          __func__);
+            break;
+        }
+
+        value &= 0xff0ffbfb;
+        if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) {
+            bus->regs[R_I2CM_CMD] |= value;
+        } else {
+            bus->regs[R_I2CM_CMD] = value;
+        }
+
+        aspeed_i2c_bus_handle_cmd(bus, value);
+        aspeed_i2c_bus_raise_interrupt(bus);
+        break;
+    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->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->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
+                                                     RX_BUF_LEN) + 1;
+        break;
+    case A_I2CM_DMA_LEN:
+        w1t = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T) ||
+                   ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T);
+        /* If none of the w1t bits are set, just write to the reg as normal. */
+        if (!w1t) {
+            bus->regs[R_I2CM_DMA_LEN] = value;
+            break;
+        }
+        if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) {
+            ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN,
+                             FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN));
+        }
+        if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) {
+            ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN,
+                             FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN));
+        }
+        break;
+    case A_I2CM_DMA_LEN_STS:
+        /* Writes clear to 0 */
+        bus->regs[R_I2CM_DMA_LEN_STS] = 0;
+        break;
+    case A_I2CC_DMA_ADDR:
+    case A_I2CC_DMA_LEN:
+        /* RO */
+        break;
+    case A_I2CS_DMA_LEN_STS:
+    case A_I2CS_DMA_TX_ADDR:
+    case A_I2CS_DMA_RX_ADDR:
+    case A_I2CS_DEV_ADDR:
+    case A_I2CS_INTR_CTRL:
+    case A_I2CS_INTR_STS:
+    case A_I2CS_CMD:
+    case A_I2CS_DMA_LEN:
+        qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n",
+                      __func__);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+    }
+}
+
+static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
+                                     uint64_t value, unsigned size)
 {
-    AspeedI2CBus *bus = opaque;
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     bool handle_rx;
 
@@ -515,7 +940,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
 
     switch (offset) {
     case A_I2CD_FUN_CTRL:
-        if (FIELD_EX32(value, I2CD_FUN_CTRL, SLAVE_EN)) {
+        if (SHARED_FIELD_EX32(value, SLAVE_EN)) {
             qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
                           __func__);
             break;
@@ -532,15 +957,17 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF;
         break;
     case A_I2CD_INTR_STS:
-        handle_rx = ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, RX_DONE) &&
-                    FIELD_EX32(value, I2CD_INTR_STS, RX_DONE);
+        handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE)
+                    && SHARED_FIELD_EX32(value, RX_DONE);
         bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF);
         if (!bus->regs[R_I2CD_INTR_STS]) {
             bus->controller->intr_status &= ~(1 << bus->id);
             qemu_irq_lower(aic->bus_get_irq(bus));
         }
-        if (handle_rx && (ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_RX_CMD) ||
-                      ARRAY_FIELD_EX32(bus->regs, I2CD_CMD, M_S_RX_CMD_LAST))) {
+        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);
         }
@@ -555,7 +982,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         break;
 
     case A_I2CD_BYTE_BUF:
-        ARRAY_FIELD_DP32(bus->regs, I2CD_BYTE_BUF, TX_BUF, value);
+        SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value);
         break;
     case A_I2CD_CMD:
         if (!aspeed_i2c_bus_is_enabled(bus)) {
@@ -569,12 +996,15 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
         }
 
         if (!aic->has_dma &&
-            (FIELD_EX32(value, I2CD_CMD, RX_DMA_EN) ||
-             FIELD_EX32(value, I2CD_CMD, TX_DMA_EN))) {
+            (SHARED_FIELD_EX32(value, RX_DMA_EN) ||
+             SHARED_FIELD_EX32(value, TX_DMA_EN))) {
             qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
             break;
         }
 
+        bus->regs[R_I2CD_CMD] &= ~0xFFFF;
+        bus->regs[R_I2CD_CMD] |= value & 0xFFFF;
+
         aspeed_i2c_bus_handle_cmd(bus, value);
         aspeed_i2c_bus_raise_interrupt(bus);
         break;
@@ -605,6 +1035,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_is_new_mode(bus->controller)) {
+        aspeed_i2c_bus_new_write(bus, offset, value, size);
+    } else {
+        aspeed_i2c_bus_old_write(bus, offset, value, size);
+    }
+}
+
 static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
                                    unsigned size)
 {
@@ -615,6 +1056,13 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
         return s->intr_status;
     case A_I2C_CTRL_GLOBAL:
         return s->ctrl_global;
+    case A_I2C_CTRL_NEW_CLK_DIVIDER:
+        if (aspeed_i2c_is_new_mode(s)) {
+            return s->new_clk_divider;
+        }
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
                       __func__, offset);
@@ -634,6 +1082,14 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
         value &= ~s->ctrl_global_rsvd;
         s->ctrl_global = value;
         break;
+    case A_I2C_CTRL_NEW_CLK_DIVIDER:
+        if (aspeed_i2c_is_new_mode(s)) {
+            s->new_clk_divider = value;
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx
+                          "\n", __func__, offset);
+        }
+        break;
     case A_I2C_CTRL_STATUS:
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@@ -691,10 +1147,10 @@ static const MemoryRegionOps aspeed_i2c_pool_ops = {
 
 static const VMStateDescription aspeed_i2c_bus_vmstate = {
     .name = TYPE_ASPEED_I2C,
-    .version_id = 4,
-    .minimum_version_id = 4,
+    .version_id = 5,
+    .minimum_version_id = 5,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_OLD_NUM_REG),
+        VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 06/21] aspeed: i2c: Add PKT_DONE IRQ to trace
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (4 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 05/21] aspeed: i2c: Add new mode support Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 07/21] aspeed: i2c: Move regs and helpers to header file Cédric Le Goater
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: I566eb09f4b9016e24570572f367627f6594039f5
Message-Id: <20220331043248.2237838-7-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/i2c/aspeed_i2c.c | 3 +++
 hw/i2c/trace-events | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 948d8dc2bb11..f179f78ee9d0 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -305,6 +305,9 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
     bool raise_irq;
 
     trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts],
+        aspeed_i2c_bus_pkt_mode_en(bus) &&
+        ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ?
+                                                               "pktdone|" : "",
         SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? "nak|" : "",
         SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? "ack|" : "",
         SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? "done|"
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 7d8907c1eede..85e4bddff936 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -9,7 +9,7 @@ i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
 # aspeed_i2c.c
 
 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_raise_interrupt(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(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_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 07/21] aspeed: i2c: Move regs and helpers to header file
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (5 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 06/21] aspeed: i2c: Add PKT_DONE IRQ to trace Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 08/21] test/avocado/machine_aspeed.py: Move OpenBMC tests Cédric Le Goater
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Joe Komlodi <komlodi@google.com>

Moves register definitions and short commonly used inlined functiosn to
the header file to help tidy up the implementation file.

Signed-off-by: Joe Komlodi <komlodi@google.com>
Change-Id: I34dff7485b6bbe3c9482715ccd94dbd65dc5f324
Message-Id: <20220331043248.2237838-8-komlodi@google.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h | 267 ++++++++++++++++++++++++++++++++++++
 hw/i2c/aspeed_i2c.c         | 266 -----------------------------------
 2 files changed, 267 insertions(+), 266 deletions(-)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 86b18d6751ca..506bcf1a9daf 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -23,6 +23,7 @@
 
 #include "hw/i2c/i2c.h"
 #include "hw/sysbus.h"
+#include "hw/registerfields.h"
 #include "qom/object.h"
 
 #define TYPE_ASPEED_I2C "aspeed.i2c"
@@ -36,6 +37,182 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
 #define ASPEED_I2C_OLD_NUM_REG 11
 #define ASPEED_I2C_NEW_NUM_REG 22
 
+/* Tx State Machine */
+#define   I2CD_TX_STATE_MASK                  0xf
+#define     I2CD_IDLE                         0x0
+#define     I2CD_MACTIVE                      0x8
+#define     I2CD_MSTART                       0x9
+#define     I2CD_MSTARTR                      0xa
+#define     I2CD_MSTOP                        0xb
+#define     I2CD_MTXD                         0xc
+#define     I2CD_MRXACK                       0xd
+#define     I2CD_MRXD                         0xe
+#define     I2CD_MTXACK                       0xf
+#define     I2CD_SWAIT                        0x1
+#define     I2CD_SRXD                         0x4
+#define     I2CD_STXACK                       0x5
+#define     I2CD_STXD                         0x6
+#define     I2CD_SRXACK                       0x7
+#define     I2CD_RECOVER                      0x3
+
+/* I2C Global Register */
+REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */
+REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */
+REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */
+    FIELD(I2C_CTRL_GLOBAL, REG_MODE, 2, 1)
+    FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1)
+REG32(I2C_CTRL_NEW_CLK_DIVIDER, 0x10) /* New mode clock divider */
+
+/* I2C Old Mode Device (Bus) Register */
+REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control  */
+    FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */
+    SHARED_FIELD(M_SDA_LOCK_EN, 16, 1)
+    SHARED_FIELD(MULTI_MASTER_DIS, 15, 1)
+    SHARED_FIELD(M_SCL_DRIVE_EN, 14, 1)
+    SHARED_FIELD(MSB_STS, 9, 1)
+    SHARED_FIELD(SDA_DRIVE_IT_EN, 8, 1)
+    SHARED_FIELD(M_SDA_DRIVE_IT_EN, 7, 1)
+    SHARED_FIELD(M_HIGH_SPEED_EN, 6, 1)
+    SHARED_FIELD(DEF_ADDR_EN, 5, 1)
+    SHARED_FIELD(DEF_ALERT_EN, 4, 1)
+    SHARED_FIELD(DEF_ARP_EN, 3, 1)
+    SHARED_FIELD(DEF_GCALL_EN, 2, 1)
+    SHARED_FIELD(SLAVE_EN, 1, 1)
+    SHARED_FIELD(MASTER_EN, 0, 1)
+REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */
+REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */
+REG32(I2CD_INTR_CTRL, 0x0C)  /* I2CD Interrupt Control */
+REG32(I2CD_INTR_STS, 0x10)   /* I2CD Interrupt Status */
+    SHARED_FIELD(SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
+    SHARED_FIELD(SLAVE_ADDR_RX_PENDING, 29, 1)
+    SHARED_FIELD(SLAVE_INACTIVE_TIMEOUT, 15, 1)
+    SHARED_FIELD(SDA_DL_TIMEOUT, 14, 1)
+    SHARED_FIELD(BUS_RECOVER_DONE, 13, 1)
+    SHARED_FIELD(SMBUS_ALERT, 12, 1)                    /* Bus [0-3] only */
+    FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1)         /* Removed */
+    FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1)   /* Removed */
+    FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1)          /* Removed */
+    FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1)              /* Removed */
+    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)     /* use RX_DONE */
+    SHARED_FIELD(SCL_TIMEOUT, 6, 1)
+    SHARED_FIELD(ABNORMAL, 5, 1)
+    SHARED_FIELD(NORMAL_STOP, 4, 1)
+    SHARED_FIELD(ARBIT_LOSS, 3, 1)
+    SHARED_FIELD(RX_DONE, 2, 1)
+    SHARED_FIELD(TX_NAK, 1, 1)
+    SHARED_FIELD(TX_ACK, 0, 1)
+REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
+    SHARED_FIELD(SDA_OE, 28, 1)
+    SHARED_FIELD(SDA_O, 27, 1)
+    SHARED_FIELD(SCL_OE, 26, 1)
+    SHARED_FIELD(SCL_O, 25, 1)
+    SHARED_FIELD(TX_TIMING, 23, 2)
+    SHARED_FIELD(TX_STATE, 19, 4)
+    SHARED_FIELD(SCL_LINE_STS, 18, 1)
+    SHARED_FIELD(SDA_LINE_STS, 17, 1)
+    SHARED_FIELD(BUS_BUSY_STS, 16, 1)
+    SHARED_FIELD(SDA_OE_OUT_DIR, 15, 1)
+    SHARED_FIELD(SDA_O_OUT_DIR, 14, 1)
+    SHARED_FIELD(SCL_OE_OUT_DIR, 13, 1)
+    SHARED_FIELD(SCL_O_OUT_DIR, 12, 1)
+    SHARED_FIELD(BUS_RECOVER_CMD_EN, 11, 1)
+    SHARED_FIELD(S_ALT_EN, 10, 1)
+    /* Command Bits */
+    SHARED_FIELD(RX_DMA_EN, 9, 1)
+    SHARED_FIELD(TX_DMA_EN, 8, 1)
+    SHARED_FIELD(RX_BUFF_EN, 7, 1)
+    SHARED_FIELD(TX_BUFF_EN, 6, 1)
+    SHARED_FIELD(M_STOP_CMD, 5, 1)
+    SHARED_FIELD(M_S_RX_CMD_LAST, 4, 1)
+    SHARED_FIELD(M_RX_CMD, 3, 1)
+    SHARED_FIELD(S_TX_CMD, 2, 1)
+    SHARED_FIELD(M_TX_CMD, 1, 1)
+    SHARED_FIELD(M_START_CMD, 0, 1)
+REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
+REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
+    SHARED_FIELD(RX_COUNT, 24, 5)
+    SHARED_FIELD(RX_SIZE, 16, 5)
+    SHARED_FIELD(TX_COUNT, 9, 5)
+    FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
+REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
+    SHARED_FIELD(RX_BUF, 8, 8)
+    SHARED_FIELD(TX_BUF, 0, 8)
+REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */
+REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
+
+/* I2C New Mode Device (Bus) Register */
+REG32(I2CC_FUN_CTRL, 0x0)
+    FIELD(I2CC_FUN_CTRL, RB_EARLY_DONE_EN, 22, 1)
+    FIELD(I2CC_FUN_CTRL, DMA_DIS_AUTO_RECOVER, 21, 1)
+    FIELD(I2CC_FUN_CTRL, S_SAVE_ADDR, 20, 1)
+    FIELD(I2CC_FUN_CTRL, M_PKT_RETRY_CNT, 18, 2)
+    /* 17:0 shared with I2CD_FUN_CTRL[17:0] */
+REG32(I2CC_AC_TIMING, 0x04)
+REG32(I2CC_MS_TXRX_BYTE_BUF, 0x08)
+    /* 31:16 shared with I2CD_CMD[31:16] */
+    /* 15:0  shared with I2CD_BYTE_BUF[15:0] */
+REG32(I2CC_POOL_CTRL, 0x0c)
+    /* 31:0 shared with I2CD_POOL_CTRL[31:0] */
+REG32(I2CM_INTR_CTRL, 0x10)
+REG32(I2CM_INTR_STS, 0x14)
+    FIELD(I2CM_INTR_STS, PKT_STATE, 28, 4)
+    FIELD(I2CM_INTR_STS, PKT_CMD_TIMEOUT, 18, 1)
+    FIELD(I2CM_INTR_STS, PKT_CMD_FAIL, 17, 1)
+    FIELD(I2CM_INTR_STS, PKT_CMD_DONE, 16, 1)
+    FIELD(I2CM_INTR_STS, BUS_RECOVER_FAIL, 15, 1)
+    /* 14:0 shared with I2CD_INTR_STS[14:0] */
+REG32(I2CM_CMD, 0x18)
+    FIELD(I2CM_CMD, W1_CTRL, 31, 1)
+    FIELD(I2CM_CMD, PKT_DEV_ADDR, 24, 7)
+    FIELD(I2CM_CMD, HS_MASTER_MODE_LSB, 17, 3)
+    FIELD(I2CM_CMD, PKT_OP_EN, 16, 1)
+    /* 15:0 shared with I2CD_CMD[15:0] */
+REG32(I2CM_DMA_LEN, 0x1c)
+    FIELD(I2CM_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
+    FIELD(I2CM_DMA_LEN, RX_BUF_LEN, 16, 11)
+    FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
+    FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
+REG32(I2CS_INTR_CTRL, 0x20)
+REG32(I2CS_INTR_STS, 0x24)
+    /* 31:29 shared with I2CD_INTR_STS[31:29] */
+    FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR3_NAK, 22, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR2_NAK, 21, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR1_NAK, 20, 1)
+    FIELD(I2CS_INTR_STS, SLAVE_ADDR_INDICATOR, 18, 2)
+    FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
+    FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
+    /* 14:0 shared with I2CD_INTR_STS[14:0] */
+REG32(I2CS_CMD, 0x28)
+    FIELD(I2CS_CMD, W1_CTRL, 31, 1)
+    FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
+    FIELD(I2CS_CMD, PKT_MODE_EN, 16, 1)
+    FIELD(I2CS_CMD, AUTO_NAK_INACTIVE_ADDR, 15, 1)
+    FIELD(I2CS_CMD, AUTO_NAK_ACTIVE_ADDR, 14, 1)
+    /* 13:0 shared with I2CD_CMD[13:0] */
+REG32(I2CS_DMA_LEN, 0x2c)
+    FIELD(I2CS_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
+    FIELD(I2CS_DMA_LEN, RX_BUF_LEN, 16, 11)
+    FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
+    FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11)
+REG32(I2CM_DMA_TX_ADDR, 0x30)
+    FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31)
+REG32(I2CM_DMA_RX_ADDR, 0x34)
+    FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DMA_TX_ADDR, 0x38)
+    FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DMA_RX_ADDR, 0x3c)
+    FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31)
+REG32(I2CS_DEV_ADDR, 0x40)
+REG32(I2CM_DMA_LEN_STS, 0x48)
+    FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13)
+    FIELD(I2CM_DMA_LEN_STS, TX_LEN, 0, 13)
+REG32(I2CS_DMA_LEN_STS, 0x4c)
+    FIELD(I2CS_DMA_LEN_STS, RX_LEN, 16, 13)
+    FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13)
+REG32(I2CC_DMA_ADDR, 0x50)
+REG32(I2CC_DMA_LEN, 0x54)
+
 struct AspeedI2CState;
 
 #define TYPE_ASPEED_I2C_BUS "aspeed.i2c.bus"
@@ -90,6 +267,96 @@ struct AspeedI2CClass {
 
 };
 
+static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
+{
+    return FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, REG_MODE);
+}
+
+static inline bool aspeed_i2c_bus_pkt_mode_en(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_OP_EN);
+    }
+    return false;
+}
+
+static inline uint32_t aspeed_i2c_bus_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_FUN_CTRL;
+    }
+    return R_I2CD_FUN_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_CMD;
+    }
+    return R_I2CD_CMD;
+}
+
+static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_INTR_CTRL;
+    }
+    return R_I2CD_INTR_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_intr_sts_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CM_INTR_STS;
+    }
+    return R_I2CD_INTR_STS;
+}
+
+static inline uint32_t aspeed_i2c_bus_pool_ctrl_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_POOL_CTRL;
+    }
+    return R_I2CD_POOL_CTRL;
+}
+
+static inline uint32_t aspeed_i2c_bus_byte_buf_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_MS_TXRX_BYTE_BUF;
+    }
+    return R_I2CD_BYTE_BUF;
+}
+
+static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CC_DMA_LEN;
+    }
+    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),
+                                   MASTER_EN);
+}
+
+static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
+{
+    uint32_t ctrl_reg = aspeed_i2c_bus_ctrl_offset(bus);
+    return SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, MASTER_EN) ||
+           SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, SLAVE_EN);
+}
+
 I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr);
 
 #endif /* ASPEED_I2C_H */
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index f179f78ee9d0..8425e928890a 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -31,272 +31,6 @@
 #include "hw/registerfields.h"
 #include "trace.h"
 
-/* Tx State Machine */
-#define   I2CD_TX_STATE_MASK                  0xf
-#define     I2CD_IDLE                         0x0
-#define     I2CD_MACTIVE                      0x8
-#define     I2CD_MSTART                       0x9
-#define     I2CD_MSTARTR                      0xa
-#define     I2CD_MSTOP                        0xb
-#define     I2CD_MTXD                         0xc
-#define     I2CD_MRXACK                       0xd
-#define     I2CD_MRXD                         0xe
-#define     I2CD_MTXACK                       0xf
-#define     I2CD_SWAIT                        0x1
-#define     I2CD_SRXD                         0x4
-#define     I2CD_STXACK                       0x5
-#define     I2CD_STXD                         0x6
-#define     I2CD_SRXACK                       0x7
-#define     I2CD_RECOVER                      0x3
-
-/* I2C Global Register */
-REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */
-REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */
-REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */
-    FIELD(I2C_CTRL_GLOBAL, REG_MODE, 2, 1)
-    FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1)
-REG32(I2C_CTRL_NEW_CLK_DIVIDER, 0x10) /* New mode clock divider */
-
-/* I2C Old Mode Device (Bus) Register */
-REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control  */
-    FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */
-    SHARED_FIELD(M_SDA_LOCK_EN, 16, 1)
-    SHARED_FIELD(MULTI_MASTER_DIS, 15, 1)
-    SHARED_FIELD(M_SCL_DRIVE_EN, 14, 1)
-    SHARED_FIELD(MSB_STS, 9, 1)
-    SHARED_FIELD(SDA_DRIVE_IT_EN, 8, 1)
-    SHARED_FIELD(M_SDA_DRIVE_IT_EN, 7, 1)
-    SHARED_FIELD(M_HIGH_SPEED_EN, 6, 1)
-    SHARED_FIELD(DEF_ADDR_EN, 5, 1)
-    SHARED_FIELD(DEF_ALERT_EN, 4, 1)
-    SHARED_FIELD(DEF_ARP_EN, 3, 1)
-    SHARED_FIELD(DEF_GCALL_EN, 2, 1)
-    SHARED_FIELD(SLAVE_EN, 1, 1)
-    SHARED_FIELD(MASTER_EN, 0, 1)
-REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */
-REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */
-REG32(I2CD_INTR_CTRL, 0x0C)  /* I2CD Interrupt Control */
-REG32(I2CD_INTR_STS, 0x10)   /* I2CD Interrupt Status */
-    SHARED_FIELD(SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
-    SHARED_FIELD(SLAVE_ADDR_RX_PENDING, 29, 1)
-    SHARED_FIELD(SLAVE_INACTIVE_TIMEOUT, 15, 1)
-    SHARED_FIELD(SDA_DL_TIMEOUT, 14, 1)
-    SHARED_FIELD(BUS_RECOVER_DONE, 13, 1)
-    SHARED_FIELD(SMBUS_ALERT, 12, 1)                    /* Bus [0-3] only */
-    FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1)         /* Removed */
-    FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1)   /* Removed */
-    FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1)          /* Removed */
-    FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1)              /* Removed */
-    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)     /* use RX_DONE */
-    SHARED_FIELD(SCL_TIMEOUT, 6, 1)
-    SHARED_FIELD(ABNORMAL, 5, 1)
-    SHARED_FIELD(NORMAL_STOP, 4, 1)
-    SHARED_FIELD(ARBIT_LOSS, 3, 1)
-    SHARED_FIELD(RX_DONE, 2, 1)
-    SHARED_FIELD(TX_NAK, 1, 1)
-    SHARED_FIELD(TX_ACK, 0, 1)
-REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
-    SHARED_FIELD(SDA_OE, 28, 1)
-    SHARED_FIELD(SDA_O, 27, 1)
-    SHARED_FIELD(SCL_OE, 26, 1)
-    SHARED_FIELD(SCL_O, 25, 1)
-    SHARED_FIELD(TX_TIMING, 23, 2)
-    SHARED_FIELD(TX_STATE, 19, 4)
-    SHARED_FIELD(SCL_LINE_STS, 18, 1)
-    SHARED_FIELD(SDA_LINE_STS, 17, 1)
-    SHARED_FIELD(BUS_BUSY_STS, 16, 1)
-    SHARED_FIELD(SDA_OE_OUT_DIR, 15, 1)
-    SHARED_FIELD(SDA_O_OUT_DIR, 14, 1)
-    SHARED_FIELD(SCL_OE_OUT_DIR, 13, 1)
-    SHARED_FIELD(SCL_O_OUT_DIR, 12, 1)
-    SHARED_FIELD(BUS_RECOVER_CMD_EN, 11, 1)
-    SHARED_FIELD(S_ALT_EN, 10, 1)
-    /* Command Bits */
-    SHARED_FIELD(RX_DMA_EN, 9, 1)
-    SHARED_FIELD(TX_DMA_EN, 8, 1)
-    SHARED_FIELD(RX_BUFF_EN, 7, 1)
-    SHARED_FIELD(TX_BUFF_EN, 6, 1)
-    SHARED_FIELD(M_STOP_CMD, 5, 1)
-    SHARED_FIELD(M_S_RX_CMD_LAST, 4, 1)
-    SHARED_FIELD(M_RX_CMD, 3, 1)
-    SHARED_FIELD(S_TX_CMD, 2, 1)
-    SHARED_FIELD(M_TX_CMD, 1, 1)
-    SHARED_FIELD(M_START_CMD, 0, 1)
-REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
-REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
-    SHARED_FIELD(RX_COUNT, 24, 5)
-    SHARED_FIELD(RX_SIZE, 16, 5)
-    SHARED_FIELD(TX_COUNT, 9, 5)
-    FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
-REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
-    SHARED_FIELD(RX_BUF, 8, 8)
-    SHARED_FIELD(TX_BUF, 0, 8)
-REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */
-REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
-
-/* I2C New Mode Device (Bus) Register */
-REG32(I2CC_FUN_CTRL, 0x0)
-    FIELD(I2CC_FUN_CTRL, RB_EARLY_DONE_EN, 22, 1)
-    FIELD(I2CC_FUN_CTRL, DMA_DIS_AUTO_RECOVER, 21, 1)
-    FIELD(I2CC_FUN_CTRL, S_SAVE_ADDR, 20, 1)
-    FIELD(I2CC_FUN_CTRL, M_PKT_RETRY_CNT, 18, 2)
-    /* 17:0 shared with I2CD_FUN_CTRL[17:0] */
-REG32(I2CC_AC_TIMING, 0x04)
-REG32(I2CC_MS_TXRX_BYTE_BUF, 0x08)
-    /* 31:16 shared with I2CD_CMD[31:16] */
-    /* 15:0  shared with I2CD_BYTE_BUF[15:0] */
-REG32(I2CC_POOL_CTRL, 0x0c)
-    /* 31:0 shared with I2CD_POOL_CTRL[31:0] */
-REG32(I2CM_INTR_CTRL, 0x10)
-REG32(I2CM_INTR_STS, 0x14)
-    FIELD(I2CM_INTR_STS, PKT_STATE, 28, 4)
-    FIELD(I2CM_INTR_STS, PKT_CMD_TIMEOUT, 18, 1)
-    FIELD(I2CM_INTR_STS, PKT_CMD_FAIL, 17, 1)
-    FIELD(I2CM_INTR_STS, PKT_CMD_DONE, 16, 1)
-    FIELD(I2CM_INTR_STS, BUS_RECOVER_FAIL, 15, 1)
-    /* 14:0 shared with I2CD_INTR_STS[14:0] */
-REG32(I2CM_CMD, 0x18)
-    FIELD(I2CM_CMD, W1_CTRL, 31, 1)
-    FIELD(I2CM_CMD, PKT_DEV_ADDR, 24, 7)
-    FIELD(I2CM_CMD, HS_MASTER_MODE_LSB, 17, 3)
-    FIELD(I2CM_CMD, PKT_OP_EN, 16, 1)
-    /* 15:0 shared with I2CD_CMD[15:0] */
-REG32(I2CM_DMA_LEN, 0x1c)
-    FIELD(I2CM_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
-    FIELD(I2CM_DMA_LEN, RX_BUF_LEN, 16, 11)
-    FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
-    FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11)
-REG32(I2CS_INTR_CTRL, 0x20)
-REG32(I2CS_INTR_STS, 0x24)
-    /* 31:29 shared with I2CD_INTR_STS[31:29] */
-    FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2)
-    FIELD(I2CS_INTR_STS, SLAVE_ADDR3_NAK, 22, 1)
-    FIELD(I2CS_INTR_STS, SLAVE_ADDR2_NAK, 21, 1)
-    FIELD(I2CS_INTR_STS, SLAVE_ADDR1_NAK, 20, 1)
-    FIELD(I2CS_INTR_STS, SLAVE_ADDR_INDICATOR, 18, 2)
-    FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1)
-    FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1)
-    /* 14:0 shared with I2CD_INTR_STS[14:0] */
-REG32(I2CS_CMD, 0x28)
-    FIELD(I2CS_CMD, W1_CTRL, 31, 1)
-    FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2)
-    FIELD(I2CS_CMD, PKT_MODE_EN, 16, 1)
-    FIELD(I2CS_CMD, AUTO_NAK_INACTIVE_ADDR, 15, 1)
-    FIELD(I2CS_CMD, AUTO_NAK_ACTIVE_ADDR, 14, 1)
-    /* 13:0 shared with I2CD_CMD[13:0] */
-REG32(I2CS_DMA_LEN, 0x2c)
-    FIELD(I2CS_DMA_LEN, RX_BUF_LEN_W1T, 31, 1)
-    FIELD(I2CS_DMA_LEN, RX_BUF_LEN, 16, 11)
-    FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1)
-    FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11)
-REG32(I2CM_DMA_TX_ADDR, 0x30)
-    FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31)
-REG32(I2CM_DMA_RX_ADDR, 0x34)
-    FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31)
-REG32(I2CS_DMA_TX_ADDR, 0x38)
-    FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31)
-REG32(I2CS_DMA_RX_ADDR, 0x3c)
-    FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31)
-REG32(I2CS_DEV_ADDR, 0x40)
-REG32(I2CM_DMA_LEN_STS, 0x48)
-    FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13)
-    FIELD(I2CM_DMA_LEN_STS, TX_LEN, 0, 13)
-REG32(I2CS_DMA_LEN_STS, 0x4c)
-    FIELD(I2CS_DMA_LEN_STS, RX_LEN, 16, 13)
-    FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13)
-REG32(I2CC_DMA_ADDR, 0x50)
-REG32(I2CC_DMA_LEN, 0x54)
-
-static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
-{
-    return FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, REG_MODE);
-}
-
-static inline bool aspeed_i2c_bus_pkt_mode_en(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_OP_EN);
-    }
-    return false;
-}
-
-static inline uint32_t aspeed_i2c_bus_ctrl_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CC_FUN_CTRL;
-    }
-    return R_I2CD_FUN_CTRL;
-}
-
-static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CM_CMD;
-    }
-    return R_I2CD_CMD;
-}
-
-static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CM_INTR_CTRL;
-    }
-    return R_I2CD_INTR_CTRL;
-}
-
-static inline uint32_t aspeed_i2c_bus_intr_sts_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CM_INTR_STS;
-    }
-    return R_I2CD_INTR_STS;
-}
-
-static inline uint32_t aspeed_i2c_bus_pool_ctrl_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CC_POOL_CTRL;
-    }
-    return R_I2CD_POOL_CTRL;
-}
-
-static inline uint32_t aspeed_i2c_bus_byte_buf_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CC_MS_TXRX_BYTE_BUF;
-    }
-    return R_I2CD_BYTE_BUF;
-}
-
-static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus)
-{
-    if (aspeed_i2c_is_new_mode(bus->controller)) {
-        return R_I2CC_DMA_LEN;
-    }
-    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),
-                                   MASTER_EN);
-}
-
-static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
-{
-    uint32_t ctrl_reg = aspeed_i2c_bus_ctrl_offset(bus);
-    return SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, MASTER_EN) ||
-           SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, SLAVE_EN);
-}
-
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 08/21] test/avocado/machine_aspeed.py: Move OpenBMC tests
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (6 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 07/21] aspeed: i2c: Move regs and helpers to header file Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 09/21] test/avocado/machine_aspeed.py: Add tests using buildroot images Cédric Le Goater
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

It's easier to run. Keep test_arm_ast2600_debian() under the
boot_linux_console.py file because it requires the extract_from_deb()
helper. We could remove it when we have tests for the AST2600.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/avocado/boot_linux_console.py | 43 -------------------------
 tests/avocado/machine_aspeed.py     | 50 +++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
index 45a2ceda2227..6b1533c17c8b 100644
--- a/tests/avocado/boot_linux_console.py
+++ b/tests/avocado/boot_linux_console.py
@@ -1043,49 +1043,6 @@ def test_arm_vexpressa9(self):
         self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb')
         self.do_test_advcal_2018('16', tar_hash, 'winter.zImage')
 
-    def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
-        """
-        :avocado: tags=arch:arm
-        :avocado: tags=machine:palmetto-bmc
-        """
-
-        image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
-                     'obmc-phosphor-image-palmetto.static.mtd')
-        image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
-        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
-                                      algorithm='sha256')
-
-        self.do_test_arm_aspeed(image_path)
-
-    def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
-        """
-        :avocado: tags=arch:arm
-        :avocado: tags=machine:romulus-bmc
-        """
-
-        image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
-                     'obmc-phosphor-image-romulus.static.mtd')
-        image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
-        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
-                                      algorithm='sha256')
-
-        self.do_test_arm_aspeed(image_path)
-
-    def do_test_arm_aspeed(self, image):
-        self.vm.set_console()
-        self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
-                         '-net', 'nic')
-        self.vm.launch()
-
-        self.wait_for_console_pattern("U-Boot 2016.07")
-        self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
-        self.wait_for_console_pattern("Starting kernel ...")
-        self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
-        self.wait_for_console_pattern(
-                "aspeed-smc 1e620000.spi: read control register: 203b0641")
-        self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
-        self.wait_for_console_pattern("systemd[1]: Set hostname to")
-
     def test_arm_ast2600_debian(self):
         """
         :avocado: tags=arch:arm
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 33090af19940..89bfad307661 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -34,3 +34,53 @@ def test_ast1030_zephyros(self):
         wait_for_console_pattern(self, "Booting Zephyr OS")
         exec_command_and_wait_for_pattern(self, "help",
                                           "Available commands")
+
+class AST2x00Machine(QemuSystemTest):
+
+    def wait_for_console_pattern(self, success_message, vm=None):
+        wait_for_console_pattern(self, success_message,
+                                 failure_message='Kernel panic - not syncing',
+                                 vm=vm)
+
+    def do_test_arm_aspeed(self, image):
+        self.vm.set_console()
+        self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+                         '-net', 'nic')
+        self.vm.launch()
+
+        self.wait_for_console_pattern("U-Boot 2016.07")
+        self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
+        self.wait_for_console_pattern("Starting kernel ...")
+        self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
+        wait_for_console_pattern(self,
+                "aspeed-smc 1e620000.spi: read control register: 203b0641")
+        self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
+        self.wait_for_console_pattern("systemd[1]: Set hostname to")
+
+    def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
+        """
+        :avocado: tags=arch:arm
+        :avocado: tags=machine:palmetto-bmc
+        """
+
+        image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+                     'obmc-phosphor-image-palmetto.static.mtd')
+        image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
+        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+                                      algorithm='sha256')
+
+        self.do_test_arm_aspeed(image_path)
+
+    def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
+        """
+        :avocado: tags=arch:arm
+        :avocado: tags=machine:romulus-bmc
+        """
+
+        image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+                     'obmc-phosphor-image-romulus.static.mtd')
+        image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
+        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+                                      algorithm='sha256')
+
+        self.do_test_arm_aspeed(image_path)
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 09/21] test/avocado/machine_aspeed.py: Add tests using buildroot images
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (7 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 08/21] test/avocado/machine_aspeed.py: Move OpenBMC tests Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 10/21] test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb Cédric Le Goater
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Buildroot images are smaller than the OpenBMC images and faster to
run. Built from source using :

  http://patchwork.ozlabs.org/project/buildroot/list/?series=303465

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/avocado/machine_aspeed.py | 52 +++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 89bfad307661..5374e7fad17a 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -5,8 +5,11 @@
 # This work is licensed under the terms of the GNU GPL, version 2 or
 # later.  See the COPYING file in the top-level directory.
 
+import time
+
 from avocado_qemu import QemuSystemTest
 from avocado_qemu import wait_for_console_pattern
+from avocado_qemu import exec_command
 from avocado_qemu import exec_command_and_wait_for_pattern
 from avocado.utils import archive
 
@@ -84,3 +87,52 @@ def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
                                       algorithm='sha256')
 
         self.do_test_arm_aspeed(image_path)
+
+    def do_test_arm_aspeed_buidroot_start(self, image, cpu_id):
+        self.vm.set_console()
+        self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+                         '-net', 'nic', '-net', 'user')
+        self.vm.launch()
+
+        self.wait_for_console_pattern('U-Boot 2019.04')
+        self.wait_for_console_pattern('## Loading kernel from FIT Image')
+        self.wait_for_console_pattern('Starting kernel ...')
+        self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
+        self.wait_for_console_pattern('lease of 10.0.2.15')
+        self.wait_for_console_pattern('Aspeed EVB')
+        exec_command(self, 'root')
+        time.sleep(0.1)
+
+    def do_test_arm_aspeed_buidroot_poweroff(self):
+        exec_command_and_wait_for_pattern(self, 'poweroff',
+                                          'reboot: System halted');
+
+    def test_arm_ast2500_evb_builroot(self):
+        """
+        :avocado: tags=arch:arm
+        :avocado: tags=machine:ast2500-evb
+        """
+
+        image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+                     'images/ast2500-evb/buildroot-2022.05-rc2/flash.img')
+        image_hash = ('ca1e507f493d7241d501764e315a2ba1087b9ce7e5732e84bfb6b901ed98ebdb')
+        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+                                      algorithm='sha256')
+
+        self.do_test_arm_aspeed_buidroot_start(image_path, '0x0')
+        self.do_test_arm_aspeed_buidroot_poweroff()
+
+    def test_arm_ast2600_evb_builroot(self):
+        """
+        :avocado: tags=arch:arm
+        :avocado: tags=machine:ast2600-evb
+        """
+
+        image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+                     'images/ast2600-evb/buildroot-2022.05-rc2/flash.img')
+        image_hash = ('122639a468a127d011e6f280cf4e6fbd9ee1e8d27d21e9f115912d1c344cc671')
+        image_path = self.fetch_asset(image_url, asset_hash=image_hash,
+                                      algorithm='sha256')
+
+        self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
+        self.do_test_arm_aspeed_buidroot_poweroff()
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 10/21] test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (8 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 09/21] test/avocado/machine_aspeed.py: Add tests using buildroot images Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test Cédric Le Goater
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Add a temperature tmp423 sensor device on bus 15 and check that the
device and manufacturer id registers contain the expected values.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/avocado/machine_aspeed.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 5374e7fad17a..a3b4b9e5093c 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -134,5 +134,12 @@ def test_arm_ast2600_evb_builroot(self):
         image_path = self.fetch_asset(image_url, asset_hash=image_hash,
                                       algorithm='sha256')
 
+        self.vm.add_args('-device',
+                         'tmp423,bus=aspeed.i2c.bus.15,address=0x4c');
         self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
+        exec_command_and_wait_for_pattern(self,
+                                          'i2cget -y 15 0x4c 0xff', '0x23');
+        exec_command_and_wait_for_pattern(self,
+                                          'i2cget -y 15 0x4c 0xfe', '0x55');
+
         self.do_test_arm_aspeed_buidroot_poweroff()
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (9 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 10/21] test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 23:16   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 12/21] aspeed/i2c: Add ast1030 controller models Cédric Le Goater
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Add a RTC device on bus 15 and check that the ouput of the hwclock
command matches the current year.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/avocado/machine_aspeed.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index a3b4b9e5093c..28b8a4c8124b 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -136,10 +136,18 @@ def test_arm_ast2600_evb_builroot(self):
 
         self.vm.add_args('-device',
                          'tmp423,bus=aspeed.i2c.bus.15,address=0x4c');
+        self.vm.add_args('-device',
+                         'ds1338,bus=aspeed.i2c.bus.15,address=0x32');
         self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
         exec_command_and_wait_for_pattern(self,
                                           'i2cget -y 15 0x4c 0xff', '0x23');
         exec_command_and_wait_for_pattern(self,
                                           'i2cget -y 15 0x4c 0xfe', '0x55');
 
+        exec_command_and_wait_for_pattern(self,
+             'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-15/device/new_device',
+             'i2c i2c-15: new_device: Instantiated device ds1307 at 0x32');
+        year = time.strftime("%Y")
+        exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
+
         self.do_test_arm_aspeed_buidroot_poweroff()
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 12/21] aspeed/i2c: Add ast1030 controller models
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (10 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 23:22   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 13/21] aspeed: Add I2C buses to AST1030 model Cédric Le Goater
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Based on :
  https://lists.nongnu.org/archive/html/qemu-devel/2022-03/msg06017.html

Cc: Troy Lee <troy_lee@aspeedtech.com>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>
Cc: Steven Lee <steven_lee@aspeedtech.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h |  1 +
 hw/i2c/aspeed_i2c.c         | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 506bcf1a9daf..79c6779c6c1e 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -30,6 +30,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
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 8425e928890a..5fce516517a5 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -1185,6 +1185,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);
@@ -1192,6 +1215,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)
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 13/21] aspeed: Add I2C buses to AST1030 model
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (11 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 12/21] aspeed/i2c: Add ast1030 controller models Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 23:18   ` Joel Stanley
  2022-06-06 15:07 ` [PATCH 14/21] hw/i2c/aspeed: rework raise interrupt trace event Cédric Le Goater
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Troy Lee <troy_lee@aspeedtech.com>

Instantiate the I2C buses in AST1030 model and create two slave device
for ast1030-evb.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Signed-off-by: Steven Lee <steven_lee@aspeedtech.com>
[ clg : - adapted to current ast1030 upstream models
        - fixed typo in commit log ]
Message-Id: <20220324100439.478317-3-troy_lee@aspeedtech.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/arm/aspeed.c         | 13 +++++++++++++
 hw/arm/aspeed_ast10x0.c | 18 ++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 98dc185acd9a..5c3802308e80 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1401,6 +1401,18 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
                        AST1030_INTERNAL_FLASH_SIZE);
 }
 
+static void ast1030_evb_i2c_init(AspeedMachineState *bmc)
+{
+    AspeedSoCState *soc = &bmc->soc;
+
+    /* U10 24C08 connects to SDA/SCL Groupt 1 by default */
+    uint8_t *eeprom_buf = g_malloc0(32 * 1024);
+    smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf);
+
+    /* U11 LM75 connects to SDA/SCL Group 2 by default */
+    i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4d);
+}
+
 static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
                                                           void *data)
 {
@@ -1412,6 +1424,7 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
     amc->hw_strap1 = 0;
     amc->hw_strap2 = 0;
     mc->init = aspeed_minibmc_machine_init;
+    amc->i2c_init = ast1030_evb_i2c_init;
     mc->default_ram_size = 0;
     mc->default_cpus = mc->min_cpus = mc->max_cpus = 1;
     amc->fmc_model = "sst25vf032b";
diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c
index d53454168403..a2ed275712fb 100644
--- a/hw/arm/aspeed_ast10x0.c
+++ b/hw/arm/aspeed_ast10x0.c
@@ -114,6 +114,9 @@ static void aspeed_soc_ast1030_init(Object *obj)
     object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1");
     object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2");
 
+    snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+    object_initialize_child(obj, "i2c", &s->i2c, typename);
+
     snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
     object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
 
@@ -188,6 +191,21 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
 
+    /* I2C */
+
+    object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(&s->sram),
+                             &error_abort);
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+    for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+        qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m),
+                                        sc->irqmap[ASPEED_DEV_I2C] + i);
+        /* The AST2600 I2C controller has one IRQ per bus. */
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+    }
+
     /* LPC */
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
         return;
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 14/21] hw/i2c/aspeed: rework raise interrupt trace event
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (12 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 13/21] aspeed: Add I2C buses to AST1030 model Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 15/21] hw/i2c/aspeed: add DEV_ADDR in old register mode Cédric Le Goater
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Klaus Jensen <k.jensen@samsung.com>

Build a single string instead of having several parameters on the trace
event.

Suggested-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[ clg: simplified trace buffer creation ]
Message-Id: <20220601210831.67259-2-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/i2c/aspeed_i2c.c | 34 ++++++++++++++++++++++------------
 hw/i2c/trace-events |  2 +-
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 5fce516517a5..b70276a87360 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -21,6 +21,7 @@
 #include "qemu/osdep.h"
 #include "hw/sysbus.h"
 #include "migration/vmstate.h"
+#include "qemu/cutils.h"
 #include "qemu/log.h"
 #include "qemu/module.h"
 #include "qemu/error-report.h"
@@ -38,23 +39,32 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
     uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus);
     bool raise_irq;
 
-    trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts],
-        aspeed_i2c_bus_pkt_mode_en(bus) &&
-        ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ?
-                                                               "pktdone|" : "",
-        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? "nak|" : "",
-        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? "ack|" : "",
-        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? "done|"
-                                                                  : "",
-        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ?
-                                                                "normal|" : "",
-        SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? "abnormal"
-                                                                   : "");
+    if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) {
+        g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s",
+               aspeed_i2c_bus_pkt_mode_en(bus) &&
+               ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ?
+                                               "pktdone|" : "",
+               SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ?
+                                               "nak|" : "",
+               SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ?
+                                               "ack|" : "",
+               SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ?
+                                               "done|" : "",
+               SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ?
+                                               "normal|" : "",
+               SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ?
+                                               "abnormal"  : "");
+
+           trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf);
+    }
+
     raise_irq = bus->regs[reg_intr_sts] & bus->regs[intr_ctrl_reg];
+
     /* In packet mode we don't mask off INTR_STS */
     if (!aspeed_i2c_bus_pkt_mode_en(bus)) {
         bus->regs[reg_intr_sts] &= bus->regs[intr_ctrl_reg];
     }
+
     if (raise_irq) {
         bus->controller->intr_status |= 1 << bus->id;
         qemu_irq_raise(aic->bus_get_irq(bus));
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 85e4bddff936..209275ed2dc8 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -9,7 +9,7 @@ i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
 # aspeed_i2c.c
 
 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, const char *str6) "handled intr=0x%x %s%s%s%s%s%s"
+aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *s) "handled intr=0x%x %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_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 15/21] hw/i2c/aspeed: add DEV_ADDR in old register mode
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (13 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 14/21] hw/i2c/aspeed: rework raise interrupt trace event Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 16/21] hw/i2c: support multiple masters Cédric Le Goater
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Klaus Jensen <k.jensen@samsung.com>

Add support for writing and reading the device address register in old
register mode.

On the AST2400 (only 1 slave address)

  * no upper bits

On the AST2500 (2 possible slave addresses),

  * bit[31] : Slave Address match indicator
  * bit[30] : Slave Address Receiving pending

On the AST2600 (3 possible slave addresses),

  * bit[31-30] : Slave Address match indicator
  * bit[29] : Slave Address Receiving pending

The model could be more precise to take into account all fields but
since the Linux driver is masking the register value being set, it
should be fine. See commit 3fb2e2aeafb2 ("i2c: aspeed: disable
additional device addresses on ast2[56]xx") from Zeiv. This can be
addressed later.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[ clg: add details to commit log ]
Message-Id: <20220601210831.67259-3-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/aspeed_i2c.h | 8 ++++++++
 hw/i2c/aspeed_i2c.c         | 5 +++--
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 79c6779c6c1e..03fe829a3a57 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -297,6 +297,14 @@ static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus)
     return R_I2CD_CMD;
 }
 
+static inline uint32_t aspeed_i2c_bus_dev_addr_offset(AspeedI2CBus *bus)
+{
+    if (aspeed_i2c_is_new_mode(bus->controller)) {
+        return R_I2CS_DEV_ADDR;
+    }
+    return R_I2CD_DEV_ADDR;
+}
+
 static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus)
 {
     if (aspeed_i2c_is_new_mode(bus->controller)) {
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b70276a87360..379dbc1379cb 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -83,6 +83,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
     case A_I2CD_AC_TIMING2:
     case A_I2CD_INTR_CTRL:
     case A_I2CD_INTR_STS:
+    case A_I2CD_DEV_ADDR:
     case A_I2CD_POOL_CTRL:
     case A_I2CD_BYTE_BUF:
         /* Value is already set, don't do anything. */
@@ -720,8 +721,7 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
         }
         break;
     case A_I2CD_DEV_ADDR:
-        qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
-                      __func__);
+        bus->regs[R_I2CD_DEV_ADDR] = value;
         break;
     case A_I2CD_POOL_CTRL:
         bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff;
@@ -1039,6 +1039,7 @@ static void aspeed_i2c_bus_reset(DeviceState *dev)
 
     s->regs[R_I2CD_INTR_CTRL] = 0;
     s->regs[R_I2CD_INTR_STS] = 0;
+    s->regs[R_I2CD_DEV_ADDR] = 0;
     s->regs[R_I2CD_CMD] = 0;
     s->regs[R_I2CD_BYTE_BUF] = 0;
     s->regs[R_I2CD_DMA_ADDR] = 0;
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 16/21] hw/i2c: support multiple masters
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (14 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 15/21] hw/i2c/aspeed: add DEV_ADDR in old register mode Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 17/21] hw/i2c: add asynchronous send Cédric Le Goater
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Klaus Jensen <k.jensen@samsung.com>

Allow slaves to master the bus by registering a bottom halve. If the bus
is busy, the bottom half is queued up. When a slave has succesfully
mastered the bus, the bottom half is scheduled.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
[ clg : - fixed typos in commit log ]
Message-Id: <20220601210831.67259-4-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/i2c.h | 14 ++++++++++++++
 hw/i2c/core.c        | 34 +++++++++++++++++++++++++++++++++-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 5ca3b708c0be..be8bb8b78a60 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -69,13 +69,25 @@ struct I2CNode {
     QLIST_ENTRY(I2CNode) next;
 };
 
+typedef struct I2CPendingMaster I2CPendingMaster;
+
+struct I2CPendingMaster {
+    QEMUBH *bh;
+    QSIMPLEQ_ENTRY(I2CPendingMaster) entry;
+};
+
 typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList;
+typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters;
 
 struct I2CBus {
     BusState qbus;
     I2CNodeList current_devs;
+    I2CPendingMasters pending_masters;
     uint8_t saved_address;
     bool broadcast;
+
+    /* Set from slave currently mastering the bus. */
+    QEMUBH *bh;
 };
 
 I2CBus *i2c_init_bus(DeviceState *parent, const char *name);
@@ -117,6 +129,8 @@ int i2c_start_send(I2CBus *bus, uint8_t address);
 
 void i2c_end_transfer(I2CBus *bus);
 void i2c_nack(I2CBus *bus);
+void i2c_bus_master(I2CBus *bus, QEMUBH *bh);
+void i2c_bus_release(I2CBus *bus);
 int i2c_send(I2CBus *bus, uint8_t data);
 uint8_t i2c_recv(I2CBus *bus);
 bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index d0cb2d32fa44..145dce60782a 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -13,6 +13,7 @@
 #include "migration/vmstate.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
+#include "qemu/main-loop.h"
 #include "trace.h"
 
 #define I2C_BROADCAST 0x00
@@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
 
     bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name));
     QLIST_INIT(&bus->current_devs);
+    QSIMPLEQ_INIT(&bus->pending_masters);
     vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus);
     return bus;
 }
@@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address)
 /* Return nonzero if bus is busy.  */
 int i2c_bus_busy(I2CBus *bus)
 {
-    return !QLIST_EMPTY(&bus->current_devs);
+    return !QLIST_EMPTY(&bus->current_devs) || bus->bh;
 }
 
 bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
@@ -180,6 +182,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv)
                                                : I2C_START_SEND);
 }
 
+void i2c_bus_master(I2CBus *bus, QEMUBH *bh)
+{
+    if (i2c_bus_busy(bus)) {
+        I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1);
+        node->bh = bh;
+
+        QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry);
+
+        return;
+    }
+
+    bus->bh = bh;
+    qemu_bh_schedule(bus->bh);
+}
+
+void i2c_bus_release(I2CBus *bus)
+{
+    bus->bh = NULL;
+}
+
 int i2c_start_recv(I2CBus *bus, uint8_t address)
 {
     return i2c_do_start_transfer(bus, address, I2C_START_RECV);
@@ -206,6 +228,16 @@ void i2c_end_transfer(I2CBus *bus)
         g_free(node);
     }
     bus->broadcast = false;
+
+    if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) {
+        I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters);
+        bus->bh = node->bh;
+
+        QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry);
+        g_free(node);
+
+        qemu_bh_schedule(bus->bh);
+    }
 }
 
 int i2c_send(I2CBus *bus, uint8_t data)
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 17/21] hw/i2c: add asynchronous send
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (15 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 16/21] hw/i2c: support multiple masters Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 18/21] hw/i2c/aspeed: add slave device in old register mode Cédric Le Goater
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Klaus Jensen <k.jensen@samsung.com>

Add an asynchronous version of i2c_send() that requires the slave to
explicitly acknowledge on the bus with i2c_ack().

The current master must use the new i2c_start_send_async() to indicate
that it wants to do an asynchronous transfer. This allows the i2c core
to check if the target slave supports this or not. This approach relies
on adding a new enum i2c_event member, which is why a bunch of other
devices needs changes in their event handling switches.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Message-Id: <20220601210831.67259-5-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/i2c/i2c.h       | 16 ++++++++++++++++
 hw/arm/pxa2xx.c            |  2 ++
 hw/display/sii9022.c       |  2 ++
 hw/display/ssd0303.c       |  2 ++
 hw/i2c/core.c              | 36 +++++++++++++++++++++++++++++++++++-
 hw/i2c/smbus_slave.c       |  4 ++++
 hw/nvram/eeprom_at24c.c    |  2 ++
 hw/sensor/lsm303dlhc_mag.c |  2 ++
 hw/i2c/trace-events        |  2 ++
 9 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index be8bb8b78a60..9b9581d23097 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -12,6 +12,7 @@
 enum i2c_event {
     I2C_START_RECV,
     I2C_START_SEND,
+    I2C_START_SEND_ASYNC,
     I2C_FINISH,
     I2C_NACK /* Masker NACKed a receive byte.  */
 };
@@ -28,6 +29,9 @@ struct I2CSlaveClass {
     /* Master to slave. Returns non-zero for a NAK, 0 for success. */
     int (*send)(I2CSlave *s, uint8_t data);
 
+    /* Master to slave (asynchronous). Receiving slave must call i2c_ack(). */
+    void (*send_async)(I2CSlave *s, uint8_t data);
+
     /*
      * Slave to master.  This cannot fail, the device should always
      * return something here.
@@ -127,11 +131,23 @@ int i2c_start_recv(I2CBus *bus, uint8_t address);
  */
 int i2c_start_send(I2CBus *bus, uint8_t address);
 
+/**
+ * i2c_start_send_async: start an asynchronous 'send' transfer on an I2C bus.
+ *
+ * @bus: #I2CBus to be used
+ * @address: address of the slave
+ *
+ * Return: 0 on success, -1 on error
+ */
+int i2c_start_send_async(I2CBus *bus, uint8_t address);
+
 void i2c_end_transfer(I2CBus *bus);
 void i2c_nack(I2CBus *bus);
+void i2c_ack(I2CBus *bus);
 void i2c_bus_master(I2CBus *bus, QEMUBH *bh);
 void i2c_bus_release(I2CBus *bus);
 int i2c_send(I2CBus *bus, uint8_t data);
+int i2c_send_async(I2CBus *bus, uint8_t data);
 uint8_t i2c_recv(I2CBus *bus);
 bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
                   I2CNodeList *current_devs);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index f4f687df68ef..93dda83d7aa9 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1305,6 +1305,8 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
     case I2C_NACK:
         s->status |= 1 << 1;				/* set ACKNAK */
         break;
+    default:
+        return -1;
     }
     pxa2xx_i2c_update(s);
 
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
index b591a5878901..664fd4046d82 100644
--- a/hw/display/sii9022.c
+++ b/hw/display/sii9022.c
@@ -76,6 +76,8 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
         break;
     case I2C_NACK:
         break;
+    default:
+        return -1;
     }
 
     return 0;
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index aeae22da9c29..d67b0ad7b529 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -196,6 +196,8 @@ static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
     case I2C_NACK:
         /* Nothing to do.  */
         break;
+    default:
+        return -1;
     }
 
     return 0;
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 145dce60782a..d4ba8146bffb 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -161,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address,
            start condition.  */
 
         if (sc->event) {
-            trace_i2c_event("start", s->address);
+            trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async",
+                            s->address);
             rv = sc->event(s, event);
             if (rv && !bus->broadcast) {
                 if (bus_scanned) {
@@ -212,6 +213,11 @@ int i2c_start_send(I2CBus *bus, uint8_t address)
     return i2c_do_start_transfer(bus, address, I2C_START_SEND);
 }
 
+int i2c_start_send_async(I2CBus *bus, uint8_t address)
+{
+    return i2c_do_start_transfer(bus, address, I2C_START_SEND_ASYNC);
+}
+
 void i2c_end_transfer(I2CBus *bus)
 {
     I2CSlaveClass *sc;
@@ -261,6 +267,23 @@ int i2c_send(I2CBus *bus, uint8_t data)
     return ret ? -1 : 0;
 }
 
+int i2c_send_async(I2CBus *bus, uint8_t data)
+{
+    I2CNode *node = QLIST_FIRST(&bus->current_devs);
+    I2CSlave *slave = node->elt;
+    I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(slave);
+
+    if (!sc->send_async) {
+        return -1;
+    }
+
+    trace_i2c_send_async(slave->address, data);
+
+    sc->send_async(slave, data);
+
+    return 0;
+}
+
 uint8_t i2c_recv(I2CBus *bus)
 {
     uint8_t data = 0xff;
@@ -297,6 +320,17 @@ void i2c_nack(I2CBus *bus)
     }
 }
 
+void i2c_ack(I2CBus *bus)
+{
+    if (!bus->bh) {
+        return;
+    }
+
+    trace_i2c_ack();
+
+    qemu_bh_schedule(bus->bh);
+}
+
 static int i2c_slave_post_load(void *opaque, int version_id)
 {
     I2CSlave *dev = opaque;
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 5d10e27664db..feb3ec633350 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -143,6 +143,10 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
             dev->mode = SMBUS_CONFUSED;
             break;
         }
+        break;
+
+    default:
+        return -1;
     }
 
     return 0;
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
index 01a3093600fa..d695f6ae894a 100644
--- a/hw/nvram/eeprom_at24c.c
+++ b/hw/nvram/eeprom_at24c.c
@@ -75,6 +75,8 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
         break;
     case I2C_NACK:
         break;
+    default:
+        return -1;
     }
     return 0;
 }
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
index 4c98ddbf207c..bb8d48b2fdb0 100644
--- a/hw/sensor/lsm303dlhc_mag.c
+++ b/hw/sensor/lsm303dlhc_mag.c
@@ -427,6 +427,8 @@ static int lsm303dlhc_mag_event(I2CSlave *i2c, enum i2c_event event)
         break;
     case I2C_NACK:
         break;
+    default:
+        return -1;
     }
 
     s->len = 0;
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 209275ed2dc8..af181d43ee64 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -4,7 +4,9 @@
 
 i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
 i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
+i2c_send_async(uint8_t address, uint8_t data) "send_async(addr:0x%02x) data:0x%02x"
 i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
+i2c_ack(void) ""
 
 # aspeed_i2c.c
 
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 18/21] hw/i2c/aspeed: add slave device in old register mode
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (16 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 17/21] hw/i2c: add asynchronous send Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 19/21] aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always Cédric Le Goater
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

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>
---
 include/hw/i2c/aspeed_i2c.h |  8 ++++
 hw/i2c/aspeed_i2c.c         | 93 +++++++++++++++++++++++++++++++++----
 2 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index 03fe829a3a57..9e88f086131a 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;
@@ -251,6 +254,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;
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 379dbc1379cb..59245079002b 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -40,7 +40,7 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
     bool raise_irq;
 
     if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) {
-        g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s",
+        g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s%s",
                aspeed_i2c_bus_pkt_mode_en(bus) &&
                ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ?
                                                "pktdone|" : "",
@@ -50,6 +50,8 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
                                                "ack|" : "",
                SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ?
                                                "done|" : "",
+               ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH) ?
+                                               "slave-match|" : "",
                SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ?
                                                "normal|" : "",
                SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ?
@@ -689,9 +691,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;
@@ -712,12 +712,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:
@@ -1033,6 +1036,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);
@@ -1063,6 +1133,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);
@@ -1222,6 +1294,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);
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 19/21] aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (17 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 18/21] hw/i2c/aspeed: add slave device in old register mode Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 20/21] hw/misc: add a toy i2c echo device [DO NOT PULL] Cédric Le Goater
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

There is no 'slave match interrupt' enable bit in the Interrupt
Control Register. Consider it is always enabled and extend the mask
value 'bus->regs[intr_ctrl_reg]' with the SLAVE_ADDR_RX_MATCH bit when
the interrupt is raised.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/i2c/aspeed_i2c.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 59245079002b..f30098bebbab 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -32,11 +32,16 @@
 #include "hw/registerfields.h"
 #include "trace.h"
 
+/* Enable SLAVE_ADDR_RX_MATCH always */
+#define R_I2CD_INTR_STS_ALWAYS_ENABLE  R_I2CD_INTR_STS_SLAVE_ADDR_RX_MATCH_MASK
+
 static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
 {
     AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
     uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus);
     uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus);
+    uint32_t intr_ctrl_mask = bus->regs[intr_ctrl_reg] |
+        R_I2CD_INTR_STS_ALWAYS_ENABLE;
     bool raise_irq;
 
     if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) {
@@ -60,11 +65,11 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
            trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf);
     }
 
-    raise_irq = bus->regs[reg_intr_sts] & bus->regs[intr_ctrl_reg];
+    raise_irq = bus->regs[reg_intr_sts] & intr_ctrl_mask ;
 
     /* In packet mode we don't mask off INTR_STS */
     if (!aspeed_i2c_bus_pkt_mode_en(bus)) {
-        bus->regs[reg_intr_sts] &= bus->regs[intr_ctrl_reg];
+        bus->regs[reg_intr_sts] &= intr_ctrl_mask;
     }
 
     if (raise_irq) {
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 20/21] hw/misc: add a toy i2c echo device [DO NOT PULL]
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (18 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 19/21] aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-06 15:07 ` [PATCH 21/21] test/avocado/machine_aspeed.py: Add I2C slave tests Cédric Le Goater
  2022-06-19 14:50 ` [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

From: Klaus Jensen <k.jensen@samsung.com>

Add an example I2C device to demonstrate how a slave may master the bus
and send data asynchronously to another slave.

The device will echo whatever it is sent to the device identified by the
first byte received.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Message-Id: <20220601210831.67259-7-its@irrelevant.dk>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/misc/i2c-echo.c  | 162 ++++++++++++++++++++++++++++++++++++++++++++
 hw/misc/meson.build |   2 +
 2 files changed, 164 insertions(+)
 create mode 100644 hw/misc/i2c-echo.c

diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c
new file mode 100644
index 000000000000..27992eff8c5b
--- /dev/null
+++ b/hw/misc/i2c-echo.c
@@ -0,0 +1,162 @@
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/main-loop.h"
+#include "block/aio.h"
+#include "hw/i2c/i2c.h"
+
+#define TYPE_I2C_ECHO "i2c-echo"
+OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
+
+enum i2c_echo_state {
+    I2C_ECHO_STATE_IDLE,
+    I2C_ECHO_STATE_REQUEST_MASTER,
+    I2C_ECHO_STATE_START_SEND,
+    I2C_ECHO_STATE_ACK,
+};
+
+typedef struct I2CEchoState {
+    I2CSlave parent_obj;
+
+    I2CBus *bus;
+
+    enum i2c_echo_state state;
+    QEMUBH *bh;
+
+    unsigned int pos;
+    uint8_t data[3];
+} I2CEchoState;
+
+static void i2c_echo_bh(void *opaque)
+{
+    I2CEchoState *state = opaque;
+
+    switch (state->state) {
+    case I2C_ECHO_STATE_IDLE:
+        return;
+
+    case I2C_ECHO_STATE_REQUEST_MASTER:
+        i2c_bus_master(state->bus, state->bh);
+        state->state = I2C_ECHO_STATE_START_SEND;
+        return;
+
+    case I2C_ECHO_STATE_START_SEND:
+        if (i2c_start_send_async(state->bus, state->data[0])) {
+            goto release_bus;
+        }
+
+        state->pos++;
+        state->state = I2C_ECHO_STATE_ACK;
+        return;
+
+    case I2C_ECHO_STATE_ACK:
+        if (state->pos > 2) {
+            break;
+        }
+
+        if (i2c_send_async(state->bus, state->data[state->pos++])) {
+            break;
+        }
+
+        return;
+    }
+
+
+    i2c_end_transfer(state->bus);
+release_bus:
+    i2c_bus_release(state->bus);
+
+    state->state = I2C_ECHO_STATE_IDLE;
+}
+
+static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    switch (event) {
+    case I2C_START_RECV:
+        state->pos = 0;
+
+        break;
+
+    case I2C_START_SEND:
+        state->pos = 0;
+
+        break;
+
+    case I2C_FINISH:
+        state->pos = 0;
+        state->state = I2C_ECHO_STATE_REQUEST_MASTER;
+        qemu_bh_schedule(state->bh);
+
+        break;
+
+    case I2C_NACK:
+        break;
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+static uint8_t i2c_echo_recv(I2CSlave *s)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    if (state->pos > 2) {
+        return 0xff;
+    }
+
+    return state->data[state->pos++];
+}
+
+static int i2c_echo_send(I2CSlave *s, uint8_t data)
+{
+    I2CEchoState *state = I2C_ECHO(s);
+
+    if (state->pos > 2) {
+        return -1;
+    }
+
+    state->data[state->pos++] = data;
+
+    return 0;
+}
+
+static void i2c_echo_realize(DeviceState *dev, Error **errp)
+{
+    I2CEchoState *state = I2C_ECHO(dev);
+    BusState *bus = qdev_get_parent_bus(dev);
+
+    state->bus = I2C_BUS(bus);
+    state->bh = qemu_bh_new(i2c_echo_bh, state);
+
+    return;
+}
+
+static void i2c_echo_class_init(ObjectClass *oc, void *data)
+{
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = i2c_echo_realize;
+
+    sc->event = i2c_echo_event;
+    sc->recv = i2c_echo_recv;
+    sc->send = i2c_echo_send;
+}
+
+static const TypeInfo i2c_echo = {
+    .name = TYPE_I2C_ECHO,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(I2CEchoState),
+    .class_init = i2c_echo_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&i2c_echo);
+}
+
+type_init(register_types);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 132b7b7344bb..8c366f94da42 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -123,6 +123,8 @@ softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
 
 softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c'))
 
+softmmu_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c'))
+
 specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c'))
 
 specific_ss.add(when: 'CONFIG_IMX', if_true: files('imx6_src.c'))
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 21/21] test/avocado/machine_aspeed.py: Add I2C slave tests
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (19 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 20/21] hw/misc: add a toy i2c echo device [DO NOT PULL] Cédric Le Goater
@ 2022-06-06 15:07 ` Cédric Le Goater
  2022-06-19 14:50 ` [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-06 15:07 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal, Cédric Le Goater

Test extracted from :

  https://lists.nongnu.org/archive/html/qemu-devel/2022-06/msg00183.html

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/avocado/machine_aspeed.py | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 28b8a4c8124b..89447dbebcb9 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -138,6 +138,8 @@ def test_arm_ast2600_evb_builroot(self):
                          'tmp423,bus=aspeed.i2c.bus.15,address=0x4c');
         self.vm.add_args('-device',
                          'ds1338,bus=aspeed.i2c.bus.15,address=0x32');
+        self.vm.add_args('-device',
+                         'i2c-echo,bus=aspeed.i2c.bus.15,address=0x42');
         self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
         exec_command_and_wait_for_pattern(self,
                                           'i2cget -y 15 0x4c 0xff', '0x23');
@@ -150,4 +152,13 @@ def test_arm_ast2600_evb_builroot(self):
         year = time.strftime("%Y")
         exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
 
+        exec_command_and_wait_for_pattern(self,
+             'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-15/new_device',
+             'i2c i2c-15: new_device: Instantiated device slave-24c02 at 0x64');
+        exec_command(self, 'i2cset -y 15 0x42 0x64 0x00 0xaa i');
+        time.sleep(0.1)
+        exec_command_and_wait_for_pattern(self,
+             'hexdump /sys/bus/i2c/devices/15-1064/slave-eeprom',
+             '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
+
         self.do_test_arm_aspeed_buidroot_poweroff()
-- 
2.35.3



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test
  2022-06-06 15:07 ` [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test Cédric Le Goater
@ 2022-06-06 23:16   ` Joel Stanley
  2022-06-07 10:17     ` Cédric Le Goater
  0 siblings, 1 reply; 34+ messages in thread
From: Joel Stanley @ 2022-06-06 23:16 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>
> Add a RTC device on bus 15 and check that the ouput of the hwclock

spelling: output

> command matches the current year.
>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  tests/avocado/machine_aspeed.py | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
> index a3b4b9e5093c..28b8a4c8124b 100644
> --- a/tests/avocado/machine_aspeed.py
> +++ b/tests/avocado/machine_aspeed.py
> @@ -136,10 +136,18 @@ def test_arm_ast2600_evb_builroot(self):
>
>          self.vm.add_args('-device',
>                           'tmp423,bus=aspeed.i2c.bus.15,address=0x4c');
> +        self.vm.add_args('-device',
> +                         'ds1338,bus=aspeed.i2c.bus.15,address=0x32');

Is there any value running this on the 2400 and 2500 machine types
too? They all use the same model so perhaps not?

>          self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
>          exec_command_and_wait_for_pattern(self,
>                                            'i2cget -y 15 0x4c 0xff', '0x23');
>          exec_command_and_wait_for_pattern(self,
>                                            'i2cget -y 15 0x4c 0xfe', '0x55');
>
> +        exec_command_and_wait_for_pattern(self,
> +             'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-15/device/new_device',
> +             'i2c i2c-15: new_device: Instantiated device ds1307 at 0x32');
> +        year = time.strftime("%Y")
> +        exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
> +
>          self.do_test_arm_aspeed_buidroot_poweroff()
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 13/21] aspeed: Add I2C buses to AST1030 model
  2022-06-06 15:07 ` [PATCH 13/21] aspeed: Add I2C buses to AST1030 model Cédric Le Goater
@ 2022-06-06 23:18   ` Joel Stanley
  2022-06-07 10:43     ` Cédric Le Goater
  0 siblings, 1 reply; 34+ messages in thread
From: Joel Stanley @ 2022-06-06 23:18 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:09, Cédric Le Goater <clg@kaod.org> wrote:
>
> From: Troy Lee <troy_lee@aspeedtech.com>
>
> Instantiate the I2C buses in AST1030 model and create two slave device
> for ast1030-evb.
>
> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> Signed-off-by: Steven Lee <steven_lee@aspeedtech.com>
> [ clg : - adapted to current ast1030 upstream models
>         - fixed typo in commit log ]
> Message-Id: <20220324100439.478317-3-troy_lee@aspeedtech.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Reviewed-by: Joel Stanley <joel@jms.id.au>

one question about a comment below.

> ---
>  hw/arm/aspeed.c         | 13 +++++++++++++
>  hw/arm/aspeed_ast10x0.c | 18 ++++++++++++++++++
>  2 files changed, 31 insertions(+)
>
> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
> index 98dc185acd9a..5c3802308e80 100644
> --- a/hw/arm/aspeed.c
> +++ b/hw/arm/aspeed.c
> @@ -1401,6 +1401,18 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
>                         AST1030_INTERNAL_FLASH_SIZE);
>  }
>
> +static void ast1030_evb_i2c_init(AspeedMachineState *bmc)
> +{
> +    AspeedSoCState *soc = &bmc->soc;
> +
> +    /* U10 24C08 connects to SDA/SCL Groupt 1 by default */
> +    uint8_t *eeprom_buf = g_malloc0(32 * 1024);
> +    smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf);
> +
> +    /* U11 LM75 connects to SDA/SCL Group 2 by default */
> +    i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4d);
> +}
> +
>  static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
>                                                            void *data)
>  {
> @@ -1412,6 +1424,7 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
>      amc->hw_strap1 = 0;
>      amc->hw_strap2 = 0;
>      mc->init = aspeed_minibmc_machine_init;
> +    amc->i2c_init = ast1030_evb_i2c_init;
>      mc->default_ram_size = 0;
>      mc->default_cpus = mc->min_cpus = mc->max_cpus = 1;
>      amc->fmc_model = "sst25vf032b";
> diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c
> index d53454168403..a2ed275712fb 100644
> --- a/hw/arm/aspeed_ast10x0.c
> +++ b/hw/arm/aspeed_ast10x0.c
> @@ -114,6 +114,9 @@ static void aspeed_soc_ast1030_init(Object *obj)
>      object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1");
>      object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2");
>
> +    snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
> +    object_initialize_child(obj, "i2c", &s->i2c, typename);
> +
>      snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
>      object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
>
> @@ -188,6 +191,21 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
>      }
>      sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
>
> +    /* I2C */
> +
> +    object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(&s->sram),
> +                             &error_abort);
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
> +        return;
> +    }
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
> +    for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
> +        qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m),
> +                                        sc->irqmap[ASPEED_DEV_I2C] + i);
> +        /* The AST2600 I2C controller has one IRQ per bus. */

I know it's the same hardware, but is the "AST2600" part of the comment correct?

> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
> +    }
> +
>      /* LPC */
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
>          return;
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 12/21] aspeed/i2c: Add ast1030 controller models
  2022-06-06 15:07 ` [PATCH 12/21] aspeed/i2c: Add ast1030 controller models Cédric Le Goater
@ 2022-06-06 23:22   ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2022-06-06 23:22 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:09, Cédric Le Goater <clg@kaod.org> wrote:
>
> Based on :
>   https://lists.nongnu.org/archive/html/qemu-devel/2022-03/msg06017.html

Perhaps use the link to lore (which also includes the message id):

https://lore.kernel.org/qemu-devel/20220324100439.478317-2-troy_lee@aspeedtech.com/

Reviewed-by: Joel Stanley <joel@jms.id.au>

>
> Cc: Troy Lee <troy_lee@aspeedtech.com>
> Cc: Jamin Lin <jamin_lin@aspeedtech.com>
> Cc: Steven Lee <steven_lee@aspeedtech.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/i2c/aspeed_i2c.h |  1 +
>  hw/i2c/aspeed_i2c.c         | 24 ++++++++++++++++++++++++
>  2 files changed, 25 insertions(+)
>
> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
> index 506bcf1a9daf..79c6779c6c1e 100644
> --- a/include/hw/i2c/aspeed_i2c.h
> +++ b/include/hw/i2c/aspeed_i2c.h
> @@ -30,6 +30,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
> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
> index 8425e928890a..5fce516517a5 100644
> --- a/hw/i2c/aspeed_i2c.c
> +++ b/hw/i2c/aspeed_i2c.c
> @@ -1185,6 +1185,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);
> @@ -1192,6 +1215,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)
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 03/21] aspeed: i2c: Migrate to registerfields API
  2022-06-06 15:07 ` [PATCH 03/21] aspeed: i2c: Migrate to registerfields API Cédric Le Goater
@ 2022-06-06 23:29   ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2022-06-06 23:29 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>
> From: Joe Komlodi <komlodi@google.com>
>
> This cleans up some of the field accessing, setting, and clearing
> bitwise operations, and wraps them in macros instead.

I don't really like this change, as it adds more project-specific
"jargon" to the models.

It's clumsy in that we can no longer take a case from our switch
statements and grep for it:

 git grep A_I2CD_FUN_CTRL

Don't consider this a nak, but I felt it was worth explaining.

>
> Signed-off-by: Joe Komlodi <komlodi@google.com>
> Change-Id: I33018d6325fa04376e7c29dc4a49ab389a8e333a
> Message-Id: <20220331043248.2237838-4-komlodi@google.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/i2c/aspeed_i2c.c | 393 ++++++++++++++++++++++----------------------
>  1 file changed, 196 insertions(+), 197 deletions(-)
>
> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
> index 97eb9d57929c..be81a798cc35 100644
> --- a/hw/i2c/aspeed_i2c.c
> +++ b/hw/i2c/aspeed_i2c.c
> @@ -28,70 +28,61 @@
>  #include "hw/i2c/aspeed_i2c.h"
>  #include "hw/irq.h"
>  #include "hw/qdev-properties.h"
> +#include "hw/registerfields.h"
>  #include "trace.h"
>
>  /* I2C Global Register */
> -
> -#define I2C_CTRL_STATUS         0x00        /* Device Interrupt Status */
> -#define I2C_CTRL_ASSIGN         0x08        /* Device Interrupt Target
> -                                               Assignment */
> -#define I2C_CTRL_GLOBAL         0x0C        /* Global Control Register */
> -#define   I2C_CTRL_SRAM_EN                 BIT(0)
> +REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */
> +REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */
> +REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */
> +    FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1)
>
>  /* I2C Device (Bus) Register */
> -
> -#define I2CD_FUN_CTRL_REG       0x00       /* I2CD Function Control  */
> -#define   I2CD_POOL_PAGE_SEL(x)            (((x) >> 20) & 0x7)  /* AST2400 */
> -#define   I2CD_M_SDA_LOCK_EN               (0x1 << 16)
> -#define   I2CD_MULTI_MASTER_DIS            (0x1 << 15)
> -#define   I2CD_M_SCL_DRIVE_EN              (0x1 << 14)
> -#define   I2CD_MSB_STS                     (0x1 << 9)
> -#define   I2CD_SDA_DRIVE_1T_EN             (0x1 << 8)
> -#define   I2CD_M_SDA_DRIVE_1T_EN           (0x1 << 7)
> -#define   I2CD_M_HIGH_SPEED_EN             (0x1 << 6)
> -#define   I2CD_DEF_ADDR_EN                 (0x1 << 5)
> -#define   I2CD_DEF_ALERT_EN                (0x1 << 4)
> -#define   I2CD_DEF_ARP_EN                  (0x1 << 3)
> -#define   I2CD_DEF_GCALL_EN                (0x1 << 2)
> -#define   I2CD_SLAVE_EN                    (0x1 << 1)
> -#define   I2CD_MASTER_EN                   (0x1)
> -
> -#define I2CD_AC_TIMING_REG1     0x04       /* Clock and AC Timing Control #1 */
> -#define I2CD_AC_TIMING_REG2     0x08       /* Clock and AC Timing Control #1 */
> -#define I2CD_INTR_CTRL_REG      0x0c       /* I2CD Interrupt Control */
> -#define I2CD_INTR_STS_REG       0x10       /* I2CD Interrupt Status */
> -
> -#define   I2CD_INTR_SLAVE_ADDR_MATCH       (0x1 << 31) /* 0: addr1 1: addr2 */
> -#define   I2CD_INTR_SLAVE_ADDR_RX_PENDING  (0x1 << 30)
> -/* bits[19-16] Reserved */
> -
> -/* All bits below are cleared by writing 1 */
> -#define   I2CD_INTR_SLAVE_INACTIVE_TIMEOUT (0x1 << 15)
> -#define   I2CD_INTR_SDA_DL_TIMEOUT         (0x1 << 14)
> -#define   I2CD_INTR_BUS_RECOVER_DONE       (0x1 << 13)
> -#define   I2CD_INTR_SMBUS_ALERT            (0x1 << 12) /* Bus [0-3] only */
> -#define   I2CD_INTR_SMBUS_ARP_ADDR         (0x1 << 11) /* Removed */
> -#define   I2CD_INTR_SMBUS_DEV_ALERT_ADDR   (0x1 << 10) /* Removed */
> -#define   I2CD_INTR_SMBUS_DEF_ADDR         (0x1 << 9)  /* Removed */
> -#define   I2CD_INTR_GCALL_ADDR             (0x1 << 8)  /* Removed */
> -#define   I2CD_INTR_SLAVE_ADDR_RX_MATCH    (0x1 << 7)  /* use RX_DONE */
> -#define   I2CD_INTR_SCL_TIMEOUT            (0x1 << 6)
> -#define   I2CD_INTR_ABNORMAL               (0x1 << 5)
> -#define   I2CD_INTR_NORMAL_STOP            (0x1 << 4)
> -#define   I2CD_INTR_ARBIT_LOSS             (0x1 << 3)
> -#define   I2CD_INTR_RX_DONE                (0x1 << 2)
> -#define   I2CD_INTR_TX_NAK                 (0x1 << 1)
> -#define   I2CD_INTR_TX_ACK                 (0x1 << 0)
> -
> -#define I2CD_CMD_REG            0x14       /* I2CD Command/Status */
> -#define   I2CD_SDA_OE                      (0x1 << 28)
> -#define   I2CD_SDA_O                       (0x1 << 27)
> -#define   I2CD_SCL_OE                      (0x1 << 26)
> -#define   I2CD_SCL_O                       (0x1 << 25)
> -#define   I2CD_TX_TIMING                   (0x1 << 24)
> -#define   I2CD_TX_STATUS                   (0x1 << 23)
> -
> -#define   I2CD_TX_STATE_SHIFT              19 /* Tx State Machine */
> +REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control  */
> +    FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */
> +    FIELD(I2CD_FUN_CTRL, M_SDA_LOCK_EN, 16, 1)
> +    FIELD(I2CD_FUN_CTRL, MULTI_MASTER_DIS, 15, 1)
> +    FIELD(I2CD_FUN_CTRL, M_SCL_DRIVE_EN, 14, 1)
> +    FIELD(I2CD_FUN_CTRL, MSB_STS, 9, 1)
> +    FIELD(I2CD_FUN_CTRL, SDA_DRIVE_IT_EN, 8, 1)
> +    FIELD(I2CD_FUN_CTRL, M_SDA_DRIVE_IT_EN, 7, 1)
> +    FIELD(I2CD_FUN_CTRL, M_HIGH_SPEED_EN, 6, 1)
> +    FIELD(I2CD_FUN_CTRL, DEF_ADDR_EN, 5, 1)
> +    FIELD(I2CD_FUN_CTRL, DEF_ALERT_EN, 4, 1)
> +    FIELD(I2CD_FUN_CTRL, DEF_ARP_EN, 3, 1)
> +    FIELD(I2CD_FUN_CTRL, DEF_GCALL_EN, 2, 1)
> +    FIELD(I2CD_FUN_CTRL, SLAVE_EN, 1, 1)
> +    FIELD(I2CD_FUN_CTRL, MASTER_EN, 0, 1)
> +REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */
> +REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */
> +REG32(I2CD_INTR_CTRL, 0x0C)  /* I2CD Interrupt Control */
> +REG32(I2CD_INTR_STS, 0x10)   /* I2CD Interrupt Status */
> +    FIELD(I2CD_INTR_STS, SLAVE_ADDR_MATCH, 31, 1)    /* 0: addr1 1: addr2 */
> +    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_PENDING, 29, 1)
> +    FIELD(I2CD_INTR_STS, SLAVE_INACTIVE_TIMEOUT, 15, 1)
> +    FIELD(I2CD_INTR_STS, SDA_DL_TIMEOUT, 14, 1)
> +    FIELD(I2CD_INTR_STS, BUS_RECOVER_DONE, 13, 1)
> +    FIELD(I2CD_INTR_STS, SMBUS_ALERT, 12, 1)            /* Bus [0-3] only */
> +    FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1)         /* Removed */
> +    FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1)   /* Removed */
> +    FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1)          /* Removed */
> +    FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1)              /* Removed */
> +    FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1)     /* use RX_DONE */
> +    FIELD(I2CD_INTR_STS, SCL_TIMEOUT, 6, 1)
> +    FIELD(I2CD_INTR_STS, ABNORMAL, 5, 1)
> +    FIELD(I2CD_INTR_STS, NORMAL_STOP, 4, 1)
> +    FIELD(I2CD_INTR_STS, ARBIT_LOSS, 3, 1)
> +    FIELD(I2CD_INTR_STS, RX_DONE, 2, 1)
> +    FIELD(I2CD_INTR_STS, TX_NAK, 1, 1)
> +    FIELD(I2CD_INTR_STS, TX_ACK, 0, 1)
> +REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
> +    FIELD(I2CD_CMD, SDA_OE, 28, 1)
> +    FIELD(I2CD_CMD, SDA_O, 27, 1)
> +    FIELD(I2CD_CMD, SCL_OE, 26, 1)
> +    FIELD(I2CD_CMD, SCL_O, 25, 1)
> +    FIELD(I2CD_CMD, TX_TIMING, 23, 2)
> +    FIELD(I2CD_CMD, TX_STATE, 19, 4)
> +/* Tx State Machine */
>  #define   I2CD_TX_STATE_MASK                  0xf
>  #define     I2CD_IDLE                         0x0
>  #define     I2CD_MACTIVE                      0x8
> @@ -108,51 +99,47 @@
>  #define     I2CD_STXD                         0x6
>  #define     I2CD_SRXACK                       0x7
>  #define     I2CD_RECOVER                      0x3
> -
> -#define   I2CD_SCL_LINE_STS                (0x1 << 18)
> -#define   I2CD_SDA_LINE_STS                (0x1 << 17)
> -#define   I2CD_BUS_BUSY_STS                (0x1 << 16)
> -#define   I2CD_SDA_OE_OUT_DIR              (0x1 << 15)
> -#define   I2CD_SDA_O_OUT_DIR               (0x1 << 14)
> -#define   I2CD_SCL_OE_OUT_DIR              (0x1 << 13)
> -#define   I2CD_SCL_O_OUT_DIR               (0x1 << 12)
> -#define   I2CD_BUS_RECOVER_CMD_EN          (0x1 << 11)
> -#define   I2CD_S_ALT_EN                    (0x1 << 10)
> -
> -/* Command Bit */
> -#define   I2CD_RX_DMA_ENABLE               (0x1 << 9)
> -#define   I2CD_TX_DMA_ENABLE               (0x1 << 8)
> -#define   I2CD_RX_BUFF_ENABLE              (0x1 << 7)
> -#define   I2CD_TX_BUFF_ENABLE              (0x1 << 6)
> -#define   I2CD_M_STOP_CMD                  (0x1 << 5)
> -#define   I2CD_M_S_RX_CMD_LAST             (0x1 << 4)
> -#define   I2CD_M_RX_CMD                    (0x1 << 3)
> -#define   I2CD_S_TX_CMD                    (0x1 << 2)
> -#define   I2CD_M_TX_CMD                    (0x1 << 1)
> -#define   I2CD_M_START_CMD                 (0x1)
> -
> -#define I2CD_DEV_ADDR_REG       0x18       /* Slave Device Address */
> -#define I2CD_POOL_CTRL_REG      0x1c       /* Pool Buffer Control */
> -#define   I2CD_POOL_RX_COUNT(x)            (((x) >> 24) & 0xff)
> -#define   I2CD_POOL_RX_SIZE(x)             ((((x) >> 16) & 0xff) + 1)
> -#define   I2CD_POOL_TX_COUNT(x)            ((((x) >> 8) & 0xff) + 1)
> -#define   I2CD_POOL_OFFSET(x)              (((x) & 0x3f) << 2)  /* AST2400 */
> -#define I2CD_BYTE_BUF_REG       0x20       /* Transmit/Receive Byte Buffer */
> -#define   I2CD_BYTE_BUF_TX_SHIFT           0
> -#define   I2CD_BYTE_BUF_TX_MASK            0xff
> -#define   I2CD_BYTE_BUF_RX_SHIFT           8
> -#define   I2CD_BYTE_BUF_RX_MASK            0xff
> -#define I2CD_DMA_ADDR           0x24       /* DMA Buffer Address */
> -#define I2CD_DMA_LEN            0x28       /* DMA Transfer Length < 4KB */
> +    FIELD(I2CD_CMD, SCL_LINE_STS, 18, 1)
> +    FIELD(I2CD_CMD, SDA_LINE_STS, 17, 1)
> +    FIELD(I2CD_CMD, BUS_BUSY_STS, 16, 1)
> +    FIELD(I2CD_CMD, SDA_OE_OUT_DIR, 15, 1)
> +    FIELD(I2CD_CMD, SDA_O_OUT_DIR, 14, 1)
> +    FIELD(I2CD_CMD, SCL_OE_OUT_DIR, 13, 1)
> +    FIELD(I2CD_CMD, SCL_O_OUT_DIR, 12, 1)
> +    FIELD(I2CD_CMD, BUS_RECOVER_CMD_EN, 11, 1)
> +    FIELD(I2CD_CMD, S_ALT_EN, 10, 1)
> +    /* Command Bits */
> +    FIELD(I2CD_CMD, RX_DMA_EN, 9, 1)
> +    FIELD(I2CD_CMD, TX_DMA_EN, 8, 1)
> +    FIELD(I2CD_CMD, RX_BUFF_EN, 7, 1)
> +    FIELD(I2CD_CMD, TX_BUFF_EN, 6, 1)
> +    FIELD(I2CD_CMD, M_STOP_CMD, 5, 1)
> +    FIELD(I2CD_CMD, M_S_RX_CMD_LAST, 4, 1)
> +    FIELD(I2CD_CMD, M_RX_CMD, 3, 1)
> +    FIELD(I2CD_CMD, S_TX_CMD, 2, 1)
> +    FIELD(I2CD_CMD, M_TX_CMD, 1, 1)
> +    FIELD(I2CD_CMD, M_START_CMD, 0, 1)
> +REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
> +REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
> +    FIELD(I2CD_POOL_CTRL, RX_COUNT, 24, 5)
> +    FIELD(I2CD_POOL_CTRL, RX_SIZE, 16, 5)
> +    FIELD(I2CD_POOL_CTRL, TX_COUNT, 9, 5)
> +    FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
> +REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
> +    FIELD(I2CD_BYTE_BUF, RX_BUF, 8, 8)
> +    FIELD(I2CD_BYTE_BUF, TX_BUF, 0, 8)
> +REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */
> +REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */
>
>  static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
>  {
> -    return bus->ctrl & I2CD_MASTER_EN;
> +    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN);
>  }
>
>  static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus)
>  {
> -    return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN);
> +    return FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, MASTER_EN) ||
> +           FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL, SLAVE_EN);
>  }
>
>  static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
> @@ -160,11 +147,13 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
>      AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
>
>      trace_aspeed_i2c_bus_raise_interrupt(bus->intr_status,
> -          bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "",
> -          bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "",
> -          bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "",
> -          bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "",
> -          bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : "");
> +        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_NAK) ? "nak|" : "",
> +        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, TX_ACK) ? "ack|" : "",
> +        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) ? "done|" : "",
> +        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, NORMAL_STOP) ? "normal|"
> +                                                                 : "",
> +        FIELD_EX32(bus->intr_status, I2CD_INTR_STS, ABNORMAL) ? "abnormal"
> +                                                              : "");
>
>      bus->intr_status &= bus->intr_ctrl;
>      if (bus->intr_status) {
> @@ -181,38 +170,38 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
>      uint64_t value = -1;
>
>      switch (offset) {
> -    case I2CD_FUN_CTRL_REG:
> +    case A_I2CD_FUN_CTRL:
>          value = bus->ctrl;
>          break;
> -    case I2CD_AC_TIMING_REG1:
> +    case A_I2CD_AC_TIMING1:
>          value = bus->timing[0];
>          break;
> -    case I2CD_AC_TIMING_REG2:
> +    case A_I2CD_AC_TIMING2:
>          value = bus->timing[1];
>          break;
> -    case I2CD_INTR_CTRL_REG:
> +    case A_I2CD_INTR_CTRL:
>          value = bus->intr_ctrl;
>          break;
> -    case I2CD_INTR_STS_REG:
> +    case A_I2CD_INTR_STS:
>          value = bus->intr_status;
>          break;
> -    case I2CD_POOL_CTRL_REG:
> +    case A_I2CD_POOL_CTRL:
>          value = bus->pool_ctrl;
>          break;
> -    case I2CD_BYTE_BUF_REG:
> +    case A_I2CD_BYTE_BUF:
>          value = bus->buf;
>          break;
> -    case I2CD_CMD_REG:
> +    case A_I2CD_CMD:
>          value = bus->cmd | (i2c_bus_busy(bus->bus) << 16);
>          break;
> -    case I2CD_DMA_ADDR:
> +    case A_I2CD_DMA_ADDR:
>          if (!aic->has_dma) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
>              break;
>          }
>          value = bus->dma_addr;
>          break;
> -    case I2CD_DMA_LEN:
> +    case A_I2CD_DMA_LEN:
>          if (!aic->has_dma) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
>              break;
> @@ -233,13 +222,12 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
>
>  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;
> +    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_STATE, state);
>  }
>
>  static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
>  {
> -    return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
> +    return FIELD_EX32(bus->cmd, I2CD_CMD, TX_STATE);
>  }
>
>  static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
> @@ -265,21 +253,21 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
>      AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
>      int ret = -1;
>      int i;
> +    int pool_tx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
>
> -    if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
> -        for (i = pool_start; i < I2CD_POOL_TX_COUNT(bus->pool_ctrl); i++) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
> +        for (i = pool_start; i < pool_tx_count; i++) {
>              uint8_t *pool_base = aic->bus_pool_base(bus);
>
> -            trace_aspeed_i2c_bus_send("BUF", i + 1,
> -                                      I2CD_POOL_TX_COUNT(bus->pool_ctrl),
> +            trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count,
>                                        pool_base[i]);
>              ret = i2c_send(bus->bus, pool_base[i]);
>              if (ret) {
>                  break;
>              }
>          }
> -        bus->cmd &= ~I2CD_TX_BUFF_ENABLE;
> -    } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_BUFF_EN, 0);
> +    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
>          while (bus->dma_len) {
>              uint8_t data;
>              aspeed_i2c_dma_read(bus, &data);
> @@ -289,7 +277,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
>                  break;
>              }
>          }
> -        bus->cmd &= ~I2CD_TX_DMA_ENABLE;
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, TX_DMA_EN, 0);
>      } else {
>          trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, bus->buf);
>          ret = i2c_send(bus->bus, bus->buf);
> @@ -304,22 +292,22 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
>      AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
>      uint8_t data;
>      int i;
> +    int pool_rx_count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT);
>
> -    if (bus->cmd & I2CD_RX_BUFF_ENABLE) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
>          uint8_t *pool_base = aic->bus_pool_base(bus);
>
> -        for (i = 0; i < I2CD_POOL_RX_SIZE(bus->pool_ctrl); i++) {
> +        for (i = 0; i < pool_rx_count; i++) {
>              pool_base[i] = i2c_recv(bus->bus);
> -            trace_aspeed_i2c_bus_recv("BUF", i + 1,
> -                                      I2CD_POOL_RX_SIZE(bus->pool_ctrl),
> +            trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count,
>                                        pool_base[i]);
>          }
>
>          /* Update RX count */
> -        bus->pool_ctrl &= ~(0xff << 24);
> -        bus->pool_ctrl |= (i & 0xff) << 24;
> -        bus->cmd &= ~I2CD_RX_BUFF_ENABLE;
> -    } else if (bus->cmd & I2CD_RX_DMA_ENABLE) {
> +        bus->pool_ctrl = FIELD_DP32(bus->pool_ctrl, I2CD_POOL_CTRL, RX_COUNT,
> +                                    i & 0xff);
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_BUFF_EN, 0);
> +    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
>          uint8_t data;
>
>          while (bus->dma_len) {
> @@ -337,11 +325,11 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
>              bus->dma_addr++;
>              bus->dma_len--;
>          }
> -        bus->cmd &= ~I2CD_RX_DMA_ENABLE;
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, RX_DMA_EN, 0);
>      } else {
>          data = i2c_recv(bus->bus);
>          trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->buf);
> -        bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
> +        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, RX_BUF, data);
>      }
>  }
>
> @@ -349,11 +337,12 @@ static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
>  {
>      aspeed_i2c_set_state(bus, I2CD_MRXD);
>      aspeed_i2c_bus_recv(bus);
> -    bus->intr_status |= I2CD_INTR_RX_DONE;
> -    if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
> +    bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS, RX_DONE, 1);
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) {
>          i2c_nack(bus->bus);
>      }
> -    bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST);
> +    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_RX_CMD, 0);
> +    bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST, 0);
>      aspeed_i2c_set_state(bus, I2CD_MACTIVE);
>  }
>
> @@ -361,11 +350,11 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
>  {
>      AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
>
> -    if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
>          uint8_t *pool_base = aic->bus_pool_base(bus);
>
>          return pool_base[0];
> -    } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
> +    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
>          uint8_t data;
>
>          aspeed_i2c_dma_read(bus, &data);
> @@ -379,7 +368,10 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
>  {
>      AspeedI2CState *s = bus->controller;
>      AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
> -
> +    bool dma_en = FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)  ||
> +                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)  ||
> +                  FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ||
> +                  FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN);
>      if (!aic->check_sram) {
>          return true;
>      }
> @@ -388,9 +380,7 @@ static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
>       * AST2500: SRAM must be enabled before using the Buffer Pool or
>       * DMA mode.
>       */
> -    if (!(s->ctrl_global & I2C_CTRL_SRAM_EN) &&
> -        (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE |
> -                     I2CD_RX_BUFF_ENABLE | I2CD_TX_BUFF_ENABLE))) {
> +    if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) {
>          qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__);
>          return false;
>      }
> @@ -402,25 +392,24 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
>  {
>      g_autofree char *cmd_flags = NULL;
>      uint32_t count;
> -
> -    if (bus->cmd & (I2CD_RX_BUFF_ENABLE | I2CD_RX_BUFF_ENABLE)) {
> -        count = I2CD_POOL_TX_COUNT(bus->pool_ctrl);
> -    } else if (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_RX_DMA_ENABLE)) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN)) {
> +        count = FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT);
> +    } else if (FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN)) {
>          count = bus->dma_len;
>      } else { /* BYTE mode */
>          count = 1;
>      }
>
>      cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
> -                                bus->cmd & I2CD_M_START_CMD ? "start|" : "",
> -                                bus->cmd & I2CD_RX_DMA_ENABLE ? "rxdma|" : "",
> -                                bus->cmd & I2CD_TX_DMA_ENABLE ? "txdma|" : "",
> -                                bus->cmd & I2CD_RX_BUFF_ENABLE ? "rxbuf|" : "",
> -                                bus->cmd & I2CD_TX_BUFF_ENABLE ? "txbuf|" : "",
> -                                bus->cmd & I2CD_M_TX_CMD ? "tx|" : "",
> -                                bus->cmd & I2CD_M_RX_CMD ? "rx|" : "",
> -                                bus->cmd & I2CD_M_S_RX_CMD_LAST ? "last|" : "",
> -                                bus->cmd & I2CD_M_STOP_CMD ? "stop" : "");
> +             FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD) ? "start|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, RX_DMA_EN) ? "rxdma|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN) ? "txdma|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, RX_BUFF_EN) ? "rxbuf|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN) ? "txbuf|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD) ? "tx|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ? "rx|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST) ? "last|" : "",
> +             FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD) ? "stop" : "");
>
>      trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status);
>  }
> @@ -444,7 +433,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
>          aspeed_i2c_bus_cmd_dump(bus);
>      }
>
> -    if (bus->cmd & I2CD_M_START_CMD) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_START_CMD)) {
>          uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
>              I2CD_MSTARTR : I2CD_MSTART;
>          uint8_t addr;
> @@ -455,21 +444,23 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
>
>          if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
>                                 extract32(addr, 0, 1))) {
> -            bus->intr_status |= I2CD_INTR_TX_NAK;
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          TX_NAK, 1);
>          } else {
> -            bus->intr_status |= I2CD_INTR_TX_ACK;
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          TX_ACK, 1);
>          }
>
> -        bus->cmd &= ~I2CD_M_START_CMD;
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_START_CMD, 0);
>
>          /*
>           * The START command is also a TX command, as the slave
>           * address is sent on the bus. Drop the TX flag if nothing
>           * else needs to be sent in this sequence.
>           */
> -        if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
> -            if (I2CD_POOL_TX_COUNT(bus->pool_ctrl) == 1) {
> -                bus->cmd &= ~I2CD_M_TX_CMD;
> +        if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_BUFF_EN)) {
> +            if (FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, TX_COUNT) == 1) {
> +                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
>              } else {
>                  /*
>                   * Increase the start index in the TX pool buffer to
> @@ -477,12 +468,12 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
>                   */
>                  pool_start++;
>              }
> -        } else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
> +        } else if (FIELD_EX32(bus->cmd, I2CD_CMD, TX_DMA_EN)) {
>              if (bus->dma_len == 0) {
> -                bus->cmd &= ~I2CD_M_TX_CMD;
> +                bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
>              }
>          } else {
> -            bus->cmd &= ~I2CD_M_TX_CMD;
> +            bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
>          }
>
>          /* No slave found */
> @@ -492,33 +483,38 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
>          aspeed_i2c_set_state(bus, I2CD_MACTIVE);
>      }
>
> -    if (bus->cmd & I2CD_M_TX_CMD) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_TX_CMD)) {
>          aspeed_i2c_set_state(bus, I2CD_MTXD);
>          if (aspeed_i2c_bus_send(bus, pool_start)) {
> -            bus->intr_status |= (I2CD_INTR_TX_NAK);
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          TX_NAK, 1);
>              i2c_end_transfer(bus->bus);
>          } else {
> -            bus->intr_status |= I2CD_INTR_TX_ACK;
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          TX_ACK, 1);
>          }
> -        bus->cmd &= ~I2CD_M_TX_CMD;
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_TX_CMD, 0);
>          aspeed_i2c_set_state(bus, I2CD_MACTIVE);
>      }
>
> -    if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) &&
> -        !(bus->intr_status & I2CD_INTR_RX_DONE)) {
> +    if ((FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
> +         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST)) &&
> +        !FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE)) {
>          aspeed_i2c_handle_rx_cmd(bus);
>      }
>
> -    if (bus->cmd & I2CD_M_STOP_CMD) {
> +    if (FIELD_EX32(bus->cmd, I2CD_CMD, M_STOP_CMD)) {
>          if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__);
> -            bus->intr_status |= I2CD_INTR_ABNORMAL;
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          ABNORMAL, 1);
>          } else {
>              aspeed_i2c_set_state(bus, I2CD_MSTOP);
>              i2c_end_transfer(bus->bus);
> -            bus->intr_status |= I2CD_INTR_NORMAL_STOP;
> +            bus->intr_status = FIELD_DP32(bus->intr_status, I2CD_INTR_STS,
> +                                          NORMAL_STOP, 1);
>          }
> -        bus->cmd &= ~I2CD_M_STOP_CMD;
> +        bus->cmd = FIELD_DP32(bus->cmd, I2CD_CMD, M_STOP_CMD, 0);
>          aspeed_i2c_set_state(bus, I2CD_IDLE);
>      }
>  }
> @@ -533,49 +529,50 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>      trace_aspeed_i2c_bus_write(bus->id, offset, size, value);
>
>      switch (offset) {
> -    case I2CD_FUN_CTRL_REG:
> -        if (value & I2CD_SLAVE_EN) {
> +    case A_I2CD_FUN_CTRL:
> +        if (FIELD_EX32(value, I2CD_FUN_CTRL, SLAVE_EN)) {
>              qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
>                            __func__);
>              break;
>          }
>          bus->ctrl = value & 0x0071C3FF;
>          break;
> -    case I2CD_AC_TIMING_REG1:
> +    case A_I2CD_AC_TIMING1:
>          bus->timing[0] = value & 0xFFFFF0F;
>          break;
> -    case I2CD_AC_TIMING_REG2:
> +    case A_I2CD_AC_TIMING2:
>          bus->timing[1] = value & 0x7;
>          break;
> -    case I2CD_INTR_CTRL_REG:
> +    case A_I2CD_INTR_CTRL:
>          bus->intr_ctrl = value & 0x7FFF;
>          break;
> -    case I2CD_INTR_STS_REG:
> -        handle_rx = (bus->intr_status & I2CD_INTR_RX_DONE) &&
> -                (value & I2CD_INTR_RX_DONE);
> +    case A_I2CD_INTR_STS:
> +        handle_rx = FIELD_EX32(bus->intr_status, I2CD_INTR_STS, RX_DONE) &&
> +                    FIELD_EX32(value, I2CD_INTR_STS, RX_DONE);
>          bus->intr_status &= ~(value & 0x7FFF);
>          if (!bus->intr_status) {
>              bus->controller->intr_status &= ~(1 << bus->id);
>              qemu_irq_lower(aic->bus_get_irq(bus));
>          }
> -        if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) {
> +        if (handle_rx && (FIELD_EX32(bus->cmd, I2CD_CMD, M_RX_CMD) ||
> +                         FIELD_EX32(bus->cmd, I2CD_CMD, M_S_RX_CMD_LAST))) {
>              aspeed_i2c_handle_rx_cmd(bus);
>              aspeed_i2c_bus_raise_interrupt(bus);
>          }
>          break;
> -    case I2CD_DEV_ADDR_REG:
> +    case A_I2CD_DEV_ADDR:
>          qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
>                        __func__);
>          break;
> -    case I2CD_POOL_CTRL_REG:
> +    case A_I2CD_POOL_CTRL:
>          bus->pool_ctrl &= ~0xffffff;
>          bus->pool_ctrl |= (value & 0xffffff);
>          break;
>
> -    case I2CD_BYTE_BUF_REG:
> -        bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT;
> +    case A_I2CD_BYTE_BUF:
> +        bus->buf = FIELD_DP32(bus->buf, I2CD_BYTE_BUF, TX_BUF, value);
>          break;
> -    case I2CD_CMD_REG:
> +    case A_I2CD_CMD:
>          if (!aspeed_i2c_bus_is_enabled(bus)) {
>              break;
>          }
> @@ -587,7 +584,8 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>          }
>
>          if (!aic->has_dma &&
> -            value & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE)) {
> +            (FIELD_EX32(value, I2CD_CMD, RX_DMA_EN) ||
> +             FIELD_EX32(value, I2CD_CMD, TX_DMA_EN))) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
>              break;
>          }
> @@ -595,7 +593,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>          aspeed_i2c_bus_handle_cmd(bus, value);
>          aspeed_i2c_bus_raise_interrupt(bus);
>          break;
> -    case I2CD_DMA_ADDR:
> +    case A_I2CD_DMA_ADDR:
>          if (!aic->has_dma) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
>              break;
> @@ -604,7 +602,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>          bus->dma_addr = value & 0x3ffffffc;
>          break;
>
> -    case I2CD_DMA_LEN:
> +    case A_I2CD_DMA_LEN:
>          if (!aic->has_dma) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n",  __func__);
>              break;
> @@ -628,9 +626,9 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
>      AspeedI2CState *s = opaque;
>
>      switch (offset) {
> -    case I2C_CTRL_STATUS:
> +    case A_I2C_CTRL_STATUS:
>          return s->intr_status;
> -    case I2C_CTRL_GLOBAL:
> +    case A_I2C_CTRL_GLOBAL:
>          return s->ctrl_global;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
> @@ -647,11 +645,11 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
>      AspeedI2CState *s = opaque;
>
>      switch (offset) {
> -    case I2C_CTRL_GLOBAL:
> +    case A_I2C_CTRL_GLOBAL:
>          value &= ~s->ctrl_global_rsvd;
>          s->ctrl_global = value;
>          break;
> -    case I2C_CTRL_STATUS:
> +    case A_I2C_CTRL_STATUS:
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
>                        __func__, offset);
> @@ -923,9 +921,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
>  static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
>  {
>      uint8_t *pool_page =
> -        &bus->controller->pool[I2CD_POOL_PAGE_SEL(bus->ctrl) * 0x100];
> +        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
> +                                          POOL_PAGE_SEL) * 0x100];
>
> -    return &pool_page[I2CD_POOL_OFFSET(bus->pool_ctrl)];
> +    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
>  }
>
>  static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars
  2022-06-06 15:07 ` [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars Cédric Le Goater
@ 2022-06-06 23:49   ` Joel Stanley
  2022-06-07  9:57     ` Cédric Le Goater
  2022-06-07 10:50     ` Cédric Le Goater
  0 siblings, 2 replies; 34+ messages in thread
From: Joel Stanley @ 2022-06-06 23:49 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>
> From: Joe Komlodi <komlodi@google.com>
>
> Using a register array will allow us to represent old-mode and new-mode
> I2C registers by using the same underlying register array, instead of
> adding an entire new set of variables to represent new mode.

The downside of this approach is you lose the safety of having
discrete types. A write to s->regs[R_FOO] can overwrite R_BAR.


>
> As part of this, we also do additional cleanup to use ARRAY_FIELD_
> macros instead of FIELD_ macros on registers.
>
> Signed-off-by: Joe Komlodi <komlodi@google.com>
> Change-Id: Ib94996b17c361b8490c042b43c99d8abc69332e3
> Message-Id: <20220331043248.2237838-5-komlodi@google.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/i2c/aspeed_i2c.h |  11 +-
>  hw/i2c/aspeed_i2c.c         | 286 +++++++++++++++++-------------------
>  2 files changed, 133 insertions(+), 164 deletions(-)

> @@ -858,12 +834,12 @@ static void aspeed_i2c_bus_reset(DeviceState *dev)
>  {
>      AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
>
> -    s->intr_ctrl = 0;
> -    s->intr_status = 0;
> -    s->cmd = 0;
> -    s->buf = 0;
> -    s->dma_addr = 0;
> -    s->dma_len = 0;
> +    s->regs[R_I2CD_INTR_CTRL] = 0;
> +    s->regs[R_I2CD_INTR_STS] = 0;
> +    s->regs[R_I2CD_CMD] = 0;
> +    s->regs[R_I2CD_BYTE_BUF] = 0;
> +    s->regs[R_I2CD_DMA_ADDR] = 0;
> +    s->regs[R_I2CD_DMA_LEN] = 0;

Could this become a memset of s->regs?

>      i2c_end_transfer(s->bus);
>  }
>
> @@ -921,10 +897,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
>  static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
>  {
>      uint8_t *pool_page =
> -        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
> -                                          POOL_PAGE_SEL) * 0x100];
> +        &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
> +                                                POOL_PAGE_SEL) * 0x100];
>
> -    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
> +    return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
>  }
>
>  static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property
  2022-06-06 15:07 ` [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property Cédric Le Goater
@ 2022-06-07  0:05   ` Joel Stanley
  2022-06-07 17:32     ` Cédric Le Goater
  0 siblings, 1 reply; 34+ messages in thread
From: Joel Stanley @ 2022-06-07  0:05 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>
> From: Joe Komlodi <komlodi@google.com>
>
> The Aspeed I2C controller is used across other SKUs that have different
> reserved bits for the ctrl_global_rsvd register.

I think rsvd stands for reserved? Lets spell out the full name in the
variable to keep it clear.

You could also call global_control_mask (or ctrl_global_mask if you
prefer), as it's a mask of valid bits.

>
> Signed-off-by: Joe Komlodi <komlodi@google.com>
> Change-Id: I606c5933c527274a9d2b0afe559b2e895767636c
> Message-Id: <20220331043248.2237838-3-komlodi@google.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/i2c/aspeed_i2c.h | 2 ++
>  hw/arm/aspeed_ast2600.c     | 2 ++
>  hw/i2c/aspeed_i2c.c         | 4 ++++
>  3 files changed, 8 insertions(+)
>
> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
> index 4b9be09274c7..3912fcc3ff53 100644
> --- a/include/hw/i2c/aspeed_i2c.h
> +++ b/include/hw/i2c/aspeed_i2c.h
> @@ -71,6 +71,8 @@ struct AspeedI2CState {
>      MemoryRegion pool_iomem;
>      uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
>
> +    uint32_t ctrl_global_rsvd;
> +
>      AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
>      MemoryRegion *dram_mr;
>      AddressSpace dram_as;
> diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
> index b0a4199b6960..cc57c8b437d8 100644
> --- a/hw/arm/aspeed_ast2600.c
> +++ b/hw/arm/aspeed_ast2600.c
> @@ -375,6 +375,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
>      aspeed_soc_uart_init(s);
>
>      /* I2C */
> +    object_property_set_int(OBJECT(&s->i2c), "ctrl-global-rsvd", 0xfffc3e00,
> +                            &error_abort);
>      object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
>                               &error_abort);
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
> index 03a4f5a91010..97eb9d57929c 100644
> --- a/hw/i2c/aspeed_i2c.c
> +++ b/hw/i2c/aspeed_i2c.c
> @@ -648,6 +648,7 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
>
>      switch (offset) {
>      case I2C_CTRL_GLOBAL:
> +        value &= ~s->ctrl_global_rsvd;

Is there value in printing a guest error when the reserved bits are set?

If not, is it worth having this property at all? It doesn't affect the
ability to model it.

>          s->ctrl_global = value;
>          break;
>      case I2C_CTRL_STATUS:
> @@ -730,6 +731,7 @@ static const VMStateDescription aspeed_i2c_vmstate = {
>      .minimum_version_id = 2,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINT32(intr_status, AspeedI2CState),
> +        VMSTATE_UINT32(ctrl_global_rsvd, AspeedI2CState),
>          VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
>                               ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
>                               AspeedI2CBus),
> @@ -828,6 +830,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
>  static Property aspeed_i2c_properties[] = {
>      DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr,
>                       TYPE_MEMORY_REGION, MemoryRegion *),
> +    DEFINE_PROP_UINT32("ctrl-global-rsvd", AspeedI2CState, ctrl_global_rsvd,
> +                       0xfffffffe),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>
> --
> 2.35.3
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars
  2022-06-06 23:49   ` Joel Stanley
@ 2022-06-07  9:57     ` Cédric Le Goater
  2022-06-07 10:50     ` Cédric Le Goater
  1 sibling, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-07  9:57 UTC (permalink / raw)
  To: Joel Stanley
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On 6/7/22 01:49, Joel Stanley wrote:
> On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> From: Joe Komlodi <komlodi@google.com>
>>
>> Using a register array will allow us to represent old-mode and new-mode
>> I2C registers by using the same underlying register array, instead of
>> adding an entire new set of variables to represent new mode.
> 
> The downside of this approach is you lose the safety of having
> discrete types. A write to s->regs[R_FOO] can overwrite R_BAR.
> 
> 
>>
>> As part of this, we also do additional cleanup to use ARRAY_FIELD_
>> macros instead of FIELD_ macros on registers.
>>
>> Signed-off-by: Joe Komlodi <komlodi@google.com>
>> Change-Id: Ib94996b17c361b8490c042b43c99d8abc69332e3
>> Message-Id: <20220331043248.2237838-5-komlodi@google.com>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>   include/hw/i2c/aspeed_i2c.h |  11 +-
>>   hw/i2c/aspeed_i2c.c         | 286 +++++++++++++++++-------------------
>>   2 files changed, 133 insertions(+), 164 deletions(-)
> 
>> @@ -858,12 +834,12 @@ static void aspeed_i2c_bus_reset(DeviceState *dev)
>>   {
>>       AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
>>
>> -    s->intr_ctrl = 0;
>> -    s->intr_status = 0;
>> -    s->cmd = 0;
>> -    s->buf = 0;
>> -    s->dma_addr = 0;
>> -    s->dma_len = 0;
>> +    s->regs[R_I2CD_INTR_CTRL] = 0;
>> +    s->regs[R_I2CD_INTR_STS] = 0;
>> +    s->regs[R_I2CD_CMD] = 0;
>> +    s->regs[R_I2CD_BYTE_BUF] = 0;
>> +    s->regs[R_I2CD_DMA_ADDR] = 0;
>> +    s->regs[R_I2CD_DMA_LEN] = 0;
> 
> Could this become a memset of s->regs?

yes. It should. I can take care of it.

Thanks,

C.

> 
>>       i2c_end_transfer(s->bus);
>>   }
>>
>> @@ -921,10 +897,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
>>   static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
>>   {
>>       uint8_t *pool_page =
>> -        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
>> -                                          POOL_PAGE_SEL) * 0x100];
>> +        &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
>> +                                                POOL_PAGE_SEL) * 0x100];
>>
>> -    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
>> +    return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
>>   }
>>
>>   static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
>> --
>> 2.35.3
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test
  2022-06-06 23:16   ` Joel Stanley
@ 2022-06-07 10:17     ` Cédric Le Goater
  0 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-07 10:17 UTC (permalink / raw)
  To: Joel Stanley
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On 6/7/22 01:16, Joel Stanley wrote:
> On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> Add a RTC device on bus 15 and check that the ouput of the hwclock
> 
> spelling: output
> 
>> command matches the current year.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> Reviewed-by: Joel Stanley <joel@jms.id.au>
> 
>> ---
>>   tests/avocado/machine_aspeed.py | 8 ++++++++
>>   1 file changed, 8 insertions(+)
>>
>> diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
>> index a3b4b9e5093c..28b8a4c8124b 100644
>> --- a/tests/avocado/machine_aspeed.py
>> +++ b/tests/avocado/machine_aspeed.py
>> @@ -136,10 +136,18 @@ def test_arm_ast2600_evb_builroot(self):
>>
>>           self.vm.add_args('-device',
>>                            'tmp423,bus=aspeed.i2c.bus.15,address=0x4c');
>> +        self.vm.add_args('-device',
>> +                         'ds1338,bus=aspeed.i2c.bus.15,address=0x32');
> 
> Is there any value running this on the 2400 and 2500 machine types
> too?

We could do that, yes. Send patches !

> They all use the same model so perhaps not?

Currently, all models are exercised more or less in the same way by
the upstream Linux driver. Things are different for the AST1030 using
Zephir and for the AST2600 when using newer drivers from the SDK.

These images seem to be using the new AST2600 register mode:

   https://github.com/AspeedTech-BMC/openbmc/releases/

   root@ast2600-default:~# dmesg | grep i2c
   [    0.211289] i2c global registered
   [    1.442027] i2c_dev: i2c /dev entries driver
   [    1.447944] i2c_new_aspeed 1e78a280.i2c-bus: NEW-I2C: i2c-bus [4]: adapter [100 khz] mode [2]
   [    1.451158] ipmb-dev 5-0010: i2c_slave_register: client slave flag not set. You might see address collisions
   [    1.451660] i2c_new_aspeed 1e78a300.i2c-bus: NEW-I2C: i2c-bus [5]: adapter [100 khz] mode [2]
   [    1.454567] ipmb-dev 6-0012: i2c_slave_register: client slave flag not set. You might see address collisions
   [    1.454938] i2c_new_aspeed 1e78a380.i2c-bus: NEW-I2C: i2c-bus [6]: adapter [100 khz] mode [2]
   [    1.462953] i2c_new_aspeed 1e78a400.i2c-bus: NEW-I2C: i2c-bus [7]: adapter [95 khz] mode [2]
   [    1.466394] i2c_new_aspeed 1e78a480.i2c-bus: NEW-I2C: i2c-bus [8]: adapter [100 khz] mode [2]
   [    1.468394] i2c_new_aspeed 1e78a500.i2c-bus: NEW-I2C: i2c-bus [9]: adapter [100 khz] mode [2]

It could be an additional avocado test.


C.


>>           self.do_test_arm_aspeed_buidroot_start(image_path, '0xf00')
>>           exec_command_and_wait_for_pattern(self,
>>                                             'i2cget -y 15 0x4c 0xff', '0x23');
>>           exec_command_and_wait_for_pattern(self,
>>                                             'i2cget -y 15 0x4c 0xfe', '0x55');
>>
>> +        exec_command_and_wait_for_pattern(self,
>> +             'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-15/device/new_device',
>> +             'i2c i2c-15: new_device: Instantiated device ds1307 at 0x32');
>> +        year = time.strftime("%Y")
>> +        exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
>> +
>>           self.do_test_arm_aspeed_buidroot_poweroff()
>> --
>> 2.35.3
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 13/21] aspeed: Add I2C buses to AST1030 model
  2022-06-06 23:18   ` Joel Stanley
@ 2022-06-07 10:43     ` Cédric Le Goater
  0 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-07 10:43 UTC (permalink / raw)
  To: Joel Stanley
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On 6/7/22 01:18, Joel Stanley wrote:
> On Mon, 6 Jun 2022 at 15:09, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> From: Troy Lee <troy_lee@aspeedtech.com>
>>
>> Instantiate the I2C buses in AST1030 model and create two slave device
>> for ast1030-evb.
>>
>> Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>> Signed-off-by: Steven Lee <steven_lee@aspeedtech.com>
>> [ clg : - adapted to current ast1030 upstream models
>>          - fixed typo in commit log ]
>> Message-Id: <20220324100439.478317-3-troy_lee@aspeedtech.com>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> Reviewed-by: Joel Stanley <joel@jms.id.au>
> 
> one question about a comment below.
> 
>> ---
>>   hw/arm/aspeed.c         | 13 +++++++++++++
>>   hw/arm/aspeed_ast10x0.c | 18 ++++++++++++++++++
>>   2 files changed, 31 insertions(+)
>>
>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
>> index 98dc185acd9a..5c3802308e80 100644
>> --- a/hw/arm/aspeed.c
>> +++ b/hw/arm/aspeed.c
>> @@ -1401,6 +1401,18 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
>>                          AST1030_INTERNAL_FLASH_SIZE);
>>   }
>>
>> +static void ast1030_evb_i2c_init(AspeedMachineState *bmc)
>> +{
>> +    AspeedSoCState *soc = &bmc->soc;
>> +
>> +    /* U10 24C08 connects to SDA/SCL Groupt 1 by default */
>> +    uint8_t *eeprom_buf = g_malloc0(32 * 1024);
>> +    smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf);
>> +
>> +    /* U11 LM75 connects to SDA/SCL Group 2 by default */
>> +    i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4d);
>> +}
>> +
>>   static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
>>                                                             void *data)
>>   {
>> @@ -1412,6 +1424,7 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
>>       amc->hw_strap1 = 0;
>>       amc->hw_strap2 = 0;
>>       mc->init = aspeed_minibmc_machine_init;
>> +    amc->i2c_init = ast1030_evb_i2c_init;
>>       mc->default_ram_size = 0;
>>       mc->default_cpus = mc->min_cpus = mc->max_cpus = 1;
>>       amc->fmc_model = "sst25vf032b";
>> diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c
>> index d53454168403..a2ed275712fb 100644
>> --- a/hw/arm/aspeed_ast10x0.c
>> +++ b/hw/arm/aspeed_ast10x0.c
>> @@ -114,6 +114,9 @@ static void aspeed_soc_ast1030_init(Object *obj)
>>       object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1");
>>       object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2");
>>
>> +    snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
>> +    object_initialize_child(obj, "i2c", &s->i2c, typename);
>> +
>>       snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
>>       object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
>>
>> @@ -188,6 +191,21 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
>>       }
>>       sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
>>
>> +    /* I2C */
>> +
>> +    object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(&s->sram),
>> +                             &error_abort);
>> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
>> +        return;
>> +    }
>> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
>> +    for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
>> +        qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m),
>> +                                        sc->irqmap[ASPEED_DEV_I2C] + i);
>> +        /* The AST2600 I2C controller has one IRQ per bus. */
> 
> I know it's the same hardware, but is the "AST2600" part of the comment correct?

I will take care of it.

Thanks,

C.


> 
>> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
>> +    }
>> +
>>       /* LPC */
>>       if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
>>           return;
>> --
>> 2.35.3
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars
  2022-06-06 23:49   ` Joel Stanley
  2022-06-07  9:57     ` Cédric Le Goater
@ 2022-06-07 10:50     ` Cédric Le Goater
  1 sibling, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-07 10:50 UTC (permalink / raw)
  To: Joel Stanley
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

On 6/7/22 01:49, Joel Stanley wrote:
> On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> From: Joe Komlodi <komlodi@google.com>
>>
>> Using a register array will allow us to represent old-mode and new-mode
>> I2C registers by using the same underlying register array, instead of
>> adding an entire new set of variables to represent new mode.
> 
> The downside of this approach is you lose the safety of having
> discrete types. A write to s->regs[R_FOO] can overwrite R_BAR.
> 
> 
>>
>> As part of this, we also do additional cleanup to use ARRAY_FIELD_
>> macros instead of FIELD_ macros on registers.
>>
>> Signed-off-by: Joe Komlodi <komlodi@google.com>
>> Change-Id: Ib94996b17c361b8490c042b43c99d8abc69332e3
>> Message-Id: <20220331043248.2237838-5-komlodi@google.com>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>   include/hw/i2c/aspeed_i2c.h |  11 +-
>>   hw/i2c/aspeed_i2c.c         | 286 +++++++++++++++++-------------------
>>   2 files changed, 133 insertions(+), 164 deletions(-)
> 
>> @@ -858,12 +834,12 @@ static void aspeed_i2c_bus_reset(DeviceState *dev)
>>   {
>>       AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
>>
>> -    s->intr_ctrl = 0;
>> -    s->intr_status = 0;
>> -    s->cmd = 0;
>> -    s->buf = 0;
>> -    s->dma_addr = 0;
>> -    s->dma_len = 0;
>> +    s->regs[R_I2CD_INTR_CTRL] = 0;
>> +    s->regs[R_I2CD_INTR_STS] = 0;
>> +    s->regs[R_I2CD_CMD] = 0;
>> +    s->regs[R_I2CD_BYTE_BUF] = 0;
>> +    s->regs[R_I2CD_DMA_ADDR] = 0;
>> +    s->regs[R_I2CD_DMA_LEN] = 0;
> 
> Could this become a memset of s->regs?

yes. I will do it.

Thanks,

C.

> 
>>       i2c_end_transfer(s->bus);
>>   }
>>
>> @@ -921,10 +897,10 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
>>   static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
>>   {
>>       uint8_t *pool_page =
>> -        &bus->controller->pool[FIELD_EX32(bus->ctrl, I2CD_FUN_CTRL,
>> -                                          POOL_PAGE_SEL) * 0x100];
>> +        &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
>> +                                                POOL_PAGE_SEL) * 0x100];
>>
>> -    return &pool_page[FIELD_EX32(bus->pool_ctrl, I2CD_POOL_CTRL, OFFSET)];
>> +    return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
>>   }
>>
>>   static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
>> --
>> 2.35.3
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property
  2022-06-07  0:05   ` Joel Stanley
@ 2022-06-07 17:32     ` Cédric Le Goater
  0 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-07 17:32 UTC (permalink / raw)
  To: Joel Stanley
  Cc: qemu-arm, QEMU Developers, Peter Maydell, Joe Komlodi, Troy Lee,
	Jamin Lin, Steven Lee, Klaus Jensen, Peter Delevoryas,
	Corey Minyard, Jonathan Cameron, Damien Hedde, Andrew Jeffery,
	Cleber Rosa, Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

Hello Joe,

On 6/7/22 02:05, Joel Stanley wrote:
> On Mon, 6 Jun 2022 at 15:08, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> From: Joe Komlodi <komlodi@google.com>
>>
>> The Aspeed I2C controller is used across other SKUs that have different
>> reserved bits for the ctrl_global_rsvd register.
> 
> I think rsvd stands for reserved? Lets spell out the full name in the
> variable to keep it clear.
> 
> You could also call global_control_mask (or ctrl_global_mask if you
> prefer), as it's a mask of valid bits.
> 
>>
>> Signed-off-by: Joe Komlodi <komlodi@google.com>
>> Change-Id: I606c5933c527274a9d2b0afe559b2e895767636c
>> Message-Id: <20220331043248.2237838-3-komlodi@google.com>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>   include/hw/i2c/aspeed_i2c.h | 2 ++
>>   hw/arm/aspeed_ast2600.c     | 2 ++
>>   hw/i2c/aspeed_i2c.c         | 4 ++++
>>   3 files changed, 8 insertions(+)
>>
>> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
>> index 4b9be09274c7..3912fcc3ff53 100644
>> --- a/include/hw/i2c/aspeed_i2c.h
>> +++ b/include/hw/i2c/aspeed_i2c.h
>> @@ -71,6 +71,8 @@ struct AspeedI2CState {
>>       MemoryRegion pool_iomem;
>>       uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
>>
>> +    uint32_t ctrl_global_rsvd;
>> +
>>       AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
>>       MemoryRegion *dram_mr;
>>       AddressSpace dram_as;
>> diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
>> index b0a4199b6960..cc57c8b437d8 100644
>> --- a/hw/arm/aspeed_ast2600.c
>> +++ b/hw/arm/aspeed_ast2600.c
>> @@ -375,6 +375,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
>>       aspeed_soc_uart_init(s);
>>
>>       /* I2C */
>> +    object_property_set_int(OBJECT(&s->i2c), "ctrl-global-rsvd", 0xfffc3e00,
>> +                            &error_abort);
>>       object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
>>                                &error_abort);
>>       if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
>> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
>> index 03a4f5a91010..97eb9d57929c 100644
>> --- a/hw/i2c/aspeed_i2c.c
>> +++ b/hw/i2c/aspeed_i2c.c
>> @@ -648,6 +648,7 @@ static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
>>
>>       switch (offset) {
>>       case I2C_CTRL_GLOBAL:
>> +        value &= ~s->ctrl_global_rsvd;
> 
> Is there value in printing a guest error when the reserved bits are set?
> 
> If not, is it worth having this property at all? It doesn't affect the
> ability to model it.


Could you tell us more about the 0xfffc3e00 value. It doesn't match
any documents I have access to. If it is for a specific board, then
it should be added to QEMU. We can keep the property to begin with,
if that helps

Thanks,

C.


> 
>>           s->ctrl_global = value;
>>           break;
>>       case I2C_CTRL_STATUS:
>> @@ -730,6 +731,7 @@ static const VMStateDescription aspeed_i2c_vmstate = {
>>       .minimum_version_id = 2,
>>       .fields = (VMStateField[]) {
>>           VMSTATE_UINT32(intr_status, AspeedI2CState),
>> +        VMSTATE_UINT32(ctrl_global_rsvd, AspeedI2CState),
>>           VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
>>                                ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
>>                                AspeedI2CBus),
>> @@ -828,6 +830,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
>>   static Property aspeed_i2c_properties[] = {
>>       DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr,
>>                        TYPE_MEMORY_REGION, MemoryRegion *),
>> +    DEFINE_PROP_UINT32("ctrl-global-rsvd", AspeedI2CState, ctrl_global_rsvd,
>> +                       0xfffffffe),
>>       DEFINE_PROP_END_OF_LIST(),
>>   };
>>
>> --
>> 2.35.3
>>



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode
  2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
                   ` (20 preceding siblings ...)
  2022-06-06 15:07 ` [PATCH 21/21] test/avocado/machine_aspeed.py: Add I2C slave tests Cédric Le Goater
@ 2022-06-19 14:50 ` Cédric Le Goater
  21 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2022-06-19 14:50 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: Peter Maydell, Joe Komlodi, Troy Lee, Jamin Lin, Steven Lee,
	Klaus Jensen, Peter Delevoryas, Corey Minyard, Jonathan Cameron,
	Damien Hedde, Andrew Jeffery, Joel Stanley, Cleber Rosa,
	Philippe Mathieu-Daudé,
	Wainer dos Santos Moschetta, Beraldo Leal

Hello Corey,

On 6/6/22 17:07, Cédric Le Goater wrote:
> Hello,
> 
> Here is a series aggregating recent changes proposed on the Aspeed
> ast2600 I2C controller model.
> 
> First comes a large set of changes converting the model to use the
> registerfield interface and adding the I2C new register mode
> (Joe). Since this is complex to review, extra tests are added to the
> acceptance test suite to check that I2C devices are still functional
> in the ast2600-evb machine. These tests use small buildroot images
> available on GH.
> 
> The ast1030 and ast2600 SoC share the same I2C logic. This series adds
> I2C support to the ast1030 now that new register mode is supported.
> There was a previous proposal from Troy doing the same but Joe's
> patchset covers the same need (and converts the model to registerfield)
> 
> Follows a proposal from Klaus adding support for multi master in the
> I2C core and the Aspeed I2C model, for the old register mode only. The
> new register mode still needs to be addressed but this shouldn't take
> too long once old register mode is merged.
> 
> Last, I have added the I2C echo device and test provided by Klaus. I
> think it would be interesting to keep them for tests. Please, tell me.
> 
> Thanks,
> 
> C.
> 
> Cédric Le Goater (7):
>    test/avocado/machine_aspeed.py: Move OpenBMC tests
>    test/avocado/machine_aspeed.py: Add tests using buildroot images
>    test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb
>    test/avocado/machine_aspeed.py: Add an I2C RTC test
>    aspeed/i2c: Add ast1030 controller models
>    aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always
>    test/avocado/machine_aspeed.py: Add I2C slave tests
> 
> Joe Komlodi (7):
>    hw/registerfields: Add shared fields macros
>    aspeed: i2c: Add ctrl_global_rsvd property
>    aspeed: i2c: Migrate to registerfields API
>    aspeed: i2c: Use reg array instead of individual vars
>    aspeed: i2c: Add new mode support
>    aspeed: i2c: Add PKT_DONE IRQ to trace
>    aspeed: i2c: Move regs and helpers to header file
> 
> Klaus Jensen (6):
>    hw/i2c/aspeed: rework raise interrupt trace event
>    hw/i2c/aspeed: add DEV_ADDR in old register mode


>    hw/i2c: support multiple masters
>    hw/i2c: add asynchronous send
>    hw/i2c/aspeed: add slave device in old register mode


Do you think we can move forward with the above 3 patches and include
them in an Aspeed PR ? I didn't see any objection.

Thanks,

C.



>    hw/misc: add a toy i2c echo device [DO NOT PULL]
> 
> Troy Lee (1):
>    aspeed: Add I2C buses to AST1030 model
> 
>   include/hw/i2c/aspeed_i2c.h         | 299 ++++++++-
>   include/hw/i2c/i2c.h                |  30 +
>   include/hw/registerfields.h         |  70 +++
>   hw/arm/aspeed.c                     |  13 +
>   hw/arm/aspeed_ast10x0.c             |  18 +
>   hw/arm/aspeed_ast2600.c             |   2 +
>   hw/arm/pxa2xx.c                     |   2 +
>   hw/display/sii9022.c                |   2 +
>   hw/display/ssd0303.c                |   2 +
>   hw/i2c/aspeed_i2c.c                 | 901 ++++++++++++++++++----------
>   hw/i2c/core.c                       |  70 ++-
>   hw/i2c/smbus_slave.c                |   4 +
>   hw/misc/i2c-echo.c                  | 162 +++++
>   hw/nvram/eeprom_at24c.c             |   2 +
>   hw/sensor/lsm303dlhc_mag.c          |   2 +
>   hw/i2c/trace-events                 |   4 +-
>   hw/misc/meson.build                 |   2 +
>   tests/avocado/boot_linux_console.py |  43 --
>   tests/avocado/machine_aspeed.py     | 128 ++++
>   19 files changed, 1393 insertions(+), 363 deletions(-)
>   create mode 100644 hw/misc/i2c-echo.c
> 



^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2022-06-19 14:52 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-06 15:07 [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater
2022-06-06 15:07 ` [PATCH 01/21] hw/registerfields: Add shared fields macros Cédric Le Goater
2022-06-06 15:07 ` [PATCH 02/21] aspeed: i2c: Add ctrl_global_rsvd property Cédric Le Goater
2022-06-07  0:05   ` Joel Stanley
2022-06-07 17:32     ` Cédric Le Goater
2022-06-06 15:07 ` [PATCH 03/21] aspeed: i2c: Migrate to registerfields API Cédric Le Goater
2022-06-06 23:29   ` Joel Stanley
2022-06-06 15:07 ` [PATCH 04/21] aspeed: i2c: Use reg array instead of individual vars Cédric Le Goater
2022-06-06 23:49   ` Joel Stanley
2022-06-07  9:57     ` Cédric Le Goater
2022-06-07 10:50     ` Cédric Le Goater
2022-06-06 15:07 ` [PATCH 05/21] aspeed: i2c: Add new mode support Cédric Le Goater
2022-06-06 15:07 ` [PATCH 06/21] aspeed: i2c: Add PKT_DONE IRQ to trace Cédric Le Goater
2022-06-06 15:07 ` [PATCH 07/21] aspeed: i2c: Move regs and helpers to header file Cédric Le Goater
2022-06-06 15:07 ` [PATCH 08/21] test/avocado/machine_aspeed.py: Move OpenBMC tests Cédric Le Goater
2022-06-06 15:07 ` [PATCH 09/21] test/avocado/machine_aspeed.py: Add tests using buildroot images Cédric Le Goater
2022-06-06 15:07 ` [PATCH 10/21] test/avocado/machine_aspeed.py: Add I2C tests to ast2600-evb Cédric Le Goater
2022-06-06 15:07 ` [PATCH 11/21] test/avocado/machine_aspeed.py: Add an I2C RTC test Cédric Le Goater
2022-06-06 23:16   ` Joel Stanley
2022-06-07 10:17     ` Cédric Le Goater
2022-06-06 15:07 ` [PATCH 12/21] aspeed/i2c: Add ast1030 controller models Cédric Le Goater
2022-06-06 23:22   ` Joel Stanley
2022-06-06 15:07 ` [PATCH 13/21] aspeed: Add I2C buses to AST1030 model Cédric Le Goater
2022-06-06 23:18   ` Joel Stanley
2022-06-07 10:43     ` Cédric Le Goater
2022-06-06 15:07 ` [PATCH 14/21] hw/i2c/aspeed: rework raise interrupt trace event Cédric Le Goater
2022-06-06 15:07 ` [PATCH 15/21] hw/i2c/aspeed: add DEV_ADDR in old register mode Cédric Le Goater
2022-06-06 15:07 ` [PATCH 16/21] hw/i2c: support multiple masters Cédric Le Goater
2022-06-06 15:07 ` [PATCH 17/21] hw/i2c: add asynchronous send Cédric Le Goater
2022-06-06 15:07 ` [PATCH 18/21] hw/i2c/aspeed: add slave device in old register mode Cédric Le Goater
2022-06-06 15:07 ` [PATCH 19/21] aspeed/i2c: Enable SLAVE_ADDR_RX_MATCH always Cédric Le Goater
2022-06-06 15:07 ` [PATCH 20/21] hw/misc: add a toy i2c echo device [DO NOT PULL] Cédric Le Goater
2022-06-06 15:07 ` [PATCH 21/21] test/avocado/machine_aspeed.py: Add I2C slave tests Cédric Le Goater
2022-06-19 14:50 ` [PATCH 00/21] aspeed: Extend ast2600 I2C model with new mode Cédric Le Goater

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.