Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2228147/?format=api
{ "id": 2228147, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2228147/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260425131721.932250-2-joel@jms.id.au/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.1/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260425131721.932250-2-joel@jms.id.au>", "date": "2026-04-25T13:17:07", "name": "[v4,01/13] hw/i2c: Add designware i2c controller", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "0f94da5e8151598bd8ae6b31f05c7d949ae6fd90", "submitter": { "id": 48628, "url": "http://patchwork.ozlabs.org/api/1.1/people/48628/?format=api", "name": "Joel Stanley", "email": "joel@jms.id.au" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260425131721.932250-2-joel@jms.id.au/mbox/", "series": [ { "id": 501439, "url": "http://patchwork.ozlabs.org/api/1.1/series/501439/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=501439", "date": "2026-04-25T13:17:08", "name": "hw/riscv: Add the Tenstorrent Atlantis machine", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/501439/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2228147/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2228147/checks/", "tags": {}, "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=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=FysKx4gY;\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 4g2r6Z0mpXz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 25 Apr 2026 23:20:22 +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 1wGctf-00070E-AY; Sat, 25 Apr 2026 09:18:11 -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 <joel.stan@gmail.com>)\n id 1wGcta-0006zL-Sq\n for qemu-devel@nongnu.org; Sat, 25 Apr 2026 09:18:07 -0400", "from mail-pf1-x430.google.com ([2607:f8b0:4864:20::430])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <joel.stan@gmail.com>)\n id 1wGctX-0008Iq-1L\n for qemu-devel@nongnu.org; Sat, 25 Apr 2026 09:18:06 -0400", "by mail-pf1-x430.google.com with SMTP id\n d2e1a72fcca58-824c9da9928so4347414b3a.3\n for <qemu-devel@nongnu.org>; Sat, 25 Apr 2026 06:18:02 -0700 (PDT)", "from donnager-debian.. ([45.124.203.19])\n by smtp.gmail.com with ESMTPSA id\n d2e1a72fcca58-82f8e9f7735sm26898866b3a.21.2026.04.25.06.17.55\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 25 Apr 2026 06:18:00 -0700 (PDT)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1777123082; x=1777727882; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date\n :message-id:reply-to;\n bh=O2PNOHXnFoOUWyr+T/iDnnwkXlcIiAXHW2HFpCYvfWg=;\n b=FysKx4gYYgNp97gPvP3ibHr/Kg6D+ji2fb330PvuFqRrigD/wdwAzEUDvSex3SMU5D\n nTwHfnJcnz52RuP8j1cOIB/pNFnHftGzk41UGPcylIA3LEvhTi9gNo7vGHpvxKmonrjz\n nzzCwRYYPkO3xk1F3WmV8bWIC6ZVvtXDtQXrVIa+6RntKNub+RYjGGnRFHKOtB4S/RSi\n gdYM9O4mv3VM1Sg2A4UwOQ7BVntg3nC211DDmfdt6qc5yUwfLv+qA3qtW6Wa28H3KZo3\n JWpdPQ3NqPNARi1VxMmct1a1Mh0oay0CTD6QVOqsHLuOXIPOo/mBO9RmMu/4nNpbQniA\n RkJA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777123082; x=1777727882;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:sender:x-gm-gg\n :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n bh=O2PNOHXnFoOUWyr+T/iDnnwkXlcIiAXHW2HFpCYvfWg=;\n b=Ep77vmbQOVbyGbJxc3/H8l+XV0dMra+1kntpEB/+XJuenwOvYDmNequzLKNUCLg78s\n i5VjDkwqpZ+ewlCi0koQPbljknxsGZsMXqR9dH9sTLnMMjfnYqiYsiRuwLHhE68SmfM3\n faqGur8aDHkl/hCIHDJImhMZSpUjdRuXLKMWZnlgHnnB6wOuInylk2szPf1I05wUOhT/\n uGPAzDylQ6ku1pFm8+wqVDZl043cmdw5AfQ3gx4yIf2ZvCEd82i0fiq2E8z3P2zdB4HY\n 5Gr+jVw+gN9EGd+45IoZ7HlAEGs8L/O0VLyziQaSSl658ct0PqGc/sEhDl47Yw4PqrxV\n 2lgg==", "X-Forwarded-Encrypted": "i=1;\n AFNElJ9VNM9LlQYY7m4ebzAd9kO3l4eV2GmntBJ/15OmVjUy4afyOC9JZwrDssS7WnztWZazgiPpfdvjT1Fz@nongnu.org", "X-Gm-Message-State": "AOJu0YxelpGaNxWVwFtQ/919K8h7HIyqsrFcRwmb3xsSKrKRA76mDD0Q\n esRRNuMP4P3lEuxh6eMppfml1YjQ1JV5u6sATdY/auqKzuRwcUL442uw", "X-Gm-Gg": "AeBDietT7lkkAvlRZpvXNQf4ZyXGL632JE1Rp3OvM8fVvjVmaX7/gTNEBqC5qMih0/w\n F0DStt5aTBIHJTrPmAKaVfRnGc/AG+UlCrHMtlFIzkghrkXF6MKyk4W1x0j13YIm7vT7cvod2Ub\n hduNyICtdxXNfRY98V+8hiiej930NgvqnB3kEPXwt25MRlzdEXJdPg3F9voDeqjx84amegxcq9v\n 2fs1I2CH2QDIW1aMi2FvZyiApodDadyjNNwAgiv2o8E4xzbn0qOLo51g7comAe0VURPczoElpQr\n LhQvufZzhZgp7BL4JLZrduZkrsz0aZpqvrvXp3+1+6vgjHj7PQJuqEj05AT0DsrA7FCRZPlUZcO\n d/0XTcJdpAeOoIM01HSafz1Myve+C4I5KAC5qPe2eZIEKHotkbP1Oul+CvHE2gXxIUhJxxl363W\n DuXmMmF8LAHD/+kiIr67YJiI/k8MQh651eBy1rfFlZc6+Bcvz+j8YK0I9mYCs8pAR4/nExMn5ZD\n bXJUZQLZIZvsqXUt4RfCmIZvpPosDfPPXdBYnNmcoc=", "X-Received": "by 2002:aa7:8892:0:b0:82a:60ad:874 with SMTP id\n d2e1a72fcca58-82f8c8b56c0mr39116428b3a.19.1777123081387;\n Sat, 25 Apr 2026 06:18:01 -0700 (PDT)", "From": "Joel Stanley <joel@jms.id.au>", "To": "Alistair Francis <alistair.francis@wdc.com>,\n Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>", "Cc": "Chao Liu <chao.liu.zevorn@gmail.com>, Chris Rauer <crauer@google.com>,\n Michael Ellerman <mpe@kernel.org>, Nicholas Piggin <npiggin@gmail.com>,\n Joel Stanley <jms@oss.tenstorrent.com>,\n Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>,\n Portia Stephens <portias@oss.tenstorrent.com>, qemu-riscv@nongnu.org,\n qemu-devel@nongnu.org, Hao Wu <wuhaotsh@google.com>", "Subject": "[PATCH v4 01/13] hw/i2c: Add designware i2c controller", "Date": "Sat, 25 Apr 2026 23:17:07 +1000", "Message-ID": "<20260425131721.932250-2-joel@jms.id.au>", "X-Mailer": "git-send-email 2.47.3", "In-Reply-To": "<20260425131721.932250-1-joel@jms.id.au>", "References": "<20260425131721.932250-1-joel@jms.id.au>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=2607:f8b0:4864:20::430;\n envelope-from=joel.stan@gmail.com; helo=mail-pf1-x430.google.com", "X-Spam_score_int": "-16", "X-Spam_score": "-1.7", "X-Spam_bar": "-", "X-Spam_report": "(-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FORGED_FROMDOMAIN=0.001,\n FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.25,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=no 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" }, "content": "From: Chris Rauer <crauer@google.com>\n\nIn the past this model has been submitted for use with the arm virt\nmachine, however in this case it will be used by the upcoming\nTenstorrent Atlantis RISC-V machine.\n\nThis is a re-submission of the model with Chris' permission, with a\nlight touch of updates to make it build with qemu master.\n\nReviewed-by: Hao Wu <wuhaotsh@google.com>\nSigned-off-by: Chris Rauer <crauer@google.com>\nLink: 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]\nSigned-off-by: Joel Stanley <joel@jms.id.au>\n---\nv4: Remove unused random header\nv2: Add trace event for read and write, document Alano and myself as\nreviewers.\n---\n MAINTAINERS | 8 +\n include/hw/i2c/designware_i2c.h | 101 ++++\n hw/i2c/designware_i2c.c | 817 ++++++++++++++++++++++++++++++++\n hw/i2c/Kconfig | 4 +\n hw/i2c/meson.build | 1 +\n hw/i2c/trace-events | 4 +\n 6 files changed, 935 insertions(+)\n create mode 100644 include/hw/i2c/designware_i2c.h\n create mode 100644 hw/i2c/designware_i2c.c", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 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\ndiff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2c.h\nnew file mode 100644\nindex 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 */\ndiff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c\nnew file mode 100644\nindex 000000000000..7d8b1c13533e\n--- /dev/null\n+++ b/hw/i2c/designware_i2c.c\n@@ -0,0 +1,817 @@\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/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+\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+\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);\ndiff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig\nindex 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+\n config ACPI_SMBUS\n bool\n select SMBUS\ndiff --git a/hw/i2c/meson.build b/hw/i2c/meson.build\nindex c459adcb596c..88aea35662dd 100644\n--- a/hw/i2c/meson.build\n+++ b/hw/i2c/meson.build\n@@ -11,6 +11,7 @@ i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c'))\n i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c'))\n i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))\n i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))\n+i2c_ss.add(when: 'CONFIG_DESIGNWARE_I2C', if_true: files('designware_i2c.c'))\n i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))\n i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c'))\n i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))\ndiff --git a/hw/i2c/trace-events b/hw/i2c/trace-events\nindex 1ad0e95c0e60..8a78d2d3c8de 100644\n--- a/hw/i2c/trace-events\n+++ b/hw/i2c/trace-events\n@@ -61,3 +61,7 @@ pca954x_read_data(uint8_t value) \"PCA954X read data: 0x%02x\"\n \n imx_i2c_read(const char *id, const char *reg, uint64_t ofs, uint64_t value) \"%s:[%s (0x%\" PRIx64 \")] -> 0x%02\" PRIx64\n imx_i2c_write(const char *id, const char *reg, uint64_t ofs, uint64_t value) \"%s:[%s (0x%\" PRIx64 \")] <- 0x%02\" PRIx64\n+\n+# designware_i2c.c\n+dw_i2c_read(const char *id, uint64_t ofs, uint64_t value) \"%s: offset 0x%02\" PRIx64 \" -> value: 0x%02\" PRIx64\n+dw_i2c_write(const char *id, uint64_t ofs, uint64_t value) \"%s: offset: 0x%02\" PRIx64 \" <- value: 0x%02\" PRIx64\n", "prefixes": [ "v4", "01/13" ] }