[{"id":3677917,"web_url":"http://patchwork.ozlabs.org/comment/3677917/","msgid":"<CAKmqyKPpX=QTy6EVNbLDN3spnG_-oXS4wp9gWo-OPuXhMf54DA@mail.gmail.com>","list_archive_url":null,"date":"2026-04-16T03:32:20","subject":"Re: [PATCH v2] hw/i2c: Add designware i2c controller","submitter":{"id":64571,"url":"http://patchwork.ozlabs.org/api/people/64571/","name":"Alistair Francis","email":"alistair23@gmail.com"},"content":"On Wed, Apr 15, 2026 at 5:35 PM Joel Stanley <joel@jms.id.au> wrote:\n>\n> From: Chris Rauer <crauer@google.com>\n>\n> In the past this model has been submitted for use with the arm virt\n> machine, however in this case it will be used by the upcoming\n> Tenstorrent Atlantis RISC-V machine.\n>\n> This is a re-submission of the model with Chris' permission, with a\n> light touch of updates to make it build with qemu master.\n>\n> Reviewed-by: Hao Wu <wuhaotsh@google.com>\n> Signed-off-by: Chris Rauer <crauer@google.com>\n> Link: https://lore.kernel.org/qemu-devel/20220110214755.810343-2-venture@google.com\n> [jms: rebase and minor build fixes for class_init and reset callback]\n> Signed-off-by: Joel Stanley <joel@jms.id.au>\n> ---\n> v2: Add trace event for read and write, document Alano and myself as\n> reviewers.\n>\n> This supersedes my v1 submission as well as Alano's similar submission\n> from January:\n>\n>  https://lore.kernel.org/qemu-devel/20260106131253.16192-1-AlanoSong@163.com/\n>\n> ---\n>  MAINTAINERS                     |   8 +\n>  include/hw/i2c/designware_i2c.h | 101 ++++\n>  hw/i2c/designware_i2c.c         | 818 ++++++++++++++++++++++++++++++++\n>  hw/i2c/Kconfig                  |   4 +\n>  hw/i2c/meson.build              |   1 +\n>  hw/i2c/trace-events             |   4 +\n>  6 files changed, 936 insertions(+)\n>  create mode 100644 include/hw/i2c/designware_i2c.h\n>  create mode 100644 hw/i2c/designware_i2c.c\n>\n> diff --git a/MAINTAINERS b/MAINTAINERS\n> index aa4267b15806..e1942a86eba5 100644\n> --- a/MAINTAINERS\n> +++ b/MAINTAINERS\n> @@ -2716,6 +2716,14 @@ S: Orphan\n>  F: hw/gpio/pcf8574.c\n>  F: include/gpio/pcf8574.h\n>\n> +DesignWare I2C\n> +M: Chris Rauer <crauer@google.com>\n> +R: Alano Song <alanosong@163.com>\n> +R: Joel Stanley <joel@jms.id.au>\n> +S: Maintained\n> +F: hw/i2c/designware_i2c.c\n> +F: include/hw/i2c/designware_i2c.h\n> +\n>  Generic Loader\n>  M: Alistair Francis <alistair@alistair23.me>\n>  S: Maintained\n> diff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2c.h\n> new file mode 100644\n> index 000000000000..0d8f904f51b7\n> --- /dev/null\n> +++ b/include/hw/i2c/designware_i2c.h\n> @@ -0,0 +1,101 @@\n> +/*\n> + * DesignWare I2C Module.\n> + *\n> + * Copyright 2021 Google LLC\n> + *\n> + * SPDX-License-Identifier: GPL-2.0-or-later\n> + */\n> +#ifndef DESIGNWARE_I2C_H\n> +#define DESIGNWARE_I2C_H\n> +\n> +#include \"hw/i2c/i2c.h\"\n> +#include \"hw/core/irq.h\"\n> +#include \"hw/core/sysbus.h\"\n> +\n> +/* Size of the FIFO buffers. */\n> +#define DESIGNWARE_I2C_RX_FIFO_SIZE 16\n> +#define DESIGNWARE_I2C_TX_FIFO_SIZE 16\n> +\n> +typedef enum DesignWareI2CStatus {\n> +    DW_I2C_STATUS_IDLE,\n> +    DW_I2C_STATUS_SENDING_ADDRESS,\n> +    DW_I2C_STATUS_SENDING,\n> +    DW_I2C_STATUS_RECEIVING,\n> +} DesignWareI2CStatus;\n> +\n> +/*\n> + * struct DesignWareI2CState - DesignWare I2C device state.\n> + * @bus: The underlying I2C Bus\n> + * @irq: GIC interrupt line to fire on events\n> + * @ic_con: : I2C control register\n> + * @ic_tar: I2C target address register\n> + * @ic_sar: I2C slave address register\n> + * @ic_ss_scl_hcnt: Standard speed i2c clock scl high count register\n> + * @ic_ss_scl_lcnt: Standard speed i2c clock scl low count register\n> + * @ic_fs_scl_hcnt: Fast mode or fast mode plus i2c clock scl high count\n> + *                  register\n> + * @ic_fs_scl_lcnt:Fast mode or fast mode plus i2c clock scl low count\n> + *                  register\n> + * @ic_intr_mask: I2C Interrupt Mask Register\n> + * @ic_raw_intr_stat: I2C raw interrupt status register\n> + * @ic_rx_tl: I2C receive FIFO threshold register\n> + * @ic_tx_tl: I2C transmit FIFO threshold register\n> + * @ic_enable: I2C enable register\n> + * @ic_status: I2C status register\n> + * @ic_txflr: I2C transmit fifo level register\n> + * @ic_rxflr: I2C receive fifo level register\n> + * @ic_sda_hold: I2C SDA hold time length register\n> + * @ic_tx_abrt_source: The I2C transmit abort source register\n> + * @ic_sda_setup: I2C SDA setup register\n> + * @ic_enable_status: I2C enable status register\n> + * @ic_fs_spklen: I2C SS, FS or FM+ spike suppression limit\n> + * @ic_comp_param_1: Component parameter register\n> + * @ic_comp_version: I2C component version register\n> + * @ic_comp_type: I2C component type register\n> + * @rx_fifo: The FIFO buffer for receiving in FIFO mode.\n> + * @rx_cur: The current position of rx_fifo.\n> + * @status: The current status of the SMBus.\n> + */\n> +typedef struct DesignWareI2CState {\n> +    SysBusDevice parent;\n> +\n> +    MemoryRegion iomem;\n> +\n> +    I2CBus      *bus;\n> +    qemu_irq     irq;\n> +\n> +    uint32_t ic_con;\n> +    uint32_t ic_tar;\n> +    uint32_t ic_sar;\n> +    uint32_t ic_ss_scl_hcnt;\n> +    uint32_t ic_ss_scl_lcnt;\n> +    uint32_t ic_fs_scl_hcnt;\n> +    uint32_t ic_fs_scl_lcnt;\n> +    uint32_t ic_intr_mask;\n> +    uint32_t ic_raw_intr_stat;\n> +    uint32_t ic_rx_tl;\n> +    uint32_t ic_tx_tl;\n> +    uint32_t ic_enable;\n> +    uint32_t ic_status;\n> +    uint32_t ic_txflr;\n> +    uint32_t ic_rxflr;\n> +    uint32_t ic_sda_hold;\n> +    uint32_t ic_tx_abrt_source;\n> +    uint32_t ic_sda_setup;\n> +    uint32_t ic_enable_status;\n> +    uint32_t ic_fs_spklen;\n> +    uint32_t ic_comp_param_1;\n> +    uint32_t ic_comp_version;\n> +    uint32_t ic_comp_type;\n> +\n> +    uint8_t      rx_fifo[DESIGNWARE_I2C_RX_FIFO_SIZE];\n> +    uint8_t      rx_cur;\n> +\n> +    DesignWareI2CStatus status;\n> +} DesignWareI2CState;\n> +\n> +#define TYPE_DESIGNWARE_I2C \"designware-i2c\"\n> +#define DESIGNWARE_I2C(obj) OBJECT_CHECK(DesignWareI2CState, (obj), \\\n> +                                        TYPE_DESIGNWARE_I2C)\n> +\n> +#endif /* DESIGNWARE_I2C_H */\n> diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c\n> new file mode 100644\n> index 000000000000..3e0e7dab2333\n> --- /dev/null\n> +++ b/hw/i2c/designware_i2c.c\n> @@ -0,0 +1,818 @@\n> +/*\n> + * DesignWare I2C Module.\n> + *\n> + * Copyright 2021 Google LLC\n> + *\n> + * SPDX-License-Identifier: GPL-2.0-or-later\n> + */\n> +\n> +#include \"qemu/osdep.h\"\n> +\n> +#include \"hw/i2c/designware_i2c.h\"\n> +#include \"migration/vmstate.h\"\n> +#include \"qemu/bitops.h\"\n> +#include \"qemu/guest-random.h\"\n> +#include \"qemu/log.h\"\n> +#include \"qemu/module.h\"\n> +#include \"qemu/units.h\"\n> +#include \"trace.h\"\n> +\n> +enum DesignWareI2CRegister {\n> +    DW_IC_CON                   = 0x00,\n> +    DW_IC_TAR                   = 0x04,\n> +    DW_IC_SAR                   = 0x08,\n> +    DW_IC_DATA_CMD              = 0x10,\n> +    DW_IC_SS_SCL_HCNT           = 0x14,\n> +    DW_IC_SS_SCL_LCNT           = 0x18,\n> +    DW_IC_FS_SCL_HCNT           = 0x1c,\n> +    DW_IC_FS_SCL_LCNT           = 0x20,\n> +    DW_IC_INTR_STAT             = 0x2c,\n> +    DW_IC_INTR_MASK             = 0x30,\n> +    DW_IC_RAW_INTR_STAT         = 0x34,\n> +    DW_IC_RX_TL                 = 0x38,\n> +    DW_IC_TX_TL                 = 0x3c,\n> +    DW_IC_CLR_INTR              = 0x40,\n> +    DW_IC_CLR_RX_UNDER          = 0x44,\n> +    DW_IC_CLR_RX_OVER           = 0x48,\n> +    DW_IC_CLR_TX_OVER           = 0x4c,\n> +    DW_IC_CLR_RD_REQ            = 0x50,\n> +    DW_IC_CLR_TX_ABRT           = 0x54,\n> +    DW_IC_CLR_RX_DONE           = 0x58,\n> +    DW_IC_CLR_ACTIVITY          = 0x5c,\n> +    DW_IC_CLR_STOP_DET          = 0x60,\n> +    DW_IC_CLR_START_DET         = 0x64,\n> +    DW_IC_CLR_GEN_CALL          = 0x68,\n> +    DW_IC_ENABLE                = 0x6c,\n> +    DW_IC_STATUS                = 0x70,\n> +    DW_IC_TXFLR                 = 0x74,\n> +    DW_IC_RXFLR                 = 0x78,\n> +    DW_IC_SDA_HOLD              = 0x7c,\n> +    DW_IC_TX_ABRT_SOURCE        = 0x80,\n> +    DW_IC_SLV_DATA_NACK_ONLY    = 0x84,\n> +    DW_IC_DMA_CR                = 0x88,\n> +    DW_IC_DMA_TDLR              = 0x8c,\n> +    DW_IC_DMA_RDLR              = 0x90,\n> +    DW_IC_SDA_SETUP             = 0x94,\n> +    DW_IC_ACK_GENERAL_CALL      = 0x98,\n> +    DW_IC_ENABLE_STATUS         = 0x9c,\n> +    DW_IC_FS_SPKLEN             = 0xa0,\n> +    DW_IC_CLR_RESTART_DET       = 0xa8,\n> +    DW_IC_COMP_PARAM_1          = 0xf4,\n> +    DW_IC_COMP_VERSION          = 0xf8,\n> +    DW_IC_COMP_TYPE             = 0xfc,\n> +};\n\nYou should use the QEMU register format here.\n\nI saw in v1 you think that this makes it grep-able, but conforming to\nthe QEMU code style makes it easier for QEMU maintainers to review and\ncontinue maintaining the code once it's merged\n\n\n> +\n> +/* DW_IC_CON fields */\n> +#define DW_IC_CON_STOP_DET_IF_MASTER_ACTIV  BIT(10)\n> +#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL     BIT(9)\n> +#define DW_IC_CON_TX_EMPTY_CTRL             BIT(8)\n> +#define DW_IC_CON_STOP_IF_ADDRESSED         BIT(7)\n> +#define DW_IC_CON_SLAVE_DISABLE             BIT(6)\n> +#define DW_IC_CON_IC_RESTART_EN             BIT(5)\n> +#define DW_IC_CON_10BITADDR_MASTER          BIT(4)\n> +#define DW_IC_CON_10BITADDR_SLAVE           BIT(3)\n> +#define DW_IC_CON_SPEED(rv)                 extract32((rv), 1, 2)\n> +#define DW_IC_CON_MASTER_MODE               BIT(0)\n> +\n> +/* DW_IC_TAR fields */\n> +#define DW_IC_TAR_IC_10BITADDR_MASTER  BIT(12)\n> +#define DW_IC_TAR_SPECIAL              BIT(11)\n> +#define DW_IC_TAR_GC_OR_START          BIT(10)\n> +#define DW_IC_TAR_ADDRESS(rv)          extract32((rv), 0, 10)\n> +\n> +/* DW_IC_DATA_CMD fields */\n> +#define DW_IC_DATA_CMD_RESTART  BIT(10)\n> +#define DW_IC_DATA_CMD_STOP     BIT(9)\n> +#define DW_IC_DATA_CMD_CMD      BIT(8)\n> +#define DW_IC_DATA_CMD_DAT(rv)  extract32((rv), 0, 8)\n> +\n> +/* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */\n> +#define DW_IC_INTR_RESTART_DET  BIT(12)\n> +#define DW_IC_INTR_GEN_CALL     BIT(11)\n> +#define DW_IC_INTR_START_DET    BIT(10)\n> +#define DW_IC_INTR_STOP_DET     BIT(9)\n> +#define DW_IC_INTR_ACTIVITY     BIT(8)\n> +#define DW_IC_INTR_RX_DONE      BIT(7)\n> +#define DW_IC_INTR_TX_ABRT      BIT(6)\n> +#define DW_IC_INTR_RD_REQ       BIT(5)\n> +#define DW_IC_INTR_TX_EMPTY     BIT(4) /* Hardware clear only. */\n> +#define DW_IC_INTR_TX_OVER      BIT(3)\n> +#define DW_IC_INTR_RX_FULL      BIT(2) /* Hardware clear only. */\n> +#define DW_IC_INTR_RX_OVER      BIT(1)\n> +#define DW_IC_INTR_RX_UNDER     BIT(0)\n> +\n> +/* DW_IC_ENABLE fields */\n> +#define DW_IC_ENABLE_TX_CMD_BLOCK  BIT(2)\n> +#define DW_IC_ENABLE_ABORT         BIT(1)\n> +#define DW_IC_ENABLE_ENABLE        BIT(0)\n> +\n> +/* DW_IC_STATUS fields */\n> +#define DW_IC_STATUS_SLV_ACTIVITY  BIT(6)\n> +#define DW_IC_STATUS_MST_ACTIVITY  BIT(5)\n> +#define DW_IC_STATUS_RFF           BIT(4)\n> +#define DW_IC_STATUS_RFNE          BIT(3)\n> +#define DW_IC_STATUS_TFE           BIT(2)\n> +#define DW_IC_STATUS_TFNF          BIT(1)\n> +#define DW_IC_STATUS_ACTIVITY      BIT(0)\n> +\n> +/* DW_IC_TX_ABRT_SOURCE fields */\n> +#define DW_IC_TX_TX_FLUSH_CNT          extract32((rv), 23, 9)\n> +#define DW_IC_TX_ABRT_USER_ABRT        BIT(16)\n> +#define DW_IC_TX_ABRT_SLVRD_INTX       BIT(15)\n> +#define DW_IC_TX_ABRT_SLV_ARBLOST      BIT(14)\n> +#define DW_IC_TX_ABRT_SLVFLUSH_TXFIFO  BIT(13)\n> +#define DW_IC_TX_ARB_LOST              BIT(12)\n> +#define DW_IC_TX_ABRT_MASTER_DIS       BIT(11)\n> +#define DW_IC_TX_ABRT_10B_RD_NORSTRT   BIT(10)\n> +#define DW_IC_TX_ABRT_SBYTE_NORSTRT    BIT(9)\n> +#define DW_IC_TX_ABRT_HS_NORSTRT       BIT(8)\n> +#define DW_IC_TX_ABRT_SBYTE_ACKDET     BIT(7)\n> +#define DW_IC_TX_ABRT_HS_ACKDET        BIT(6)\n> +#define DW_IC_TX_ABRT_GCALL_READ       BIT(5)\n> +#define DW_IC_TX_ABRT_GCALL_NOACK      BIT(4)\n> +#define DW_IC_TX_ABRT_TXDATA_NOACK     BIT(3)\n> +#define DW_IC_TX_ABRT_10ADDR2_NOACK    BIT(2)\n> +#define DW_IC_TX_ABRT_10ADDR1_NOACK    BIT(1)\n> +#define DW_IC_TX_ABRT_7B_ADDR_NOACK    BIT(0)\n> +\n> +\n> +/* IC_ENABLE_STATUS fields */\n> +#define DW_IC_ENABLE_STATUS_SLV_RX_DATA_LOST         BIT(2)\n> +#define DW_IC_ENABLE_STATUS_SLV_DISABLED_WHILE_BUSY  BIT(1)\n> +#define DW_IC_ENABLE_STATUS_IC_EN                    BIT(0)\n> +\n> +/* Masks for writable registers. */\n> +#define DW_IC_CON_MASK          0x000003ff\n> +#define DW_IC_TAR_MASK          0x00000fff\n> +#define DW_IC_SAR_MASK          0x000003ff\n> +#define DW_IC_SS_SCL_HCNT_MASK  0x0000ffff\n> +#define DW_IC_SS_SCL_LCNT_MASK  0x0000ffff\n> +#define DW_IC_FS_SCL_HCNT_MASK  0x0000ffff\n> +#define DW_IC_FS_SCL_LCNT_MASK  0x0000ffff\n> +#define DW_IC_INTR_MASK_MASK    0x00001fff\n> +#define DW_IC_ENABLE_MASK       0x00000007\n> +#define DW_IC_SDA_HOLD_MASK     0x00ffffff\n> +#define DW_IC_SDA_SETUP_MASK    0x000000ff\n> +#define DW_IC_FS_SPKLEN_MASK    0x000000ff\n> +\n> +/* Reset values */\n> +#define DW_IC_CON_INIT_VAL          0x7d\n> +#define DW_IC_TAR_INIT_VAL          0x1055\n> +#define DW_IC_SAR_INIT_VAL          0x55\n> +#define DW_IC_SS_SCL_HCNT_INIT_VAL  0x190\n> +#define DW_IC_SS_SCL_LCNT_INIT_VAL  0x1d6\n> +#define DW_IC_FS_SCL_HCNT_INIT_VAL  0x3c\n> +#define DW_IC_FS_SCL_LCNT_INIT_VAL  0x82\n> +#define DW_IC_INTR_MASK_INIT_VAL    0x8ff\n> +#define DW_IC_STATUS_INIT_VAL       0x6\n> +#define DW_IC_SDA_HOLD_INIT_VAL     0x1\n> +#define DW_IC_SDA_SETUP_INIT_VAL    0x64\n> +#define DW_IC_FS_SPKLEN_INIT_VAL    0x2\n> +\n> +#define DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS   BIT(7)\n> +#define DW_IC_COMP_PARAM_1_HAS_DMA              0 /* bit 6 - DMA disabled. */\n> +#define DW_IC_COMP_PARAM_1_INTR_IO              BIT(5)\n> +#define DW_IC_COMP_PARAM_1_HC_COUNT_VAL         0 /* bit 4 - disabled */\n> +#define DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE      (BIT(2) | BIT(3))\n> +#define DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32    BIT(1) /* bits 0, 1 */\n> +#define DW_IC_COMP_PARAM_1_INIT_VAL             \\\n> +    (DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32 | \\\n> +    DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE | \\\n> +    DW_IC_COMP_PARAM_1_HC_COUNT_VAL | \\\n> +    DW_IC_COMP_PARAM_1_INTR_IO | \\\n> +    DW_IC_COMP_PARAM_1_HAS_DMA | \\\n> +    DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS | \\\n> +    ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1) << 8) | \\\n> +    ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1) << 16))\n> +#define DW_IC_COMP_VERSION_INIT_VAL             0x3132302a\n> +#define DW_IC_COMP_TYPE_INIT_VAL                0x44570140\n> +\n> +static void dw_i2c_update_irq(DesignWareI2CState *s)\n> +{\n> +    int level;\n> +    uint32_t intr = s->ic_raw_intr_stat & s->ic_intr_mask;\n> +\n> +    level = !!((intr & DW_IC_INTR_RX_UNDER) |\n> +        (intr & DW_IC_INTR_RX_OVER) |\n> +        (intr & DW_IC_INTR_RX_FULL) |\n> +        (intr & DW_IC_INTR_TX_OVER) |\n> +        (intr & DW_IC_INTR_TX_EMPTY) |\n> +        (intr & DW_IC_INTR_RD_REQ) |\n> +        (intr & DW_IC_INTR_TX_ABRT) |\n> +        (intr & DW_IC_INTR_RX_DONE) |\n> +        (intr & DW_IC_INTR_ACTIVITY) |\n> +        (intr & DW_IC_INTR_STOP_DET) |\n> +        (intr & DW_IC_INTR_START_DET) |\n> +        (intr & DW_IC_INTR_GEN_CALL) |\n> +        (intr & DW_IC_INTR_RESTART_DET)\n> +        );\n> +    qemu_set_irq(s->irq, level);\n> +}\n> +\n> +static uint32_t dw_i2c_read_ic_data_cmd(DesignWareI2CState *s)\n> +{\n> +    uint32_t value = s->rx_fifo[s->rx_cur];\n> +\n> +    if (s->status != DW_I2C_STATUS_RECEIVING) {\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: Attempted to read from RX fifo when not in receive \"\n> +                      \"state.\\n\", DEVICE(s)->canonical_path);\n> +        if (s->status != DW_I2C_STATUS_IDLE) {\n> +            s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_UNDER;\n> +            dw_i2c_update_irq(s);\n> +        }\n> +        return 0;\n> +    }\n> +\n> +    s->rx_cur = (s->rx_cur + 1) % DESIGNWARE_I2C_RX_FIFO_SIZE;\n> +\n> +    if (s->ic_rxflr > 0) {\n> +        s->ic_rxflr--;\n> +    } else {\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_UNDER;\n> +        dw_i2c_update_irq(s);\n> +        return 0;\n> +    }\n> +\n> +    if (s->ic_rxflr <= s->ic_rx_tl) {\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_FULL;\n> +        dw_i2c_update_irq(s);\n> +    }\n> +\n> +    return value;\n> +}\n> +\n> +static uint64_t dw_i2c_read(void *opaque, hwaddr offset, unsigned size)\n> +{\n> +    uint64_t value = 0;\n> +\n> +    DesignWareI2CState *s = opaque;\n> +\n> +    switch (offset) {\n> +    case DW_IC_CON:\n> +        value = s->ic_con;\n> +        break;\n> +    case DW_IC_TAR:\n> +        value = s->ic_tar;\n> +        break;\n> +    case DW_IC_SAR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported read - ic_sar\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        value = s->ic_sar;\n> +        break;\n> +    case DW_IC_DATA_CMD:\n> +        value = dw_i2c_read_ic_data_cmd(s);\n> +        break;\n> +    case DW_IC_SS_SCL_HCNT:\n> +        value = s->ic_ss_scl_hcnt;\n> +        break;\n> +    case DW_IC_SS_SCL_LCNT:\n> +        value = s->ic_ss_scl_lcnt;\n> +        break;\n> +    case DW_IC_FS_SCL_HCNT:\n> +        value = s->ic_fs_scl_hcnt;\n> +        break;\n> +    case DW_IC_FS_SCL_LCNT:\n> +        value = s->ic_fs_scl_lcnt;\n> +        break;\n> +    case DW_IC_INTR_STAT:\n> +        value = s->ic_raw_intr_stat & s->ic_intr_mask;\n> +        break;\n> +    case DW_IC_INTR_MASK:\n> +        value = s->ic_intr_mask;\n> +        break;\n> +    case DW_IC_RAW_INTR_STAT:\n> +        value = s->ic_raw_intr_stat;\n> +        break;\n> +    case DW_IC_RX_TL:\n> +        value = s->ic_rx_tl;\n> +        break;\n> +    case DW_IC_TX_TL:\n> +        value = s->ic_tx_tl;\n> +        break;\n> +    case DW_IC_CLR_INTR:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_GEN_CALL |\n> +            DW_IC_INTR_RESTART_DET |\n> +            DW_IC_INTR_START_DET |\n> +            DW_IC_INTR_STOP_DET |\n> +            DW_IC_INTR_ACTIVITY |\n> +            DW_IC_INTR_RX_DONE |\n> +            DW_IC_INTR_TX_ABRT |\n> +            DW_IC_INTR_RD_REQ |\n> +            DW_IC_INTR_TX_OVER |\n> +            DW_IC_INTR_RX_OVER |\n> +            DW_IC_INTR_RX_UNDER);\n> +        s->ic_tx_abrt_source = 0;\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_RX_UNDER:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_RX_UNDER);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_RX_OVER:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_RX_OVER);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_TX_OVER:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_TX_OVER);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_RD_REQ:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_RD_REQ);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_TX_ABRT:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_TX_ABRT);\n> +        s->ic_tx_abrt_source = 0;\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_RX_DONE:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_RX_DONE);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_ACTIVITY:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_ACTIVITY);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_STOP_DET:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_STOP_DET);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_START_DET:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_START_DET);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_CLR_GEN_CALL:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_GEN_CALL);\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_ENABLE:\n> +        value = s->ic_enable;\n> +        break;\n> +    case DW_IC_STATUS:\n> +        value = s->ic_status;\n> +        break;\n> +    case DW_IC_TXFLR:\n> +        value = s->ic_txflr;\n> +        break;\n> +    case DW_IC_RXFLR:\n> +        value = s->ic_rxflr;\n> +        break;\n> +    case DW_IC_SDA_HOLD:\n> +        value = s->ic_sda_hold;\n> +        break;\n> +    case DW_IC_TX_ABRT_SOURCE:\n> +        value = s->ic_tx_abrt_source;\n> +        break;\n> +    case DW_IC_SLV_DATA_NACK_ONLY:\n> +        qemu_log_mask(LOG_UNIMP,\n> +                      \"%s: unsupported read - ic_slv_data_nack_only\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_CR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported read - ic_dma_cr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_TDLR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported read - ic_dma_tdlr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_RDLR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported read - ic_dma_rdlr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_SDA_SETUP:\n> +        value = s->ic_sda_setup;\n> +        break;\n> +    case DW_IC_ACK_GENERAL_CALL:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported read - ic_ack_general_call\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_ENABLE_STATUS:\n> +        value = s->ic_enable_status;\n> +        break;\n> +    case DW_IC_FS_SPKLEN:\n> +        value = s->ic_fs_spklen;\n> +        break;\n> +    case DW_IC_CLR_RESTART_DET:\n> +        s->ic_raw_intr_stat &= ~(DW_IC_INTR_RESTART_DET);\n> +        break;\n> +    case DW_IC_COMP_PARAM_1:\n> +        value = s->ic_comp_param_1;\n> +        break;\n> +    case DW_IC_COMP_VERSION:\n> +        value = s->ic_comp_version;\n> +        break;\n> +    case DW_IC_COMP_TYPE:\n> +        value = s->ic_comp_type;\n> +        break;\n> +\n> +    /* This register is invalid at this point. */\n> +    default:\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: read from invalid offset 0x%\" HWADDR_PRIx \"\\n\",\n> +                      DEVICE(s)->canonical_path, offset);\n> +        break;\n> +    }\n> +\n> +    trace_dw_i2c_read(DEVICE(s)->canonical_path, offset, value);\n> +\n> +    return value;\n> +}\n> +\n> +static void dw_i2c_write_ic_con(DesignWareI2CState *s, uint32_t value)\n> +{\n> +    if (value & DW_IC_CON_RX_FIFO_FULL_HLD_CTRL) {\n> +        qemu_log_mask(LOG_UNIMP,\n> +                      \"%s: unsupported ic_con flag - RX_FIFO_FULL_HLD_CTRL\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +    }\n> +\n> +    if (!(s->ic_enable & DW_IC_ENABLE_ENABLE)) {\n> +        s->ic_con = value & DW_IC_CON_MASK;\n> +    } else {\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: invalid setting to ic_con %d when ic_enable[0]==1\\n\",\n> +                      DEVICE(s)->canonical_path, value);\n> +    }\n> +}\n> +\n> +static void dw_i2c_reset_to_idle(DesignWareI2CState *s)\n> +{\n> +        s->ic_enable_status &= ~DW_IC_ENABLE_STATUS_IC_EN;\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_TX_EMPTY;\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_FULL;\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_UNDER;\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_OVER;\n> +        s->ic_rxflr = 0;\n> +        s->ic_status &= ~DW_IC_STATUS_ACTIVITY;\n> +        s->status = DW_I2C_STATUS_IDLE;\n> +        dw_i2c_update_irq(s);\n> +}\n> +\n> +static void dw_ic_tx_abort(DesignWareI2CState *s, uint32_t src)\n> +{\n> +    s->ic_tx_abrt_source |= src;\n> +    s->ic_raw_intr_stat |= DW_IC_INTR_TX_ABRT;\n> +    dw_i2c_reset_to_idle(s);\n> +    dw_i2c_update_irq(s);\n> +}\n> +\n> +static void dw_i2c_write_ic_data_cmd(DesignWareI2CState *s, uint32_t value)\n> +{\n> +    int recv = !!(value & DW_IC_DATA_CMD_CMD);\n> +\n> +    if (s->status == DW_I2C_STATUS_IDLE ||\n> +        s->ic_raw_intr_stat & DW_IC_INTR_TX_ABRT) {\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: Attempted to write to TX fifo when it is held in \"\n> +                      \"reset.\\n\", DEVICE(s)->canonical_path);\n> +        return;\n> +    }\n> +\n> +    /* Send the address if it hasn't been sent yet. */\n> +    if (s->status == DW_I2C_STATUS_SENDING_ADDRESS) {\n> +        int rv = i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar), recv);\n> +        if (rv) {\n> +            dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK);\n> +            return;\n> +        }\n> +        s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;\n> +    }\n> +\n> +    /* Send data */\n> +    if (!recv) {\n> +        int rv = i2c_send(s->bus, DW_IC_DATA_CMD_DAT(value));\n> +        if (rv) {\n> +            i2c_end_transfer(s->bus);\n> +            dw_ic_tx_abort(s, DW_IC_TX_ABRT_TXDATA_NOACK);\n> +            return;\n> +        }\n> +        dw_i2c_update_irq(s);\n> +    }\n> +\n> +    /* Restart command */\n> +    if (value & DW_IC_DATA_CMD_RESTART && s->ic_con & DW_IC_CON_IC_RESTART_EN) {\n> +        s->ic_raw_intr_stat |= DW_IC_INTR_RESTART_DET |\n> +                               DW_IC_INTR_START_DET |\n> +                               DW_IC_INTR_ACTIVITY;\n> +        s->ic_status |= DW_IC_STATUS_ACTIVITY;\n> +        dw_i2c_update_irq(s);\n> +\n> +        if (i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar), recv)) {\n> +            dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK);\n> +            return;\n> +        }\n> +\n> +        s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;\n> +    }\n> +\n> +    /* Receive data */\n> +    if (recv) {\n> +        uint8_t pos = (s->rx_cur + s->ic_rxflr) % DESIGNWARE_I2C_RX_FIFO_SIZE;\n> +\n> +        if (s->ic_rxflr < DESIGNWARE_I2C_RX_FIFO_SIZE) {\n> +            s->rx_fifo[pos] = i2c_recv(s->bus);\n> +            s->ic_rxflr++;\n> +        } else {\n> +            s->ic_raw_intr_stat |= DW_IC_INTR_RX_OVER;\n> +            dw_i2c_update_irq(s);\n> +        }\n> +\n> +        if (s->ic_rxflr > s->ic_rx_tl) {\n> +            s->ic_raw_intr_stat |= DW_IC_INTR_RX_FULL;\n> +            dw_i2c_update_irq(s);\n> +        }\n> +        if (value & DW_IC_DATA_CMD_STOP) {\n> +            i2c_nack(s->bus);\n> +        }\n> +    }\n> +\n> +    /* Stop command */\n> +    if (value & DW_IC_DATA_CMD_STOP) {\n> +        s->ic_raw_intr_stat |= DW_IC_INTR_STOP_DET;\n> +        s->ic_status &= ~DW_IC_STATUS_ACTIVITY;\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_TX_EMPTY;\n> +        i2c_end_transfer(s->bus);\n> +        dw_i2c_update_irq(s);\n> +    }\n> +}\n> +\n> +static void dw_i2c_write_ic_enable(DesignWareI2CState *s, uint32_t value)\n> +{\n> +    if (value & DW_IC_ENABLE_ENABLE && !(s->ic_con & DW_IC_CON_SLAVE_DISABLE)) {\n> +        qemu_log_mask(LOG_UNIMP,\n> +                      \"%s: Designware I2C slave mode is not supported.\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        return;\n> +    }\n> +\n> +    s->ic_enable = value & DW_IC_ENABLE_MASK;\n> +\n> +    if (value & DW_IC_ENABLE_ABORT || value & DW_IC_ENABLE_TX_CMD_BLOCK) {\n> +        dw_ic_tx_abort(s, DW_IC_TX_ABRT_USER_ABRT);\n> +        return;\n> +    }\n> +\n> +    if (value & DW_IC_ENABLE_ENABLE) {\n> +        s->ic_enable_status |= DW_IC_ENABLE_STATUS_IC_EN;\n> +        s->ic_status |= DW_IC_STATUS_ACTIVITY;\n> +        s->ic_raw_intr_stat |= DW_IC_INTR_ACTIVITY |\n> +                               DW_IC_INTR_START_DET |\n> +                               DW_IC_INTR_TX_EMPTY;\n> +        s->status = DW_I2C_STATUS_SENDING_ADDRESS;\n> +        dw_i2c_update_irq(s);\n> +    } else if ((value & DW_IC_ENABLE_ENABLE) == 0) {\n> +        dw_i2c_reset_to_idle(s);\n> +    }\n> +\n> +}\n> +\n> +static void dw_i2c_write_ic_rx_tl(DesignWareI2CState *s, uint32_t value)\n> +{\n> +    /* Note that a value of 0 for ic_rx_tl indicates a threashold of 1. */\n> +    if (value > DESIGNWARE_I2C_RX_FIFO_SIZE - 1) {\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: invalid setting to ic_rx_tl %d\\n\",\n> +                      DEVICE(s)->canonical_path, value);\n> +        s->ic_rx_tl = DESIGNWARE_I2C_RX_FIFO_SIZE - 1;\n> +    } else {\n> +        s->ic_rx_tl = value;\n> +    }\n> +\n> +    if (s->ic_rxflr > s->ic_rx_tl && s->ic_enable & DW_IC_ENABLE_ENABLE) {\n> +        s->ic_raw_intr_stat |= DW_IC_INTR_RX_FULL;\n> +    } else {\n> +        s->ic_raw_intr_stat &= ~DW_IC_INTR_RX_FULL;\n> +    }\n> +    dw_i2c_update_irq(s);\n> +}\n> +\n> +static void dw_i2c_write_ic_tx_tl(DesignWareI2CState *s, uint32_t value)\n> +{\n> +    /*\n> +     * Note that a value of 0 for ic_tx_tl indicates a threashold of 1.\n> +     * However, the tx threshold is not used in the model because commands are\n> +     * always sent out as soon as they are written.\n> +     */\n> +    if (value > DESIGNWARE_I2C_TX_FIFO_SIZE - 1) {\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: invalid setting to ic_tx_tl %d\\n\",\n> +                      DEVICE(s)->canonical_path, value);\n> +        s->ic_tx_tl = DESIGNWARE_I2C_TX_FIFO_SIZE - 1;\n> +    } else {\n> +        s->ic_tx_tl = value;\n> +    }\n> +}\n> +\n> +static void dw_i2c_write(void *opaque, hwaddr offset, uint64_t value,\n> +                              unsigned size)\n> +{\n> +    DesignWareI2CState *s = opaque;\n> +\n> +    trace_dw_i2c_write(DEVICE(s)->canonical_path, offset, value);\n> +\n> +    /* The order of the registers are their order in memory. */\n> +    switch (offset) {\n> +    case DW_IC_CON:\n> +        dw_i2c_write_ic_con(s, value);\n> +        break;\n> +    case DW_IC_TAR:\n> +        s->ic_tar = value & DW_IC_TAR_MASK;\n> +        break;\n> +    case DW_IC_SAR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported write - ic_sar\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        s->ic_sar = value & DW_IC_SAR_MASK;\n> +        break;\n> +    case DW_IC_DATA_CMD:\n> +        dw_i2c_write_ic_data_cmd(s, value);\n> +        break;\n> +    case DW_IC_SS_SCL_HCNT:\n> +        s->ic_ss_scl_hcnt = value & DW_IC_SS_SCL_HCNT_MASK;\n> +        break;\n> +    case DW_IC_SS_SCL_LCNT:\n> +        s->ic_ss_scl_lcnt = value & DW_IC_SS_SCL_LCNT_MASK;\n> +        break;\n> +    case DW_IC_FS_SCL_HCNT:\n> +        s->ic_fs_scl_hcnt = value & DW_IC_FS_SCL_HCNT_MASK;\n> +        break;\n> +    case DW_IC_FS_SCL_LCNT:\n> +        s->ic_fs_scl_lcnt = value & DW_IC_FS_SCL_LCNT_MASK;\n> +        break;\n> +    case DW_IC_INTR_MASK:\n> +        s->ic_intr_mask = value & DW_IC_INTR_MASK_MASK;\n> +        dw_i2c_update_irq(s);\n> +        break;\n> +    case DW_IC_RX_TL:\n> +        dw_i2c_write_ic_rx_tl(s, value);\n> +        break;\n> +    case DW_IC_TX_TL:\n> +        dw_i2c_write_ic_tx_tl(s, value);\n> +        break;\n> +    case DW_IC_ENABLE:\n> +        dw_i2c_write_ic_enable(s, value);\n> +        break;\n> +    case DW_IC_SDA_HOLD:\n> +        s->ic_sda_hold = value & DW_IC_SDA_HOLD_MASK;\n> +        break;\n> +    case DW_IC_SLV_DATA_NACK_ONLY:\n> +        qemu_log_mask(LOG_UNIMP,\n> +                      \"%s: unsupported write - ic_slv_data_nack_only\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_CR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported write - ic_dma_cr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_TDLR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported write - ic_dma_tdlr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_DMA_RDLR:\n> +        qemu_log_mask(LOG_UNIMP, \"%s: unsupported write - ic_dma_rdlr\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_SDA_SETUP:\n> +        s->ic_sda_setup = value & DW_IC_SDA_SETUP_MASK;\n> +        break;\n> +    case DW_IC_ACK_GENERAL_CALL:\n> +        qemu_log_mask(LOG_UNIMP,\n> +                      \"%s: unsupported write - ic_ack_general_call\\n\",\n> +                      DEVICE(s)->canonical_path);\n> +        break;\n> +    case DW_IC_FS_SPKLEN:\n> +        s->ic_fs_spklen = value & DW_IC_FS_SPKLEN_MASK;\n> +        break;\n> +\n> +    /* This register is invalid at this point. */\n> +    default:\n> +        qemu_log_mask(LOG_GUEST_ERROR,\n> +                      \"%s: write to invalid offset or readonly register 0x%\"\n> +                      HWADDR_PRIx \"\\n\",\n> +                      DEVICE(s)->canonical_path, offset);\n> +        break;\n> +    }\n> +}\n> +\n> +static const MemoryRegionOps designware_i2c_ops = {\n> +    .read = dw_i2c_read,\n> +    .write = dw_i2c_write,\n> +    .endianness = DEVICE_LITTLE_ENDIAN,\n> +    .valid = {\n> +        .min_access_size = 4,\n> +        .max_access_size = 4,\n> +        .unaligned = false,\n> +    },\n> +};\n> +\n> +static void designware_i2c_enter_reset(Object *obj, ResetType type)\n> +{\n> +    DesignWareI2CState *s = DESIGNWARE_I2C(obj);\n> +\n> +    s->ic_con = DW_IC_CON_INIT_VAL;\n> +    s->ic_tar = DW_IC_TAR_INIT_VAL;\n> +    s->ic_sar = DW_IC_SAR_INIT_VAL;\n> +    s->ic_ss_scl_hcnt = DW_IC_SS_SCL_HCNT_INIT_VAL;\n> +    s->ic_ss_scl_lcnt = DW_IC_SS_SCL_LCNT_INIT_VAL;\n> +    s->ic_fs_scl_hcnt = DW_IC_FS_SCL_HCNT_INIT_VAL;\n> +    s->ic_fs_scl_lcnt = DW_IC_FS_SCL_LCNT_INIT_VAL;\n> +    s->ic_intr_mask = DW_IC_INTR_MASK_INIT_VAL;\n> +    s->ic_raw_intr_stat = 0;\n> +    s->ic_rx_tl = 0;\n> +    s->ic_tx_tl = 0;\n> +    s->ic_enable = 0;\n> +    s->ic_status = DW_IC_STATUS_INIT_VAL;\n> +    s->ic_txflr = 0;\n> +    s->ic_rxflr = 0;\n> +    s->ic_sda_hold = DW_IC_SDA_HOLD_INIT_VAL;\n> +    s->ic_tx_abrt_source = 0;\n> +    s->ic_sda_setup = DW_IC_SDA_SETUP_INIT_VAL;\n> +    s->ic_enable_status = 0;\n> +    s->ic_fs_spklen = DW_IC_FS_SPKLEN_INIT_VAL;\n> +    s->ic_comp_param_1 = DW_IC_COMP_PARAM_1_INIT_VAL;\n> +    s->ic_comp_version = DW_IC_COMP_VERSION_INIT_VAL;\n> +    s->ic_comp_type = DW_IC_COMP_TYPE_INIT_VAL;\n> +\n> +    s->rx_cur = 0;\n> +    s->status = DW_I2C_STATUS_IDLE;\n> +}\n> +\n> +static void designware_i2c_hold_reset(Object *obj, ResetType type)\n> +{\n> +    DesignWareI2CState *s = DESIGNWARE_I2C(obj);\n> +\n> +    qemu_irq_lower(s->irq);\n> +}\n> +\n> +static const VMStateDescription vmstate_designware_i2c = {\n> +    .name = TYPE_DESIGNWARE_I2C,\n> +    .version_id = 0,\n> +    .minimum_version_id = 0,\n> +    .fields = (VMStateField[]) {\n> +        VMSTATE_UINT32(ic_con, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_tar, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_sar, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_ss_scl_hcnt, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_ss_scl_lcnt, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_fs_scl_hcnt, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_fs_scl_lcnt, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_intr_mask, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_raw_intr_stat, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_rx_tl, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_tx_tl, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_enable, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_status, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_txflr, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_rxflr, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_sda_hold, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_tx_abrt_source, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_sda_setup, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_enable_status, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_fs_spklen, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_comp_param_1, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_comp_version, DesignWareI2CState),\n> +        VMSTATE_UINT32(ic_comp_type, DesignWareI2CState),\n> +        VMSTATE_UINT32(status, DesignWareI2CState),\n> +        VMSTATE_UINT8_ARRAY(rx_fifo, DesignWareI2CState,\n> +                        DESIGNWARE_I2C_RX_FIFO_SIZE),\n> +        VMSTATE_UINT8(rx_cur, DesignWareI2CState),\n> +        VMSTATE_END_OF_LIST(),\n> +    },\n> +};\n> +\n> +static void designware_i2c_smbus_init(Object *obj)\n> +{\n> +    DesignWareI2CState *s = DESIGNWARE_I2C(obj);\n> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);\n> +\n> +    sysbus_init_irq(sbd, &s->irq);\n> +\n> +    memory_region_init_io(&s->iomem, obj, &designware_i2c_ops, s,\n> +                          \"regs\", 4 * KiB);\n> +    sysbus_init_mmio(sbd, &s->iomem);\n> +\n> +    s->bus = i2c_init_bus(DEVICE(s), \"i2c-bus\");\n> +}\n\nWhat's the plan for using this device? It will need to be used before\nit can be merged\n\n> +\n> +static void designware_i2c_class_init(ObjectClass *klass, const void *data)\n> +{\n> +    ResettableClass *rc = RESETTABLE_CLASS(klass);\n> +    DeviceClass *dc = DEVICE_CLASS(klass);\n> +\n> +    dc->desc = \"Designware I2C\";\n> +    dc->vmsd = &vmstate_designware_i2c;\n> +    rc->phases.enter = designware_i2c_enter_reset;\n> +    rc->phases.hold = designware_i2c_hold_reset;\n> +}\n> +\n> +static const TypeInfo designware_i2c_types[] = {\n> +    {\n> +        .name = TYPE_DESIGNWARE_I2C,\n> +        .parent = TYPE_SYS_BUS_DEVICE,\n> +        .instance_size = sizeof(DesignWareI2CState),\n> +        .class_init = designware_i2c_class_init,\n> +        .instance_init = designware_i2c_smbus_init,\n> +    },\n> +};\n> +DEFINE_TYPES(designware_i2c_types);\n> diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig\n> index 596a7a3165ad..d3f394edeb9c 100644\n> --- a/hw/i2c/Kconfig\n> +++ b/hw/i2c/Kconfig\n> @@ -18,6 +18,10 @@ config ARM_SBCON_I2C\n>      bool\n>      select BITBANG_I2C\n>\n> +config DESIGNWARE_I2C\n> +    bool\n> +    select I2C\n\nNothing selects `DESIGNWARE_I2C` though, so this won't be enabled.\nAFAIK this new code won't even be built by default or as part of the\nCI\n\nWe need something to use the hardware.\n\nAlistair","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=my7ZGLG8;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fx3XK5Kj2z1yG9\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 13:34:08 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wDDTU-0002Xq-Mp; Wed, 15 Apr 2026 23:33:05 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <alistair23@gmail.com>)\n id 1wDDTQ-0002XL-EZ\n for qemu-devel@nongnu.org; Wed, 15 Apr 2026 23:33:00 -0400","from mail-ej1-x62b.google.com ([2a00:1450:4864:20::62b])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <alistair23@gmail.com>)\n id 1wDDTL-0000GF-D7\n for qemu-devel@nongnu.org; Wed, 15 Apr 2026 23:33:00 -0400","by mail-ej1-x62b.google.com with SMTP id\n a640c23a62f3a-b97f9587e6eso1051613366b.3\n for <qemu-devel@nongnu.org>; Wed, 15 Apr 2026 20:32:49 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; t=1776310369; cv=none;\n d=google.com; s=arc-20240605;\n b=FUbRJD2XDn+f1Pw7QoW74nGG69EMbMLyuHy7WvlORno6tGhcOqU//D+0o2SZismhbX\n pd2ob1gg16QqGynQdTIfuucGiz7OHQOevpCUM2paAq6ZBaVpXgUTYQCGnyoTBeVkoMZ/\n 9XjtSEddUKpoC5KLQhf3M+M/vxH7gTVupmBFf4y0X6wiVYz3GsD4AjdmRErWH/WOzITw\n 0BPQP5dmGhwiC/YviehrZu5PUasGD94t61dtWBrgyRYz6vhUU6Z4ikJiHByxghHQ1PGh\n xvcG/zkjNKj4jZSy67qQmhlWqsQnesstUai/+K4LG0l0RYi9Pbop27OmcLF8s8FlrEVg\n pJQg==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:dkim-signature;\n bh=NTAeosnvgUeuIaBh+ACliR2hh4HGoxDwFbAFEdQKkiI=;\n fh=z5WscUWt45g5r97yIz0//ryVeGShS8Vc9nQC40+rJBU=;\n b=DQtf6sIwYL4QwAjOkqShHSRP7abygreHK1Tkv6h508O36GSrkk+U1UyLzFwwM3gAd9\n h2HG3n/Lufkw62+n6t9LPjXPZ7ruW9/dthLDyfQZkQFdjtSdh1JwrVw6nXVVRFJklyp1\n 3xEWZaLHxgo7XpwUMwtBbXdvR8KZYLowBJUQjntThXq1WtyHfDvIrLZEYF3nmkzl7vyT\n KeGxFtzI2qEqgTuNyAv2ltWkfSVW2VlYhuJd2g+XTn9vAq1eWVQ1FjfF1+xzGIL+2a6P\n 45nQLnV2a+yuDsm0ZCIakxnCsyLDJukwkZAVg3dGOaujcUTLiJIb726/h0Du6EiUv//p\n fnRQ==; darn=nongnu.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1776310369; x=1776915169; darn=nongnu.org;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:from:to:cc:subject:date\n :message-id:reply-to;\n bh=NTAeosnvgUeuIaBh+ACliR2hh4HGoxDwFbAFEdQKkiI=;\n b=my7ZGLG81P9WM57wKafHju5eckXaPxvh2gWtMLJxjmgrvK2IBpLz3+lNTBfIECWg/X\n 3X2s4tkxRfypmb3BNAQy10uk6bTryurnZ0ukpn7AhgazYQF55YYtFg3S7FzCrI9QQclk\n irjwtqgLkfvEdV2Kd1PTnr4EIbJopTFLLtf+Qw9Ub2eZfKBzz2Zst3xjsJLfwxfd2zZ4\n NfzFC/sbf0VqUbaKRrrk0ZDf9XNlaYdRp16TZ/ItSocMm8Kbx/XN0EnH/kth9qnkZc5Q\n vJGgoWs7/gghKLDs7Jon6+SuCrNX/0Wr59IC0FAo0evz+PNyLGEyJkL0MeKTp1lnhncb\n sXsg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776310369; x=1776915169;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=NTAeosnvgUeuIaBh+ACliR2hh4HGoxDwFbAFEdQKkiI=;\n b=Q5CnGSq6DWx4uuU78aBByVYknPgSSrlna7F0JSh8NANW8szUyJwaYf5Vqhjvs80gGA\n rBKtlVntDEn0g85vOTpVTgDf1eLGacBjVh70BNWZi7QkNxgK0LmL8W9M8X+5m/sPuLeK\n VWnpzcYuh+FHLV6FbT6fhISajQouGgJsmWISNSr6LHn4M4tyla9mEPrahJxtNRWC2hNd\n /Y5uKBOHOJ92ONcTdtVW2vSCmdHDy9hHqTp9H4bOq0UN30GvHhT8ORVrEle/Z2FzrQNJ\n tq7AXONuFKtXhiWjY0Ey+fkJwzdrN4xruUmkFuKiU4TTAGg5V35jEeXDmK/hQgab9Mb8\n 2ssA==","X-Gm-Message-State":"AOJu0YypeMJuStH2/bUSZlxSPf6Eve1jocYv4woAUBgXn9L+YH/VVgGn\n DpiGPvH0kG1ovYlwmh2kkXtwMXB9XBW8fPRk2xB0GfMs8KhASWMJiu9hSg16Eo6fUS48uH39y0q\n qXfFb/sLgELuSHsx22JKGBjSZ8uEZ2oY=","X-Gm-Gg":"AeBDievVWCT7HUtjJ1O8NMbxdA8sJpVCA1cRdV+1BVJRlfe1hdPA1c7UaHoo3oXEh1b\n ytd7AoLtWZQiq9q9f+6Y11qytc/cxuDvbdnHeCCQW7v+gZtLmZbOGalgy8eWGKaI4loPFAD7Fbn\n IqN1/uThfBUOsqRMOlMNylqkUr9UhxasyTfTK32nHYCXedkytptgN8xEBrbe50H7ZFXb7BfweZQ\n reWtlvYv0CTYI236luudVQnPUfNeor6D4hJKuUIzsvG1iAuR29z918LmNJVtQN/ckxK5d2xARH+\n unfdj2bNVK0UZEUD2CtGvmC/b46PeoEVtrGWYQ==","X-Received":"by 2002:a17:907:961c:b0:b9b:308f:d9ad with SMTP id\n a640c23a62f3a-b9d7260e804mr1308794766b.19.1776310368338; Wed, 15 Apr 2026\n 20:32:48 -0700 (PDT)","MIME-Version":"1.0","References":"<20260415073341.690754-1-joel@jms.id.au>","In-Reply-To":"<20260415073341.690754-1-joel@jms.id.au>","From":"Alistair Francis <alistair23@gmail.com>","Date":"Thu, 16 Apr 2026 13:32:20 +1000","X-Gm-Features":"AQROBzDJj1vNK_fmkEMxFVS_2ricxE_cbJu4RVV4LRBc95yk_t9A1TQARinKwTg","Message-ID":"\n <CAKmqyKPpX=QTy6EVNbLDN3spnG_-oXS4wp9gWo-OPuXhMf54DA@mail.gmail.com>","Subject":"Re: [PATCH v2] hw/i2c: Add designware i2c controller","To":"Joel Stanley <joel@jms.id.au>","Cc":"qemu-devel@nongnu.org, Alistair Francis <alistair.francis@wdc.com>,\n Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>,\n Chris Rauer <crauer@google.com>,\n Paolo Bonzini <pbonzini@redhat.com>, Alano Song <alanosong@163.com>,\n qemu-riscv@nongnu.org, Hao Wu <wuhaotsh@google.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","Received-SPF":"pass client-ip=2a00:1450:4864:20::62b;\n envelope-from=alistair23@gmail.com; helo=mail-ej1-x62b.google.com","X-Spam_score_int":"-17","X-Spam_score":"-1.8","X-Spam_bar":"-","X-Spam_report":"(-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"}}]