From nobody Sat May 30 16:35:39 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778155629; cv=none; d=zohomail.com; s=zohoarc; b=GdHvE5rkitVgjRTaILUJRwnexp/uk85qacCGk5PkJXOHDW0RpDyGxnSgcj90OYx73ccrpyrlgvXUWv0wNeP28IqKMFgMBuTvnibBg17WELfMNWzItYBHFx9+IBMT7Zp/6FnwloPzchu79JQh+gvvrbUe0R7UgmT6oHgHx+z9JaI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778155629; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=VV7TTrYiMWvq+Wx8vvctSGzKHLoz6KzY4t2o0/Obpxk=; b=nJ2CfdNaZM5abHsNdo+pJn/qe7eWLK/e8FufwQ9xfPMwWM6/iFsppnBmqbV994IeA966C+9kAoKPWlrEARDbNIPZAdUjskoZTd3iSu9/xAPzn7f/SmDrijwW4iiiNmckL6LfvWsAMO3/wDTRgOmm+P2L/lfsRqgW6CqCfQzIUuQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778155629219255.72865085901253; Thu, 7 May 2026 05:07:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wKxUP-0008VK-E9; Thu, 07 May 2026 08:06:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wKxUA-0008So-RE for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:49 -0400 Received: from mail-pj1-x102e.google.com ([2607:f8b0:4864:20::102e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wKxU6-0002Af-8u for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:46 -0400 Received: by mail-pj1-x102e.google.com with SMTP id 98e67ed59e1d1-365cae89bf5so333865a91.3 for ; Thu, 07 May 2026 05:05:41 -0700 (PDT) Received: from localhost (124.158.97.178.qld.leaptel.network. [124.158.97.178]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-366347008c7sm252763a91.6.2026.05.07.05.05.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 05:05:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778155541; x=1778760341; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=VV7TTrYiMWvq+Wx8vvctSGzKHLoz6KzY4t2o0/Obpxk=; b=bswXtDButby1XifqlZ8BkuLVojl6iOSN7oZUUgoLucA5mLFunkCRGbdY1AUwuEjeY+ upKSlxXmWc8jvkKuYYMF6yLf2aprzIM0lEoRwEnXHkdCNSwSq0C4mUqDXV02BTTQ1gUR eredSiK7agPMbIGQVjGV3qDlxhzxugHUaWg6ul/w7n68vzcG7E4X2SS7TzLySmS8TdfR Xnkj5SB5Jdev2yz0Y7hkurYri785RPJtLFQfp89h4KHite1RF9h/XGju3uIEqfVbmtgL ngMN5tsf7JiuQXfeOxwU7ce25nCg2VZU8q5YJ28AzezOvDoUrgC9ALTSkW6MefVl0PfH OMcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778155541; x=1778760341; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=VV7TTrYiMWvq+Wx8vvctSGzKHLoz6KzY4t2o0/Obpxk=; b=cZe/bJBzmll8aM0HrO2hlqQD/d5g9/V7t2ooL9fC7DkudVw6tg7wMpDNZpzmeaveYr ZQa10+Wbcnihlx29HmFPSorWb7GvlLB62q7NDZfdQtZFOKeWXm6ocLKr7TK1081Rd67G wEFmQwsEhBlyIDgmw+7+NZLL2yR0ki1Khb3s+kEHok/uW3T8mSt4wQCnXpqlEtFgxWAp /GUpBQ51Uqgfh5f55UrCAy2C+zkcP6G5523mGJ7k9SSCQrspquxMdc14ukFJHh0BiVZI 3xyGbT7h5Cr8qsE5HKsv47zpWGgCqLAi4JXkxDjZck5zvOkwCkficNpl0vI6eRkdyyBt ETvw== X-Forwarded-Encrypted: i=1; AFNElJ85qbq35QH5gf+TxDsuzfg89XQp7qOOPs0fy9f4aFBleSmen43fmsshCtdHzLWF7K69LOmbOIeax0PQ@nongnu.org X-Gm-Message-State: AOJu0YybE1r1cNzIPdEhsOPR/3E6YO8OmqWviFtEmr5wplHxV5IMNVeZ RMjjpfJcEkWVNgVn5GXYYHbQC1vuQN+fjhJJSQC9CbQrXA90zf71HMzd X-Gm-Gg: AeBDieteI+DWiswO31xifTMIUDZOmde/95AhjN2Rdvnww5tH4r2uv30TxdBkKjol9Kw EWkPiKDnO1UnLyn0/rC/Esgx+SvZ3VfZGdNDlJ1wSts1er1KA4HXzqjHCqinRC9hDW9GGCizLYn TNQtAaoo5eeTVn+rsSOFW+x/lWNobTqeZLTH41MmkbGvFjsyc3pYDbFIur4mNywMwVfbYBrbUM9 yD96V8NEYft9Nn941BxgYsHml5j2k9TrN+7sm8Q/2ShLbQRlPy7IrEYcx98n3gnULMqIno5ktxm GmXR/ThJhFviOCGeuSXWxFUz5PzZNmUmAgRjfp4lwhGJYK0mqz7cRN+C6rSVKAfZWrATLcM+XYx bT04mSeskkMQIWzgx6Mhj/V84TzxkL4wfmimvUx90C9Be3UUlwwvFlKvgBNzNDUkB6pBd1UmxZM EJGbU6PfkL3TFXB94d59un0g1Q6PGxignU3ZwomMQiH/bvFD7QGNY17ohvC+K4K86fWydXnQHzJ VDYPwCF X-Received: by 2002:a17:90b:3d08:b0:35b:e4f8:7cb0 with SMTP id 98e67ed59e1d1-365ac47cf68mr8287110a91.21.1778155539609; Thu, 07 May 2026 05:05:39 -0700 (PDT) From: Nicholas Piggin To: Corey Minyard Cc: Nicholas Piggin , Alistair Francis , Daniel Henrique Barboza , Chao Liu , Chris Rauer , Michael Ellerman , Joel Stanley , Anirudh Srinivasan , Portia Stephens , qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Hao Wu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Joel Stanley Subject: [PATCH 1/4] hw/i2c: Add designware i2c controller Date: Thu, 7 May 2026 22:05:19 +1000 Message-ID: <20260507120524.111056-2-npiggin@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260507120524.111056-1-npiggin@gmail.com> References: <20260507120524.111056-1-npiggin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::102e; envelope-from=npiggin@gmail.com; helo=mail-pj1-x102e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1778155631576158500 Content-Type: text/plain; charset="utf-8" From: Chris Rauer In the past this model has been submitted for use with the arm virt machine, however in this case it will be used by the upcoming Tenstorrent Atlantis RISC-V machine. This is a re-submission of the model with Chris' permission, with a light touch of updates to make it build with qemu master. Reviewed-by: Hao Wu Signed-off-by: Chris Rauer Link: https://lore.kernel.org/qemu-devel/20220110214755.810343-2-venture@go= ogle.com [jms: rebase and minor build fixes for class_init and reset callback] Signed-off-by: Joel Stanley Signed-off-by: Nicholas Piggin Acked-by: Alistair Francis Acked-by: Corey Minyard Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- Changes since posting in v4 of the TT Atlantis series, thanks to Phil for comments: - Fix setting of underflow interrupt bit - Recalculate irq state after clearing RESTART_DET interrupt bit - Add .impl attributes to register MMIO ops - Set DEVICE_CATEGORY_BRIDGE - Fix 'parent_obj' naming - constify VMState fields Thanks, Nick --- MAINTAINERS | 8 + hw/i2c/Kconfig | 4 + hw/i2c/designware_i2c.c | 824 ++++++++++++++++++++++++++++++++ hw/i2c/meson.build | 1 + hw/i2c/trace-events | 4 + include/hw/i2c/designware_i2c.h | 101 ++++ roms/seabios-hppa | 2 +- 7 files changed, 943 insertions(+), 1 deletion(-) create mode 100644 hw/i2c/designware_i2c.c create mode 100644 include/hw/i2c/designware_i2c.h diff --git a/MAINTAINERS b/MAINTAINERS index e106cadb81..8df2464aa0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2716,6 +2716,14 @@ S: Orphan F: hw/gpio/pcf8574.c F: include/gpio/pcf8574.h =20 +DesignWare I2C +M: Chris Rauer +R: Alano Song +R: Joel Stanley +S: Maintained +F: hw/i2c/designware_i2c.c +F: include/hw/i2c/designware_i2c.h + Generic Loader M: Alistair Francis S: Maintained diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 596a7a3165..d3f394edeb 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -18,6 +18,10 @@ config ARM_SBCON_I2C bool select BITBANG_I2C =20 +config DESIGNWARE_I2C + bool + select I2C + config ACPI_SMBUS bool select SMBUS diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c new file mode 100644 index 0000000000..1e5505f571 --- /dev/null +++ b/hw/i2c/designware_i2c.c @@ -0,0 +1,824 @@ +/* + * DesignWare I2C Module. + * + * Copyright 2021 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "hw/i2c/designware_i2c.h" +#include "migration/vmstate.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "trace.h" + +enum DesignWareI2CRegister { + DW_IC_CON =3D 0x00, + DW_IC_TAR =3D 0x04, + DW_IC_SAR =3D 0x08, + DW_IC_DATA_CMD =3D 0x10, + DW_IC_SS_SCL_HCNT =3D 0x14, + DW_IC_SS_SCL_LCNT =3D 0x18, + DW_IC_FS_SCL_HCNT =3D 0x1c, + DW_IC_FS_SCL_LCNT =3D 0x20, + DW_IC_INTR_STAT =3D 0x2c, + DW_IC_INTR_MASK =3D 0x30, + DW_IC_RAW_INTR_STAT =3D 0x34, + DW_IC_RX_TL =3D 0x38, + DW_IC_TX_TL =3D 0x3c, + DW_IC_CLR_INTR =3D 0x40, + DW_IC_CLR_RX_UNDER =3D 0x44, + DW_IC_CLR_RX_OVER =3D 0x48, + DW_IC_CLR_TX_OVER =3D 0x4c, + DW_IC_CLR_RD_REQ =3D 0x50, + DW_IC_CLR_TX_ABRT =3D 0x54, + DW_IC_CLR_RX_DONE =3D 0x58, + DW_IC_CLR_ACTIVITY =3D 0x5c, + DW_IC_CLR_STOP_DET =3D 0x60, + DW_IC_CLR_START_DET =3D 0x64, + DW_IC_CLR_GEN_CALL =3D 0x68, + DW_IC_ENABLE =3D 0x6c, + DW_IC_STATUS =3D 0x70, + DW_IC_TXFLR =3D 0x74, + DW_IC_RXFLR =3D 0x78, + DW_IC_SDA_HOLD =3D 0x7c, + DW_IC_TX_ABRT_SOURCE =3D 0x80, + DW_IC_SLV_DATA_NACK_ONLY =3D 0x84, + DW_IC_DMA_CR =3D 0x88, + DW_IC_DMA_TDLR =3D 0x8c, + DW_IC_DMA_RDLR =3D 0x90, + DW_IC_SDA_SETUP =3D 0x94, + DW_IC_ACK_GENERAL_CALL =3D 0x98, + DW_IC_ENABLE_STATUS =3D 0x9c, + DW_IC_FS_SPKLEN =3D 0xa0, + DW_IC_CLR_RESTART_DET =3D 0xa8, + DW_IC_COMP_PARAM_1 =3D 0xf4, + DW_IC_COMP_VERSION =3D 0xf8, + DW_IC_COMP_TYPE =3D 0xfc, +}; + +/* DW_IC_CON fields */ +#define DW_IC_CON_STOP_DET_IF_MASTER_ACTIV BIT(10) +#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) +#define DW_IC_CON_TX_EMPTY_CTRL BIT(8) +#define DW_IC_CON_STOP_IF_ADDRESSED BIT(7) +#define DW_IC_CON_SLAVE_DISABLE BIT(6) +#define DW_IC_CON_IC_RESTART_EN BIT(5) +#define DW_IC_CON_10BITADDR_MASTER BIT(4) +#define DW_IC_CON_10BITADDR_SLAVE BIT(3) +#define DW_IC_CON_SPEED(rv) extract32((rv), 1, 2) +#define DW_IC_CON_MASTER_MODE BIT(0) + +/* DW_IC_TAR fields */ +#define DW_IC_TAR_IC_10BITADDR_MASTER BIT(12) +#define DW_IC_TAR_SPECIAL BIT(11) +#define DW_IC_TAR_GC_OR_START BIT(10) +#define DW_IC_TAR_ADDRESS(rv) extract32((rv), 0, 10) + +/* DW_IC_DATA_CMD fields */ +#define DW_IC_DATA_CMD_RESTART BIT(10) +#define DW_IC_DATA_CMD_STOP BIT(9) +#define DW_IC_DATA_CMD_CMD BIT(8) +#define DW_IC_DATA_CMD_DAT(rv) extract32((rv), 0, 8) + +/* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */ +#define DW_IC_INTR_RESTART_DET BIT(12) +#define DW_IC_INTR_GEN_CALL BIT(11) +#define DW_IC_INTR_START_DET BIT(10) +#define DW_IC_INTR_STOP_DET BIT(9) +#define DW_IC_INTR_ACTIVITY BIT(8) +#define DW_IC_INTR_RX_DONE BIT(7) +#define DW_IC_INTR_TX_ABRT BIT(6) +#define DW_IC_INTR_RD_REQ BIT(5) +#define DW_IC_INTR_TX_EMPTY BIT(4) /* Hardware clear only. */ +#define DW_IC_INTR_TX_OVER BIT(3) +#define DW_IC_INTR_RX_FULL BIT(2) /* Hardware clear only. */ +#define DW_IC_INTR_RX_OVER BIT(1) +#define DW_IC_INTR_RX_UNDER BIT(0) + +/* DW_IC_ENABLE fields */ +#define DW_IC_ENABLE_TX_CMD_BLOCK BIT(2) +#define DW_IC_ENABLE_ABORT BIT(1) +#define DW_IC_ENABLE_ENABLE BIT(0) + +/* DW_IC_STATUS fields */ +#define DW_IC_STATUS_SLV_ACTIVITY BIT(6) +#define DW_IC_STATUS_MST_ACTIVITY BIT(5) +#define DW_IC_STATUS_RFF BIT(4) +#define DW_IC_STATUS_RFNE BIT(3) +#define DW_IC_STATUS_TFE BIT(2) +#define DW_IC_STATUS_TFNF BIT(1) +#define DW_IC_STATUS_ACTIVITY BIT(0) + +/* DW_IC_TX_ABRT_SOURCE fields */ +#define DW_IC_TX_TX_FLUSH_CNT extract32((rv), 23, 9) +#define DW_IC_TX_ABRT_USER_ABRT BIT(16) +#define DW_IC_TX_ABRT_SLVRD_INTX BIT(15) +#define DW_IC_TX_ABRT_SLV_ARBLOST BIT(14) +#define DW_IC_TX_ABRT_SLVFLUSH_TXFIFO BIT(13) +#define DW_IC_TX_ARB_LOST BIT(12) +#define DW_IC_TX_ABRT_MASTER_DIS BIT(11) +#define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(10) +#define DW_IC_TX_ABRT_SBYTE_NORSTRT BIT(9) +#define DW_IC_TX_ABRT_HS_NORSTRT BIT(8) +#define DW_IC_TX_ABRT_SBYTE_ACKDET BIT(7) +#define DW_IC_TX_ABRT_HS_ACKDET BIT(6) +#define DW_IC_TX_ABRT_GCALL_READ BIT(5) +#define DW_IC_TX_ABRT_GCALL_NOACK BIT(4) +#define DW_IC_TX_ABRT_TXDATA_NOACK BIT(3) +#define DW_IC_TX_ABRT_10ADDR2_NOACK BIT(2) +#define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(1) +#define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(0) + + +/* IC_ENABLE_STATUS fields */ +#define DW_IC_ENABLE_STATUS_SLV_RX_DATA_LOST BIT(2) +#define DW_IC_ENABLE_STATUS_SLV_DISABLED_WHILE_BUSY BIT(1) +#define DW_IC_ENABLE_STATUS_IC_EN BIT(0) + +/* Masks for writable registers. */ +#define DW_IC_CON_MASK 0x000003ff +#define DW_IC_TAR_MASK 0x00000fff +#define DW_IC_SAR_MASK 0x000003ff +#define DW_IC_SS_SCL_HCNT_MASK 0x0000ffff +#define DW_IC_SS_SCL_LCNT_MASK 0x0000ffff +#define DW_IC_FS_SCL_HCNT_MASK 0x0000ffff +#define DW_IC_FS_SCL_LCNT_MASK 0x0000ffff +#define DW_IC_INTR_MASK_MASK 0x00001fff +#define DW_IC_ENABLE_MASK 0x00000007 +#define DW_IC_SDA_HOLD_MASK 0x00ffffff +#define DW_IC_SDA_SETUP_MASK 0x000000ff +#define DW_IC_FS_SPKLEN_MASK 0x000000ff + +/* Reset values */ +#define DW_IC_CON_INIT_VAL 0x7d +#define DW_IC_TAR_INIT_VAL 0x1055 +#define DW_IC_SAR_INIT_VAL 0x55 +#define DW_IC_SS_SCL_HCNT_INIT_VAL 0x190 +#define DW_IC_SS_SCL_LCNT_INIT_VAL 0x1d6 +#define DW_IC_FS_SCL_HCNT_INIT_VAL 0x3c +#define DW_IC_FS_SCL_LCNT_INIT_VAL 0x82 +#define DW_IC_INTR_MASK_INIT_VAL 0x8ff +#define DW_IC_STATUS_INIT_VAL 0x6 +#define DW_IC_SDA_HOLD_INIT_VAL 0x1 +#define DW_IC_SDA_SETUP_INIT_VAL 0x64 +#define DW_IC_FS_SPKLEN_INIT_VAL 0x2 + +#define DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS BIT(7) +#define DW_IC_COMP_PARAM_1_HAS_DMA 0 /* bit 6 - DMA disabled.= */ +#define DW_IC_COMP_PARAM_1_INTR_IO BIT(5) +#define DW_IC_COMP_PARAM_1_HC_COUNT_VAL 0 /* bit 4 - disabled */ +#define DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE (BIT(2) | BIT(3)) +#define DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32 BIT(1) /* bits 0, 1 */ +#define DW_IC_COMP_PARAM_1_INIT_VAL \ + (DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32 | \ + DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE | \ + DW_IC_COMP_PARAM_1_HC_COUNT_VAL | \ + DW_IC_COMP_PARAM_1_INTR_IO | \ + DW_IC_COMP_PARAM_1_HAS_DMA | \ + DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS | \ + ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1) << 8) | \ + ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1) << 16)) +#define DW_IC_COMP_VERSION_INIT_VAL 0x3132302a +#define DW_IC_COMP_TYPE_INIT_VAL 0x44570140 + +static void dw_i2c_update_irq(DesignWareI2CState *s) +{ + int level; + uint32_t intr =3D s->ic_raw_intr_stat & s->ic_intr_mask; + + level =3D !!((intr & DW_IC_INTR_RX_UNDER) | + (intr & DW_IC_INTR_RX_OVER) | + (intr & DW_IC_INTR_RX_FULL) | + (intr & DW_IC_INTR_TX_OVER) | + (intr & DW_IC_INTR_TX_EMPTY) | + (intr & DW_IC_INTR_RD_REQ) | + (intr & DW_IC_INTR_TX_ABRT) | + (intr & DW_IC_INTR_RX_DONE) | + (intr & DW_IC_INTR_ACTIVITY) | + (intr & DW_IC_INTR_STOP_DET) | + (intr & DW_IC_INTR_START_DET) | + (intr & DW_IC_INTR_GEN_CALL) | + (intr & DW_IC_INTR_RESTART_DET) + ); + qemu_set_irq(s->irq, level); +} + +static uint32_t dw_i2c_read_ic_data_cmd(DesignWareI2CState *s) +{ + uint32_t value =3D s->rx_fifo[s->rx_cur]; + + if (s->status !=3D DW_I2C_STATUS_RECEIVING) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Attempted to read from RX fifo when not in rece= ive " + "state.\n", DEVICE(s)->canonical_path); + if (s->status !=3D DW_I2C_STATUS_IDLE) { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_UNDER; + dw_i2c_update_irq(s); + } + return 0; + } + + s->rx_cur =3D (s->rx_cur + 1) % DESIGNWARE_I2C_RX_FIFO_SIZE; + + if (s->ic_rxflr > 0) { + s->ic_rxflr--; + } else { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_UNDER; + dw_i2c_update_irq(s); + return 0; + } + + if (s->ic_rxflr <=3D s->ic_rx_tl) { + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; + dw_i2c_update_irq(s); + } + + return value; +} + +static uint64_t dw_i2c_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t value =3D 0; + + DesignWareI2CState *s =3D opaque; + + switch (offset) { + case DW_IC_CON: + value =3D s->ic_con; + break; + case DW_IC_TAR: + value =3D s->ic_tar; + break; + case DW_IC_SAR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_sar\n", + DEVICE(s)->canonical_path); + value =3D s->ic_sar; + break; + case DW_IC_DATA_CMD: + value =3D dw_i2c_read_ic_data_cmd(s); + break; + case DW_IC_SS_SCL_HCNT: + value =3D s->ic_ss_scl_hcnt; + break; + case DW_IC_SS_SCL_LCNT: + value =3D s->ic_ss_scl_lcnt; + break; + case DW_IC_FS_SCL_HCNT: + value =3D s->ic_fs_scl_hcnt; + break; + case DW_IC_FS_SCL_LCNT: + value =3D s->ic_fs_scl_lcnt; + break; + case DW_IC_INTR_STAT: + value =3D s->ic_raw_intr_stat & s->ic_intr_mask; + break; + case DW_IC_INTR_MASK: + value =3D s->ic_intr_mask; + break; + case DW_IC_RAW_INTR_STAT: + value =3D s->ic_raw_intr_stat; + break; + case DW_IC_RX_TL: + value =3D s->ic_rx_tl; + break; + case DW_IC_TX_TL: + value =3D s->ic_tx_tl; + break; + case DW_IC_CLR_INTR: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_GEN_CALL | + DW_IC_INTR_RESTART_DET | + DW_IC_INTR_START_DET | + DW_IC_INTR_STOP_DET | + DW_IC_INTR_ACTIVITY | + DW_IC_INTR_RX_DONE | + DW_IC_INTR_TX_ABRT | + DW_IC_INTR_RD_REQ | + DW_IC_INTR_TX_OVER | + DW_IC_INTR_RX_OVER | + DW_IC_INTR_RX_UNDER); + s->ic_tx_abrt_source =3D 0; + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_RX_UNDER: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_UNDER); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_RX_OVER: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_OVER); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_TX_OVER: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_TX_OVER); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_RD_REQ: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RD_REQ); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_TX_ABRT: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_TX_ABRT); + s->ic_tx_abrt_source =3D 0; + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_RX_DONE: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_DONE); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_ACTIVITY: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_ACTIVITY); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_STOP_DET: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_STOP_DET); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_START_DET: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_START_DET); + dw_i2c_update_irq(s); + break; + case DW_IC_CLR_GEN_CALL: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_GEN_CALL); + dw_i2c_update_irq(s); + break; + case DW_IC_ENABLE: + value =3D s->ic_enable; + break; + case DW_IC_STATUS: + value =3D s->ic_status; + break; + case DW_IC_TXFLR: + value =3D s->ic_txflr; + break; + case DW_IC_RXFLR: + value =3D s->ic_rxflr; + break; + case DW_IC_SDA_HOLD: + value =3D s->ic_sda_hold; + break; + case DW_IC_TX_ABRT_SOURCE: + value =3D s->ic_tx_abrt_source; + break; + case DW_IC_SLV_DATA_NACK_ONLY: + qemu_log_mask(LOG_UNIMP, + "%s: unsupported read - ic_slv_data_nack_only\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_CR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_cr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_TDLR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_tdlr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_RDLR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_rdlr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_SDA_SETUP: + value =3D s->ic_sda_setup; + break; + case DW_IC_ACK_GENERAL_CALL: + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_ack_general_ca= ll\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_ENABLE_STATUS: + value =3D s->ic_enable_status; + break; + case DW_IC_FS_SPKLEN: + value =3D s->ic_fs_spklen; + break; + case DW_IC_CLR_RESTART_DET: + s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RESTART_DET); + dw_i2c_update_irq(s); + break; + case DW_IC_COMP_PARAM_1: + value =3D s->ic_comp_param_1; + break; + case DW_IC_COMP_VERSION: + value =3D s->ic_comp_version; + break; + case DW_IC_COMP_TYPE: + value =3D s->ic_comp_type; + break; + + /* This register is invalid at this point. */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: read from invalid offset 0x%" HWADDR_PRIx "\n", + DEVICE(s)->canonical_path, offset); + break; + } + + trace_dw_i2c_read(DEVICE(s)->canonical_path, offset, value); + + return value; +} + +static void dw_i2c_write_ic_con(DesignWareI2CState *s, uint32_t value) +{ + if (value & DW_IC_CON_RX_FIFO_FULL_HLD_CTRL) { + qemu_log_mask(LOG_UNIMP, + "%s: unsupported ic_con flag - RX_FIFO_FULL_HLD_CTRL= \n", + DEVICE(s)->canonical_path); + } + + if (!(s->ic_enable & DW_IC_ENABLE_ENABLE)) { + s->ic_con =3D value & DW_IC_CON_MASK; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid setting to ic_con %d when ic_enable[0]= =3D=3D1\n", + DEVICE(s)->canonical_path, value); + } +} + +static void dw_i2c_reset_to_idle(DesignWareI2CState *s) +{ + s->ic_enable_status &=3D ~DW_IC_ENABLE_STATUS_IC_EN; + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_TX_EMPTY; + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_UNDER; + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_OVER; + s->ic_rxflr =3D 0; + s->ic_status &=3D ~DW_IC_STATUS_ACTIVITY; + s->status =3D DW_I2C_STATUS_IDLE; + dw_i2c_update_irq(s); +} + +static void dw_ic_tx_abort(DesignWareI2CState *s, uint32_t src) +{ + s->ic_tx_abrt_source |=3D src; + s->ic_raw_intr_stat |=3D DW_IC_INTR_TX_ABRT; + dw_i2c_reset_to_idle(s); + dw_i2c_update_irq(s); +} + +static void dw_i2c_write_ic_data_cmd(DesignWareI2CState *s, uint32_t value) +{ + int recv =3D !!(value & DW_IC_DATA_CMD_CMD); + + if (s->status =3D=3D DW_I2C_STATUS_IDLE || + s->ic_raw_intr_stat & DW_IC_INTR_TX_ABRT) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Attempted to write to TX fifo when it is held i= n " + "reset.\n", DEVICE(s)->canonical_path); + return; + } + + /* Send the address if it hasn't been sent yet. */ + if (s->status =3D=3D DW_I2C_STATUS_SENDING_ADDRESS) { + int rv =3D i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar)= , recv); + if (rv) { + dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK); + return; + } + s->status =3D recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDI= NG; + } + + /* Send data */ + if (!recv) { + int rv =3D i2c_send(s->bus, DW_IC_DATA_CMD_DAT(value)); + if (rv) { + i2c_end_transfer(s->bus); + dw_ic_tx_abort(s, DW_IC_TX_ABRT_TXDATA_NOACK); + return; + } + dw_i2c_update_irq(s); + } + + /* Restart command */ + if (value & DW_IC_DATA_CMD_RESTART && s->ic_con & DW_IC_CON_IC_RESTART= _EN) { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RESTART_DET | + DW_IC_INTR_START_DET | + DW_IC_INTR_ACTIVITY; + s->ic_status |=3D DW_IC_STATUS_ACTIVITY; + dw_i2c_update_irq(s); + + if (i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar), recv)= ) { + dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK); + return; + } + + s->status =3D recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDI= NG; + } + + /* Receive data */ + if (recv) { + uint8_t pos =3D (s->rx_cur + s->ic_rxflr) % DESIGNWARE_I2C_RX_FIFO= _SIZE; + + if (s->ic_rxflr < DESIGNWARE_I2C_RX_FIFO_SIZE) { + s->rx_fifo[pos] =3D i2c_recv(s->bus); + s->ic_rxflr++; + } else { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_OVER; + dw_i2c_update_irq(s); + } + + if (s->ic_rxflr > s->ic_rx_tl) { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_FULL; + dw_i2c_update_irq(s); + } + if (value & DW_IC_DATA_CMD_STOP) { + i2c_nack(s->bus); + } + } + + /* Stop command */ + if (value & DW_IC_DATA_CMD_STOP) { + s->ic_raw_intr_stat |=3D DW_IC_INTR_STOP_DET; + s->ic_status &=3D ~DW_IC_STATUS_ACTIVITY; + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_TX_EMPTY; + i2c_end_transfer(s->bus); + dw_i2c_update_irq(s); + } +} + +static void dw_i2c_write_ic_enable(DesignWareI2CState *s, uint32_t value) +{ + if (value & DW_IC_ENABLE_ENABLE && !(s->ic_con & DW_IC_CON_SLAVE_DISAB= LE)) { + qemu_log_mask(LOG_UNIMP, + "%s: Designware I2C slave mode is not supported.\n", + DEVICE(s)->canonical_path); + return; + } + + s->ic_enable =3D value & DW_IC_ENABLE_MASK; + + if (value & DW_IC_ENABLE_ABORT || value & DW_IC_ENABLE_TX_CMD_BLOCK) { + dw_ic_tx_abort(s, DW_IC_TX_ABRT_USER_ABRT); + return; + } + + if (value & DW_IC_ENABLE_ENABLE) { + s->ic_enable_status |=3D DW_IC_ENABLE_STATUS_IC_EN; + s->ic_status |=3D DW_IC_STATUS_ACTIVITY; + s->ic_raw_intr_stat |=3D DW_IC_INTR_ACTIVITY | + DW_IC_INTR_START_DET | + DW_IC_INTR_TX_EMPTY; + s->status =3D DW_I2C_STATUS_SENDING_ADDRESS; + dw_i2c_update_irq(s); + } else if ((value & DW_IC_ENABLE_ENABLE) =3D=3D 0) { + dw_i2c_reset_to_idle(s); + } + +} + +static void dw_i2c_write_ic_rx_tl(DesignWareI2CState *s, uint32_t value) +{ + /* Note that a value of 0 for ic_rx_tl indicates a threashold of 1. */ + if (value > DESIGNWARE_I2C_RX_FIFO_SIZE - 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid setting to ic_rx_tl %d\n", + DEVICE(s)->canonical_path, value); + s->ic_rx_tl =3D DESIGNWARE_I2C_RX_FIFO_SIZE - 1; + } else { + s->ic_rx_tl =3D value; + } + + if (s->ic_rxflr > s->ic_rx_tl && s->ic_enable & DW_IC_ENABLE_ENABLE) { + s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_FULL; + } else { + s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; + } + dw_i2c_update_irq(s); +} + +static void dw_i2c_write_ic_tx_tl(DesignWareI2CState *s, uint32_t value) +{ + /* + * Note that a value of 0 for ic_tx_tl indicates a threashold of 1. + * However, the tx threshold is not used in the model because commands= are + * always sent out as soon as they are written. + */ + if (value > DESIGNWARE_I2C_TX_FIFO_SIZE - 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid setting to ic_tx_tl %d\n", + DEVICE(s)->canonical_path, value); + s->ic_tx_tl =3D DESIGNWARE_I2C_TX_FIFO_SIZE - 1; + } else { + s->ic_tx_tl =3D value; + } +} + +static void dw_i2c_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + DesignWareI2CState *s =3D opaque; + + trace_dw_i2c_write(DEVICE(s)->canonical_path, offset, value); + + /* The order of the registers are their order in memory. */ + switch (offset) { + case DW_IC_CON: + dw_i2c_write_ic_con(s, value); + break; + case DW_IC_TAR: + s->ic_tar =3D value & DW_IC_TAR_MASK; + break; + case DW_IC_SAR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_sar\n", + DEVICE(s)->canonical_path); + s->ic_sar =3D value & DW_IC_SAR_MASK; + break; + case DW_IC_DATA_CMD: + dw_i2c_write_ic_data_cmd(s, value); + break; + case DW_IC_SS_SCL_HCNT: + s->ic_ss_scl_hcnt =3D value & DW_IC_SS_SCL_HCNT_MASK; + break; + case DW_IC_SS_SCL_LCNT: + s->ic_ss_scl_lcnt =3D value & DW_IC_SS_SCL_LCNT_MASK; + break; + case DW_IC_FS_SCL_HCNT: + s->ic_fs_scl_hcnt =3D value & DW_IC_FS_SCL_HCNT_MASK; + break; + case DW_IC_FS_SCL_LCNT: + s->ic_fs_scl_lcnt =3D value & DW_IC_FS_SCL_LCNT_MASK; + break; + case DW_IC_INTR_MASK: + s->ic_intr_mask =3D value & DW_IC_INTR_MASK_MASK; + dw_i2c_update_irq(s); + break; + case DW_IC_RX_TL: + dw_i2c_write_ic_rx_tl(s, value); + break; + case DW_IC_TX_TL: + dw_i2c_write_ic_tx_tl(s, value); + break; + case DW_IC_ENABLE: + dw_i2c_write_ic_enable(s, value); + break; + case DW_IC_SDA_HOLD: + s->ic_sda_hold =3D value & DW_IC_SDA_HOLD_MASK; + break; + case DW_IC_SLV_DATA_NACK_ONLY: + qemu_log_mask(LOG_UNIMP, + "%s: unsupported write - ic_slv_data_nack_only\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_CR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_cr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_TDLR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_tdlr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_DMA_RDLR: + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_rdlr\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_SDA_SETUP: + s->ic_sda_setup =3D value & DW_IC_SDA_SETUP_MASK; + break; + case DW_IC_ACK_GENERAL_CALL: + qemu_log_mask(LOG_UNIMP, + "%s: unsupported write - ic_ack_general_call\n", + DEVICE(s)->canonical_path); + break; + case DW_IC_FS_SPKLEN: + s->ic_fs_spklen =3D value & DW_IC_FS_SPKLEN_MASK; + break; + + /* This register is invalid at this point. */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to invalid offset or readonly register 0x= %" + HWADDR_PRIx "\n", + DEVICE(s)->canonical_path, offset); + break; + } +} + +static const MemoryRegionOps designware_i2c_ops =3D { + .read =3D dw_i2c_read, + .write =3D dw_i2c_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + .unaligned =3D false, + }, +}; + +static void designware_i2c_enter_reset(Object *obj, ResetType type) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); + + s->ic_con =3D DW_IC_CON_INIT_VAL; + s->ic_tar =3D DW_IC_TAR_INIT_VAL; + s->ic_sar =3D DW_IC_SAR_INIT_VAL; + s->ic_ss_scl_hcnt =3D DW_IC_SS_SCL_HCNT_INIT_VAL; + s->ic_ss_scl_lcnt =3D DW_IC_SS_SCL_LCNT_INIT_VAL; + s->ic_fs_scl_hcnt =3D DW_IC_FS_SCL_HCNT_INIT_VAL; + s->ic_fs_scl_lcnt =3D DW_IC_FS_SCL_LCNT_INIT_VAL; + s->ic_intr_mask =3D DW_IC_INTR_MASK_INIT_VAL; + s->ic_raw_intr_stat =3D 0; + s->ic_rx_tl =3D 0; + s->ic_tx_tl =3D 0; + s->ic_enable =3D 0; + s->ic_status =3D DW_IC_STATUS_INIT_VAL; + s->ic_txflr =3D 0; + s->ic_rxflr =3D 0; + s->ic_sda_hold =3D DW_IC_SDA_HOLD_INIT_VAL; + s->ic_tx_abrt_source =3D 0; + s->ic_sda_setup =3D DW_IC_SDA_SETUP_INIT_VAL; + s->ic_enable_status =3D 0; + s->ic_fs_spklen =3D DW_IC_FS_SPKLEN_INIT_VAL; + s->ic_comp_param_1 =3D DW_IC_COMP_PARAM_1_INIT_VAL; + s->ic_comp_version =3D DW_IC_COMP_VERSION_INIT_VAL; + s->ic_comp_type =3D DW_IC_COMP_TYPE_INIT_VAL; + + s->rx_cur =3D 0; + s->status =3D DW_I2C_STATUS_IDLE; +} + +static void designware_i2c_hold_reset(Object *obj, ResetType type) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); + + qemu_irq_lower(s->irq); +} + +static const VMStateDescription vmstate_designware_i2c =3D { + .name =3D TYPE_DESIGNWARE_I2C, + .version_id =3D 0, + .minimum_version_id =3D 0, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT32(ic_con, DesignWareI2CState), + VMSTATE_UINT32(ic_tar, DesignWareI2CState), + VMSTATE_UINT32(ic_sar, DesignWareI2CState), + VMSTATE_UINT32(ic_ss_scl_hcnt, DesignWareI2CState), + VMSTATE_UINT32(ic_ss_scl_lcnt, DesignWareI2CState), + VMSTATE_UINT32(ic_fs_scl_hcnt, DesignWareI2CState), + VMSTATE_UINT32(ic_fs_scl_lcnt, DesignWareI2CState), + VMSTATE_UINT32(ic_intr_mask, DesignWareI2CState), + VMSTATE_UINT32(ic_raw_intr_stat, DesignWareI2CState), + VMSTATE_UINT32(ic_rx_tl, DesignWareI2CState), + VMSTATE_UINT32(ic_tx_tl, DesignWareI2CState), + VMSTATE_UINT32(ic_enable, DesignWareI2CState), + VMSTATE_UINT32(ic_status, DesignWareI2CState), + VMSTATE_UINT32(ic_txflr, DesignWareI2CState), + VMSTATE_UINT32(ic_rxflr, DesignWareI2CState), + VMSTATE_UINT32(ic_sda_hold, DesignWareI2CState), + VMSTATE_UINT32(ic_tx_abrt_source, DesignWareI2CState), + VMSTATE_UINT32(ic_sda_setup, DesignWareI2CState), + VMSTATE_UINT32(ic_enable_status, DesignWareI2CState), + VMSTATE_UINT32(ic_fs_spklen, DesignWareI2CState), + VMSTATE_UINT32(ic_comp_param_1, DesignWareI2CState), + VMSTATE_UINT32(ic_comp_version, DesignWareI2CState), + VMSTATE_UINT32(ic_comp_type, DesignWareI2CState), + VMSTATE_UINT32(status, DesignWareI2CState), + VMSTATE_UINT8_ARRAY(rx_fifo, DesignWareI2CState, + DESIGNWARE_I2C_RX_FIFO_SIZE), + VMSTATE_UINT8(rx_cur, DesignWareI2CState), + VMSTATE_END_OF_LIST(), + }, +}; + +static void designware_i2c_smbus_init(Object *obj) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, obj, &designware_i2c_ops, s, + "regs", 4 * KiB); + sysbus_init_mmio(sbd, &s->iomem); + + s->bus =3D i2c_init_bus(DEVICE(s), "i2c-bus"); +} + +static void designware_i2c_class_init(ObjectClass *klass, const void *data) +{ + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->desc =3D "Designware I2C"; + dc->vmsd =3D &vmstate_designware_i2c; + rc->phases.enter =3D designware_i2c_enter_reset; + rc->phases.hold =3D designware_i2c_hold_reset; + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo designware_i2c_types[] =3D { + { + .name =3D TYPE_DESIGNWARE_I2C, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(DesignWareI2CState), + .class_init =3D designware_i2c_class_init, + .instance_init =3D designware_i2c_smbus_init, + }, +}; +DEFINE_TYPES(designware_i2c_types); diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index c459adcb59..88aea35662 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -11,6 +11,7 @@ i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2= c.c')) i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c')) i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c')) i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c')) +i2c_ss.add(when: 'CONFIG_DESIGNWARE_I2C', if_true: files('designware_i2c.c= ')) i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c')) i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 1ad0e95c0e..8a78d2d3c8 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -61,3 +61,7 @@ pca954x_read_data(uint8_t value) "PCA954X read data: 0x%0= 2x" =20 imx_i2c_read(const char *id, const char *reg, uint64_t ofs, uint64_t value= ) "%s:[%s (0x%" PRIx64 ")] -> 0x%02" PRIx64 imx_i2c_write(const char *id, const char *reg, uint64_t ofs, uint64_t valu= e) "%s:[%s (0x%" PRIx64 ")] <- 0x%02" PRIx64 + +# designware_i2c.c +dw_i2c_read(const char *id, uint64_t ofs, uint64_t value) "%s: offset 0x%0= 2" PRIx64 " -> value: 0x%02" PRIx64 +dw_i2c_write(const char *id, uint64_t ofs, uint64_t value) "%s: offset: 0x= %02" PRIx64 " <- value: 0x%02" PRIx64 diff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2= c.h new file mode 100644 index 0000000000..71d74c9141 --- /dev/null +++ b/include/hw/i2c/designware_i2c.h @@ -0,0 +1,101 @@ +/* + * DesignWare I2C Module. + * + * Copyright 2021 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef DESIGNWARE_I2C_H +#define DESIGNWARE_I2C_H + +#include "hw/i2c/i2c.h" +#include "hw/core/irq.h" +#include "hw/core/sysbus.h" + +/* Size of the FIFO buffers. */ +#define DESIGNWARE_I2C_RX_FIFO_SIZE 16 +#define DESIGNWARE_I2C_TX_FIFO_SIZE 16 + +typedef enum DesignWareI2CStatus { + DW_I2C_STATUS_IDLE, + DW_I2C_STATUS_SENDING_ADDRESS, + DW_I2C_STATUS_SENDING, + DW_I2C_STATUS_RECEIVING, +} DesignWareI2CStatus; + +/* + * struct DesignWareI2CState - DesignWare I2C device state. + * @bus: The underlying I2C Bus + * @irq: GIC interrupt line to fire on events + * @ic_con: : I2C control register + * @ic_tar: I2C target address register + * @ic_sar: I2C slave address register + * @ic_ss_scl_hcnt: Standard speed i2c clock scl high count register + * @ic_ss_scl_lcnt: Standard speed i2c clock scl low count register + * @ic_fs_scl_hcnt: Fast mode or fast mode plus i2c clock scl high count + * register + * @ic_fs_scl_lcnt:Fast mode or fast mode plus i2c clock scl low count + * register + * @ic_intr_mask: I2C Interrupt Mask Register + * @ic_raw_intr_stat: I2C raw interrupt status register + * @ic_rx_tl: I2C receive FIFO threshold register + * @ic_tx_tl: I2C transmit FIFO threshold register + * @ic_enable: I2C enable register + * @ic_status: I2C status register + * @ic_txflr: I2C transmit fifo level register + * @ic_rxflr: I2C receive fifo level register + * @ic_sda_hold: I2C SDA hold time length register + * @ic_tx_abrt_source: The I2C transmit abort source register + * @ic_sda_setup: I2C SDA setup register + * @ic_enable_status: I2C enable status register + * @ic_fs_spklen: I2C SS, FS or FM+ spike suppression limit + * @ic_comp_param_1: Component parameter register + * @ic_comp_version: I2C component version register + * @ic_comp_type: I2C component type register + * @rx_fifo: The FIFO buffer for receiving in FIFO mode. + * @rx_cur: The current position of rx_fifo. + * @status: The current status of the SMBus. + */ +typedef struct DesignWareI2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + I2CBus *bus; + qemu_irq irq; + + uint32_t ic_con; + uint32_t ic_tar; + uint32_t ic_sar; + uint32_t ic_ss_scl_hcnt; + uint32_t ic_ss_scl_lcnt; + uint32_t ic_fs_scl_hcnt; + uint32_t ic_fs_scl_lcnt; + uint32_t ic_intr_mask; + uint32_t ic_raw_intr_stat; + uint32_t ic_rx_tl; + uint32_t ic_tx_tl; + uint32_t ic_enable; + uint32_t ic_status; + uint32_t ic_txflr; + uint32_t ic_rxflr; + uint32_t ic_sda_hold; + uint32_t ic_tx_abrt_source; + uint32_t ic_sda_setup; + uint32_t ic_enable_status; + uint32_t ic_fs_spklen; + uint32_t ic_comp_param_1; + uint32_t ic_comp_version; + uint32_t ic_comp_type; + + uint8_t rx_fifo[DESIGNWARE_I2C_RX_FIFO_SIZE]; + uint8_t rx_cur; + + DesignWareI2CStatus status; +} DesignWareI2CState; + +#define TYPE_DESIGNWARE_I2C "designware-i2c" +#define DESIGNWARE_I2C(obj) OBJECT_CHECK(DesignWareI2CState, (obj), \ + TYPE_DESIGNWARE_I2C) + +#endif /* DESIGNWARE_I2C_H */ diff --git a/roms/seabios-hppa b/roms/seabios-hppa index d9560852a3..1a8ada1fb7 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit d9560852a34f156155b3777745baa0d96d553f22 +Subproject commit 1a8ada1fb70643172e251aacbac673c9ecda99e9 --=20 2.53.0 From nobody Sat May 30 16:35:39 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778155659; cv=none; d=zohomail.com; s=zohoarc; b=ZaP8Orhd/VYfHJ8ehrOCxMt424ZDthoArrn0IeG2ULnhRHWuOxZ9N28/cYJ8DBYB5gTfB8rikFxvGJO9/vgpCwDYb2GJcMfpzU5ZBMDdaj0aHfxTbjuFodKnAsenkpycxjT/+bzbpqy2YPJzCGM0YkyduR9FYQfRy2gGyfn7Y1I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778155659; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=a55fnsta7QVOIhLTdBCQDzrOhK52w63j4puh3Zx2B0Q=; b=HNscyxEh8nENiKUwfNUoVoDilrCM6KQKd/1c3fxfh9fREuooBBiEmABEr8c4+tKmbKBovK8++l/VFZfqbJwyfCE2Qf6m8HZjqmp+wzTso+cAeHPrWs40szLIlg7FzSfQrRbtf65P1rAbKfblpOfdQ20eie0wtYuWcDv/HmEt6Yc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778155659980196.40265887501027; Thu, 7 May 2026 05:07:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wKxUK-0008U9-I7; Thu, 07 May 2026 08:05:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wKxUG-0008TT-BC for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:53 -0400 Received: from mail-pl1-x62f.google.com ([2607:f8b0:4864:20::62f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wKxUC-0002BH-5h for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:51 -0400 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-2a7a9b8ed69so6463145ad.2 for ; Thu, 07 May 2026 05:05:46 -0700 (PDT) Received: from localhost (124.158.97.178.qld.leaptel.network. [124.158.97.178]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2babaad7b68sm24663835ad.22.2026.05.07.05.05.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 05:05:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778155546; x=1778760346; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=a55fnsta7QVOIhLTdBCQDzrOhK52w63j4puh3Zx2B0Q=; b=Z7Z/o5SVR+GTrYf460UFMHSzNPv8VDTFEISiHkjhsO2BeVxxXBJC5DP6nBOF/Zg2k3 6XmcESKdyfTwbgioSKrHrDAYSPAPWD8SEu1A5LBzhLL+T2eR7GVzB+MFMQRG4Jc4NYSu f8osxMNlBeHYXeDBLklCrTdasarDQc7VjscwqXcSqkaV+4kM0urVMm753zxb/zbiybHK i3YJOK160bw5s/hz40iFUKLEFs4v6qzum0gRHqcwaKVO8kxF9pyWaHngclr9RiMFj2v/ 8xrvC4PzqkgGPChrl+B57HoakyCHJhLbPfavt154NuwCG5bI4ZpoaVPjFGrRJJm/reVS n7Qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778155546; x=1778760346; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=a55fnsta7QVOIhLTdBCQDzrOhK52w63j4puh3Zx2B0Q=; b=UAL0omD7dyot854mqsVUlTxgJX63ITmiBmuxcwHPDe4pOKGZlzaInArAlOqR13+3M9 cXmLK/ePc/OvIlziCGWXW3ut1yP1kAE3S1qkDafXeGzcidSjCPuu3Pjlqq/8ORUcp5Cm QsqugAtLB6Na5wJNaRja5eYD15BY6NYYaAmuOa1PaypHs9uYk68f9XdH8W81jxmaohHb sneRVaLb+2Nr0kot+lOZ9HxDEn7fyMbl4JFJVYd/DSOCG1WU2dI+tcJUwafYqzUlkkc1 mD0WJb3/o9hJ8rlujnFzD3sDkxv7kL3d07dSgnccsWeTNJ6laeUut7vT9UWjM2q41t2Z e1Bg== X-Forwarded-Encrypted: i=1; AFNElJ8Z+QQMZhTmG6dVi3QC2zzE/RaALhoFXPr7roivRMgnS+aAaSpUjqStSZol7XufiVUhaqpGHEMO3I5N@nongnu.org X-Gm-Message-State: AOJu0Yy9qvlT9V0+cxRTBgdaQnjzW4wpP2iNCR+XhfGYdOTMp0u6OxFk CZMBOgoBeef7qnuK2Ke7/Ii4pn41yxf/DfPdpA3AlBJU1/SBuxHl4eIK X-Gm-Gg: AeBDievEPqJ0j6BNqUL3Og68B48khAQ66jQ2brum6ZHXCn6WMRwm+aXjEdZzdzss5Tc NVAyLIXjIT4HCJ4I03L57nfIv9R2Pd+cvrufzL6ZbAFlpNB47RylB/gQOKwmS78jiZ642xObzo6 LRXJAlFNqw8ku3kcLfAy33DcReOw6Kb2V0MO+Ro1rtVEwgbWKSU1ivvHFDuwpPCOGEo0Gw+tSVk ADgjsR6tMlo6PgJ2836mEropmApt3DH41a/3oKK3pfy2dPPuIs8YB5S7DFpVqb5ZofMhHAehXqy PYKlyLGKEHJBe6mc+SC0P2FMTR2KE0Vt6NFymYP1k/aW5mCj1Tj21/xO6rM5KiyKn6VWHyZSKCx a2gTQAGrwoBExHZr002kCpB854PTAfb4jpiI8ZzagfuxabhCY/PCYnbOaMVkZCHjc1BdC98Hncc 1fq8ZICjVP35udgxPqMoLc2QPExIoTn4O6NDDWvawhrb8c4y6G/KVspXxXelNbWT/tYhdVMRBhX oCtjr5T X-Received: by 2002:a17:902:bd87:b0:2b0:ac1e:9720 with SMTP id d9443c01a7336-2ba79c22193mr58822705ad.23.1778155545723; Thu, 07 May 2026 05:05:45 -0700 (PDT) From: Nicholas Piggin To: Corey Minyard Cc: Nicholas Piggin , Alistair Francis , Daniel Henrique Barboza , Chao Liu , Chris Rauer , Michael Ellerman , Joel Stanley , Anirudh Srinivasan , Portia Stephens , qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Hao Wu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH 2/4] [RFC] hw/i2c/designware_i2c: Switch to Fifo8 Date: Thu, 7 May 2026 22:05:20 +1000 Message-ID: <20260507120524.111056-3-npiggin@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260507120524.111056-1-npiggin@gmail.com> References: <20260507120524.111056-1-npiggin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62f; envelope-from=npiggin@gmail.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1778155661585154100 Content-Type: text/plain; charset="utf-8" Alistair suggested moving to Fifo8, which I think is a good improvement. Broken out for individual review, but IMO we should squash before merge since it changes VMState format. Signed-off-by: Nicholas Piggin Acked-by: Corey Minyard --- hw/i2c/designware_i2c.c | 37 ++++++++++++++++++++------------- include/hw/i2c/designware_i2c.h | 7 +++---- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c index 1e5505f571..83d0968580 100644 --- a/hw/i2c/designware_i2c.c +++ b/hw/i2c/designware_i2c.c @@ -208,10 +208,8 @@ static void dw_i2c_update_irq(DesignWareI2CState *s) qemu_set_irq(s->irq, level); } =20 -static uint32_t dw_i2c_read_ic_data_cmd(DesignWareI2CState *s) +static uint8_t dw_i2c_read_ic_data_cmd(DesignWareI2CState *s) { - uint32_t value =3D s->rx_fifo[s->rx_cur]; - if (s->status !=3D DW_I2C_STATUS_RECEIVING) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempted to read from RX fifo when not in rece= ive " @@ -223,22 +221,21 @@ static uint32_t dw_i2c_read_ic_data_cmd(DesignWareI2C= State *s) return 0; } =20 - s->rx_cur =3D (s->rx_cur + 1) % DESIGNWARE_I2C_RX_FIFO_SIZE; + g_assert(s->ic_rxflr =3D=3D fifo8_num_used(&s->rx_fifo)); =20 - if (s->ic_rxflr > 0) { - s->ic_rxflr--; - } else { + if (fifo8_is_empty(&s->rx_fifo)) { s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_UNDER; dw_i2c_update_irq(s); return 0; } =20 + s->ic_rxflr--; if (s->ic_rxflr <=3D s->ic_rx_tl) { s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; dw_i2c_update_irq(s); } =20 - return value; + return fifo8_pop(&s->rx_fifo); } =20 static uint64_t dw_i2c_read(void *opaque, hwaddr offset, unsigned size) @@ -445,6 +442,7 @@ static void dw_i2c_reset_to_idle(DesignWareI2CState *s) s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_UNDER; s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_OVER; s->ic_rxflr =3D 0; + fifo8_reset(&s->rx_fifo); s->ic_status &=3D ~DW_IC_STATUS_ACTIVITY; s->status =3D DW_I2C_STATUS_IDLE; dw_i2c_update_irq(s); @@ -509,10 +507,10 @@ static void dw_i2c_write_ic_data_cmd(DesignWareI2CSta= te *s, uint32_t value) =20 /* Receive data */ if (recv) { - uint8_t pos =3D (s->rx_cur + s->ic_rxflr) % DESIGNWARE_I2C_RX_FIFO= _SIZE; + g_assert(s->ic_rxflr =3D=3D fifo8_num_used(&s->rx_fifo)); =20 - if (s->ic_rxflr < DESIGNWARE_I2C_RX_FIFO_SIZE) { - s->rx_fifo[pos] =3D i2c_recv(s->bus); + if (!fifo8_is_full(&s->rx_fifo)) { + fifo8_push(&s->rx_fifo, i2c_recv(s->bus)); s->ic_rxflr++; } else { s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_OVER; @@ -738,7 +736,8 @@ static void designware_i2c_enter_reset(Object *obj, Res= etType type) s->ic_comp_version =3D DW_IC_COMP_VERSION_INIT_VAL; s->ic_comp_type =3D DW_IC_COMP_TYPE_INIT_VAL; =20 - s->rx_cur =3D 0; + fifo8_reset(&s->rx_fifo); + s->status =3D DW_I2C_STATUS_IDLE; } =20 @@ -777,10 +776,8 @@ static const VMStateDescription vmstate_designware_i2c= =3D { VMSTATE_UINT32(ic_comp_param_1, DesignWareI2CState), VMSTATE_UINT32(ic_comp_version, DesignWareI2CState), VMSTATE_UINT32(ic_comp_type, DesignWareI2CState), + VMSTATE_FIFO8(rx_fifo, DesignWareI2CState), VMSTATE_UINT32(status, DesignWareI2CState), - VMSTATE_UINT8_ARRAY(rx_fifo, DesignWareI2CState, - DESIGNWARE_I2C_RX_FIFO_SIZE), - VMSTATE_UINT8(rx_cur, DesignWareI2CState), VMSTATE_END_OF_LIST(), }, }; @@ -790,6 +787,8 @@ static void designware_i2c_smbus_init(Object *obj) DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); =20 + fifo8_create(&s->rx_fifo, DESIGNWARE_I2C_RX_FIFO_SIZE); + sysbus_init_irq(sbd, &s->irq); =20 memory_region_init_io(&s->iomem, obj, &designware_i2c_ops, s, @@ -799,6 +798,13 @@ static void designware_i2c_smbus_init(Object *obj) s->bus =3D i2c_init_bus(DEVICE(s), "i2c-bus"); } =20 +static void designware_i2c_finalize(Object *obj) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); + + fifo8_destroy(&s->rx_fifo); +} + static void designware_i2c_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc =3D RESETTABLE_CLASS(klass); @@ -819,6 +825,7 @@ static const TypeInfo designware_i2c_types[] =3D { .instance_size =3D sizeof(DesignWareI2CState), .class_init =3D designware_i2c_class_init, .instance_init =3D designware_i2c_smbus_init, + .instance_finalize =3D designware_i2c_finalize, }, }; DEFINE_TYPES(designware_i2c_types); diff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2= c.h index 71d74c9141..affaf983a2 100644 --- a/include/hw/i2c/designware_i2c.h +++ b/include/hw/i2c/designware_i2c.h @@ -8,6 +8,7 @@ #ifndef DESIGNWARE_I2C_H #define DESIGNWARE_I2C_H =20 +#include "qemu/fifo8.h" #include "hw/i2c/i2c.h" #include "hw/core/irq.h" #include "hw/core/sysbus.h" @@ -53,8 +54,6 @@ typedef enum DesignWareI2CStatus { * @ic_comp_version: I2C component version register * @ic_comp_type: I2C component type register * @rx_fifo: The FIFO buffer for receiving in FIFO mode. - * @rx_cur: The current position of rx_fifo. - * @status: The current status of the SMBus. */ typedef struct DesignWareI2CState { SysBusDevice parent_obj; @@ -88,8 +87,8 @@ typedef struct DesignWareI2CState { uint32_t ic_comp_version; uint32_t ic_comp_type; =20 - uint8_t rx_fifo[DESIGNWARE_I2C_RX_FIFO_SIZE]; - uint8_t rx_cur; + /* fifo8_num_used(rx_fifo) should always equal ic_rxflr */ + Fifo8 rx_fifo; =20 DesignWareI2CStatus status; } DesignWareI2CState; --=20 2.53.0 From nobody Sat May 30 16:35:39 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778155647; cv=none; d=zohomail.com; s=zohoarc; b=Ot5oqTK6xQwc9Z4xfo8sIY8KcZtq5zk5rr7+o30L8bBUcVJNMa4BF7Hyf5YjzwVpPm07DW96yJWbKIH6kUvAiebmjMltwPkIK7G5q9Lt+WtJa1P+YvJdqjpsPsIXXO5/ivGSmaB5gxKt6ArAT1RY8YpT7hX89xrwQ825CN2b0JA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778155647; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=uPAB8UEnJQc6fSnOOnptelJUuydCzjN5zql6YY4rLdo=; b=OhWgPo7icw8RWEmROvXMI9+WWNjrA4waj5wbwvHcZAUOoujzlejZW8CD9g086+Ca+ucjSzvuLF6ZiDEN+JG6A8O1iBDwYWkXS+TU6qU1r8HW9+mzhqIDsmETW1fJDk4y6ufZ1DQhFhl5f6CimiUmhY+gkUrz7WWzAlCpb1BIMo8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177815564744868.29481067769836; Thu, 7 May 2026 05:07:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wKxUW-00005G-Bx; Thu, 07 May 2026 08:06:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wKxUK-0008UR-Gp for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:56 -0400 Received: from mail-pj1-x102e.google.com ([2607:f8b0:4864:20::102e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wKxUG-0002Bt-3m for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:56 -0400 Received: by mail-pj1-x102e.google.com with SMTP id 98e67ed59e1d1-356337f058aso438065a91.2 for ; Thu, 07 May 2026 05:05:51 -0700 (PDT) Received: from localhost (124.158.97.178.qld.leaptel.network. [124.158.97.178]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-365b4c196ecsm5899474a91.6.2026.05.07.05.05.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 05:05:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778155550; x=1778760350; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uPAB8UEnJQc6fSnOOnptelJUuydCzjN5zql6YY4rLdo=; b=FB7Ed18YEyzllJ1ZQSSL152+CNqdmUewS31jT3L0a0hm0x4r2LZ8fhz6S/H6cjFs4J DeHkK5viGyqp/fsVCpJ5MZmezg3GqgLA8gTM1K+1qYFDR3n5tq3aSEEAzgULAYgbEUBr WsIbXHIiRI6PhL7PEhKt11YNJ/62Y6VSuJ9AFYltJ2IHTmehEirHg9TSh5daJfyhRISq P6jL1gGWNBRj+ZmPZP/SI8gKDAsMGVmORXa4meJczpWRvGPXi3Jfj6lMD3OudCQ9pa/H OXRNfUuJjbh+MQDPM6KJbyTKAo+dXtOrt3P+iCrH36JAG31JLFWR/JJF5uGAKhbNtc4I u9Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778155550; x=1778760350; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=uPAB8UEnJQc6fSnOOnptelJUuydCzjN5zql6YY4rLdo=; b=EWK+bNtpEFMqk1wg93vQ0g9bSvcnCsh2qmYbcsVJH7ZJNqDz9j4FGUJCoVjtB5OwDY m/MfdbrLix+ZQpLsOp34kfJ/TxOqNkG5j3CDbHt+VqeFN37HvGgxfzy6bZxAgkdKNTSb dxzJqBJWlK7hAZ7LWYVUVlvLmKV7Gy2bOG13/WLFs2HNtZVhzuZ09P1YrWEvqCLEFJAv g6OBWOLauJPq2Mo/Ucg0vxAcSxWT9lNZr+5CURF2r+V5d22zUiMc7Da1LsyXauBMfE6f 8GfURMbvWCJeMPoC7qGkDCC01fYb/AU0X6ESSp049d6HEpfN6MOPL2FuJSPjeQc3VfE9 yB9w== X-Forwarded-Encrypted: i=1; AFNElJ9OXml4IPlNZDcpM/o21Sa88Ixoy1OatGqIvRAw3VS8NpecXPiEHPISKzO98wCt1e82ytsBF2IPUDt4@nongnu.org X-Gm-Message-State: AOJu0YyvCL7BE/iPebCvzJ9gRrB1xU5oxPWiVJ66VygzJJwNKeV+IZoG OgveqEX9M8AGPyb/Q9SGddcvxXEN2XdQscVSo6zsXXRPLWkuoJkma92gvX6dHw== X-Gm-Gg: AeBDievYRlXwebY65TppiGvQPI1P2Dl49UHdT8OsjVrhMC9PY/tX/TyJNKOa8frJxaz 72sMHEPozkGcoF83HjP04at8pOsJpuoeproGPDEuaiKAh+Ug03zqw/df4wdiGcLIn8cdItTP98U wOD7j6bB5iINMMyelhSUepTl6jt0YU9wGkbavljOEn8P0p6GEwsmxA6/fzsrX1ytqvBb6L8CoBj JhowS6LgPzr+k+4qxPznMAnzc7BYNy4TVefJ2qtM75xdqpCZvopntrKc9xUwi2Vbpel7H4MgL5w YfNW7r3vGV3vnMdrvoud4jcYKO9a2DqNhpsh2fCb7KYCUrFGQp3mZ8CB4fdZ+1c4sRVC3/fExhV HwuQQFwsrxH6MUtyT2O29+NvWiAhuXhEfWLgga5uZIrUlhFFW6cursDxmvqMI4YS+8tO7ER3qrE 3IKsZFtTk7grvgoBsuViQ8BPezC9ZEFqFRy0xg0w6laf+PdY7yyMneKwBCzUw4cuUWpQ3u02gah TPFfify X-Received: by 2002:a17:90a:1081:b0:366:9bd:9ef3 with SMTP id 98e67ed59e1d1-36609bd9f2fmr1686490a91.26.1778155550036; Thu, 07 May 2026 05:05:50 -0700 (PDT) From: Nicholas Piggin To: Corey Minyard Cc: Nicholas Piggin , Alistair Francis , Daniel Henrique Barboza , Chao Liu , Chris Rauer , Michael Ellerman , Joel Stanley , Anirudh Srinivasan , Portia Stephens , qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Hao Wu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH 3/4] [RFC] hw/i2c/designware_i2c: Switch to QEMU register API Date: Thu, 7 May 2026 22:05:21 +1000 Message-ID: <20260507120524.111056-4-npiggin@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260507120524.111056-1-npiggin@gmail.com> References: <20260507120524.111056-1-npiggin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::102e; envelope-from=npiggin@gmail.com; helo=mail-pj1-x102e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1778155649478154100 Content-Type: text/plain; charset="utf-8" Alistair suggested moving to QEMU register API. I haven't used it before but IMO it is an improvement. It is a lot of churn that is not very review-able but unfortunately also changes VMState making it a pain to do incrementally. If we decide to go this way, we should squash the conversion patch when we're happy with it. I tried not to rearrange the code too much, to reduce patch size. I prefer putting register implementation all together rather than grouped by read and write, which this API promotes. So if others like that style then I will move that. I didn't change to use all the FIELD APIs to set/clear bits, since it worked out a bit easier to script and only a smal win since there is little/no multibit fields and shifting/masking required. Register traces of loading the kernel drivers for the 2 devices added on the Atlantis machine in the series Joel posted earlier look identical modulo RTC data reads (which I guess is due to time differences). Signed-off-by: Nicholas Piggin Acked-by: Corey Minyard --- hw/i2c/Kconfig | 1 + hw/i2c/designware_i2c.c | 1022 ++++++++++++++----------------- include/hw/i2c/designware_i2c.h | 56 +- 3 files changed, 471 insertions(+), 608 deletions(-) diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index d3f394edeb..0766130b59 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -20,6 +20,7 @@ config ARM_SBCON_I2C =20 config DESIGNWARE_I2C bool + select REGISTER select I2C =20 config ACPI_SMBUS diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c index 83d0968580..b7be4d68c4 100644 --- a/hw/i2c/designware_i2c.c +++ b/hw/i2c/designware_i2c.c @@ -16,452 +16,312 @@ #include "qemu/units.h" #include "trace.h" =20 -enum DesignWareI2CRegister { - DW_IC_CON =3D 0x00, - DW_IC_TAR =3D 0x04, - DW_IC_SAR =3D 0x08, - DW_IC_DATA_CMD =3D 0x10, - DW_IC_SS_SCL_HCNT =3D 0x14, - DW_IC_SS_SCL_LCNT =3D 0x18, - DW_IC_FS_SCL_HCNT =3D 0x1c, - DW_IC_FS_SCL_LCNT =3D 0x20, - DW_IC_INTR_STAT =3D 0x2c, - DW_IC_INTR_MASK =3D 0x30, - DW_IC_RAW_INTR_STAT =3D 0x34, - DW_IC_RX_TL =3D 0x38, - DW_IC_TX_TL =3D 0x3c, - DW_IC_CLR_INTR =3D 0x40, - DW_IC_CLR_RX_UNDER =3D 0x44, - DW_IC_CLR_RX_OVER =3D 0x48, - DW_IC_CLR_TX_OVER =3D 0x4c, - DW_IC_CLR_RD_REQ =3D 0x50, - DW_IC_CLR_TX_ABRT =3D 0x54, - DW_IC_CLR_RX_DONE =3D 0x58, - DW_IC_CLR_ACTIVITY =3D 0x5c, - DW_IC_CLR_STOP_DET =3D 0x60, - DW_IC_CLR_START_DET =3D 0x64, - DW_IC_CLR_GEN_CALL =3D 0x68, - DW_IC_ENABLE =3D 0x6c, - DW_IC_STATUS =3D 0x70, - DW_IC_TXFLR =3D 0x74, - DW_IC_RXFLR =3D 0x78, - DW_IC_SDA_HOLD =3D 0x7c, - DW_IC_TX_ABRT_SOURCE =3D 0x80, - DW_IC_SLV_DATA_NACK_ONLY =3D 0x84, - DW_IC_DMA_CR =3D 0x88, - DW_IC_DMA_TDLR =3D 0x8c, - DW_IC_DMA_RDLR =3D 0x90, - DW_IC_SDA_SETUP =3D 0x94, - DW_IC_ACK_GENERAL_CALL =3D 0x98, - DW_IC_ENABLE_STATUS =3D 0x9c, - DW_IC_FS_SPKLEN =3D 0xa0, - DW_IC_CLR_RESTART_DET =3D 0xa8, - DW_IC_COMP_PARAM_1 =3D 0xf4, - DW_IC_COMP_VERSION =3D 0xf8, - DW_IC_COMP_TYPE =3D 0xfc, -}; - -/* DW_IC_CON fields */ -#define DW_IC_CON_STOP_DET_IF_MASTER_ACTIV BIT(10) -#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) -#define DW_IC_CON_TX_EMPTY_CTRL BIT(8) -#define DW_IC_CON_STOP_IF_ADDRESSED BIT(7) -#define DW_IC_CON_SLAVE_DISABLE BIT(6) -#define DW_IC_CON_IC_RESTART_EN BIT(5) -#define DW_IC_CON_10BITADDR_MASTER BIT(4) -#define DW_IC_CON_10BITADDR_SLAVE BIT(3) -#define DW_IC_CON_SPEED(rv) extract32((rv), 1, 2) -#define DW_IC_CON_MASTER_MODE BIT(0) - -/* DW_IC_TAR fields */ -#define DW_IC_TAR_IC_10BITADDR_MASTER BIT(12) -#define DW_IC_TAR_SPECIAL BIT(11) -#define DW_IC_TAR_GC_OR_START BIT(10) -#define DW_IC_TAR_ADDRESS(rv) extract32((rv), 0, 10) - -/* DW_IC_DATA_CMD fields */ -#define DW_IC_DATA_CMD_RESTART BIT(10) -#define DW_IC_DATA_CMD_STOP BIT(9) -#define DW_IC_DATA_CMD_CMD BIT(8) -#define DW_IC_DATA_CMD_DAT(rv) extract32((rv), 0, 8) - -/* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */ -#define DW_IC_INTR_RESTART_DET BIT(12) -#define DW_IC_INTR_GEN_CALL BIT(11) -#define DW_IC_INTR_START_DET BIT(10) -#define DW_IC_INTR_STOP_DET BIT(9) -#define DW_IC_INTR_ACTIVITY BIT(8) -#define DW_IC_INTR_RX_DONE BIT(7) -#define DW_IC_INTR_TX_ABRT BIT(6) -#define DW_IC_INTR_RD_REQ BIT(5) -#define DW_IC_INTR_TX_EMPTY BIT(4) /* Hardware clear only. */ -#define DW_IC_INTR_TX_OVER BIT(3) -#define DW_IC_INTR_RX_FULL BIT(2) /* Hardware clear only. */ -#define DW_IC_INTR_RX_OVER BIT(1) -#define DW_IC_INTR_RX_UNDER BIT(0) - -/* DW_IC_ENABLE fields */ -#define DW_IC_ENABLE_TX_CMD_BLOCK BIT(2) -#define DW_IC_ENABLE_ABORT BIT(1) -#define DW_IC_ENABLE_ENABLE BIT(0) - -/* DW_IC_STATUS fields */ -#define DW_IC_STATUS_SLV_ACTIVITY BIT(6) -#define DW_IC_STATUS_MST_ACTIVITY BIT(5) -#define DW_IC_STATUS_RFF BIT(4) -#define DW_IC_STATUS_RFNE BIT(3) -#define DW_IC_STATUS_TFE BIT(2) -#define DW_IC_STATUS_TFNF BIT(1) -#define DW_IC_STATUS_ACTIVITY BIT(0) - -/* DW_IC_TX_ABRT_SOURCE fields */ -#define DW_IC_TX_TX_FLUSH_CNT extract32((rv), 23, 9) -#define DW_IC_TX_ABRT_USER_ABRT BIT(16) -#define DW_IC_TX_ABRT_SLVRD_INTX BIT(15) -#define DW_IC_TX_ABRT_SLV_ARBLOST BIT(14) -#define DW_IC_TX_ABRT_SLVFLUSH_TXFIFO BIT(13) -#define DW_IC_TX_ARB_LOST BIT(12) -#define DW_IC_TX_ABRT_MASTER_DIS BIT(11) -#define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(10) -#define DW_IC_TX_ABRT_SBYTE_NORSTRT BIT(9) -#define DW_IC_TX_ABRT_HS_NORSTRT BIT(8) -#define DW_IC_TX_ABRT_SBYTE_ACKDET BIT(7) -#define DW_IC_TX_ABRT_HS_ACKDET BIT(6) -#define DW_IC_TX_ABRT_GCALL_READ BIT(5) -#define DW_IC_TX_ABRT_GCALL_NOACK BIT(4) -#define DW_IC_TX_ABRT_TXDATA_NOACK BIT(3) -#define DW_IC_TX_ABRT_10ADDR2_NOACK BIT(2) -#define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(1) -#define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(0) - - -/* IC_ENABLE_STATUS fields */ -#define DW_IC_ENABLE_STATUS_SLV_RX_DATA_LOST BIT(2) -#define DW_IC_ENABLE_STATUS_SLV_DISABLED_WHILE_BUSY BIT(1) -#define DW_IC_ENABLE_STATUS_IC_EN BIT(0) - -/* Masks for writable registers. */ -#define DW_IC_CON_MASK 0x000003ff -#define DW_IC_TAR_MASK 0x00000fff -#define DW_IC_SAR_MASK 0x000003ff -#define DW_IC_SS_SCL_HCNT_MASK 0x0000ffff -#define DW_IC_SS_SCL_LCNT_MASK 0x0000ffff -#define DW_IC_FS_SCL_HCNT_MASK 0x0000ffff -#define DW_IC_FS_SCL_LCNT_MASK 0x0000ffff -#define DW_IC_INTR_MASK_MASK 0x00001fff -#define DW_IC_ENABLE_MASK 0x00000007 -#define DW_IC_SDA_HOLD_MASK 0x00ffffff -#define DW_IC_SDA_SETUP_MASK 0x000000ff -#define DW_IC_FS_SPKLEN_MASK 0x000000ff - -/* Reset values */ -#define DW_IC_CON_INIT_VAL 0x7d -#define DW_IC_TAR_INIT_VAL 0x1055 -#define DW_IC_SAR_INIT_VAL 0x55 -#define DW_IC_SS_SCL_HCNT_INIT_VAL 0x190 -#define DW_IC_SS_SCL_LCNT_INIT_VAL 0x1d6 -#define DW_IC_FS_SCL_HCNT_INIT_VAL 0x3c -#define DW_IC_FS_SCL_LCNT_INIT_VAL 0x82 -#define DW_IC_INTR_MASK_INIT_VAL 0x8ff -#define DW_IC_STATUS_INIT_VAL 0x6 -#define DW_IC_SDA_HOLD_INIT_VAL 0x1 -#define DW_IC_SDA_SETUP_INIT_VAL 0x64 -#define DW_IC_FS_SPKLEN_INIT_VAL 0x2 - -#define DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS BIT(7) -#define DW_IC_COMP_PARAM_1_HAS_DMA 0 /* bit 6 - DMA disabled.= */ -#define DW_IC_COMP_PARAM_1_INTR_IO BIT(5) -#define DW_IC_COMP_PARAM_1_HC_COUNT_VAL 0 /* bit 4 - disabled */ -#define DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE (BIT(2) | BIT(3)) -#define DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32 BIT(1) /* bits 0, 1 */ -#define DW_IC_COMP_PARAM_1_INIT_VAL \ - (DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32 | \ - DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE | \ - DW_IC_COMP_PARAM_1_HC_COUNT_VAL | \ - DW_IC_COMP_PARAM_1_INTR_IO | \ - DW_IC_COMP_PARAM_1_HAS_DMA | \ - DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS | \ - ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1) << 8) | \ - ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1) << 16)) -#define DW_IC_COMP_VERSION_INIT_VAL 0x3132302a -#define DW_IC_COMP_TYPE_INIT_VAL 0x44570140 +#ifndef DESIGNWARE_I2C_ERR_DEBUG +#define DESIGNWARE_I2C_ERR_DEBUG 0 +#endif + +REG32(DW_IC_CON, 0x00) /* I2C control */ + FIELD(DW_IC_CON, STOP_DET_IF_MASTER_ACTIV, 10, 1) + FIELD(DW_IC_CON, RX_FIFO_FULL_HLD_CTRL, 9, 1) + FIELD(DW_IC_CON, TX_EMPTY_CTRL, 8, 1) + FIELD(DW_IC_CON, STOP_IF_ADDRESSED, 7, 1) + FIELD(DW_IC_CON, SLAVE_DISABLE, 6, 1) + FIELD(DW_IC_CON, IC_RESTART_EN, 5, 1) + FIELD(DW_IC_CON, 10BITADDR_MASTER, 4, 1) + FIELD(DW_IC_CON, 10BITADDR_SLAVE, 3, 1) + FIELD(DW_IC_CON, SPEED, 1, 2) + FIELD(DW_IC_CON, MASTER_MODE, 0, 1) +REG32(DW_IC_TAR, 0x04) /* I2C target address */ + FIELD(DW_IC_TAR, IC_10BITADDR_MASTER, 12, 1) + FIELD(DW_IC_TAR, SPECIAL, 11, 1) + FIELD(DW_IC_TAR, GC_OR_START, 10, 1) + FIELD(DW_IC_TAR, ADDRESS, 0, 10) +REG32(DW_IC_SAR, 0x08) /* I2C slave address */ +REG32(DW_IC_DATA_CMD, 0x10) + FIELD(DW_IC_DATA_CMD, RESTART, 10, 1) + FIELD(DW_IC_DATA_CMD, STOP, 9, 1) + FIELD(DW_IC_DATA_CMD, CMD, 8, 1) + FIELD(DW_IC_DATA_CMD, DAT, 0, 8) +REG32(DW_IC_SS_SCL_HCNT, 0x14) /* Standard speed i2c clock scl high= count */ +REG32(DW_IC_SS_SCL_LCNT, 0x18) /* Standard speed i2c clock scl low = count */ +REG32(DW_IC_FS_SCL_HCNT, 0x1c) /* Fast or fast plus i2c clock scl h= igh count */ +REG32(DW_IC_FS_SCL_LCNT, 0x20) /* Fast or fast plus i2c clock scl l= ow count */ +REG32(DW_IC_INTR_STAT, 0x2c) +REG32(DW_IC_INTR_MASK, 0x30) /* I2C Interrupt Mask */ +REG32(DW_IC_RAW_INTR_STAT, 0x34) /* I2C raw interrupt status */ + /* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */ + SHARED_FIELD(DW_IC_INTR_RESTART_DET, 12, 1) + SHARED_FIELD(DW_IC_INTR_GEN_CALL, 11, 1) + SHARED_FIELD(DW_IC_INTR_START_DET, 10, 1) + SHARED_FIELD(DW_IC_INTR_STOP_DET, 9, 1) + SHARED_FIELD(DW_IC_INTR_ACTIVITY, 8, 1) + SHARED_FIELD(DW_IC_INTR_RX_DONE, 7, 1) + SHARED_FIELD(DW_IC_INTR_TX_ABRT, 6, 1) + SHARED_FIELD(DW_IC_INTR_RD_REQ, 5, 1) + SHARED_FIELD(DW_IC_INTR_TX_EMPTY, 4, 1) /* Hardware clear only. */ + SHARED_FIELD(DW_IC_INTR_TX_OVER, 3, 1) + SHARED_FIELD(DW_IC_INTR_RX_FULL, 2, 1) /* Hardware clear only. */ + SHARED_FIELD(DW_IC_INTR_RX_OVER, 1, 1) + SHARED_FIELD(DW_IC_INTR_RX_UNDER, 0, 1) + +#define DW_IC_INTR_ANY_MASK \ + (DW_IC_INTR_RESTART_DET_MASK | \ + DW_IC_INTR_GEN_CALL_MASK | \ + DW_IC_INTR_START_DET_MASK | \ + DW_IC_INTR_STOP_DET_MASK | \ + DW_IC_INTR_ACTIVITY_MASK | \ + DW_IC_INTR_RX_DONE_MASK | \ + DW_IC_INTR_TX_ABRT_MASK | \ + DW_IC_INTR_RD_REQ_MASK | \ + DW_IC_INTR_TX_EMPTY_MASK | \ + DW_IC_INTR_TX_OVER_MASK | \ + DW_IC_INTR_RX_FULL_MASK | \ + DW_IC_INTR_RX_OVER_MASK | \ + DW_IC_INTR_RX_UNDER_MASK) + +#define DW_IC_INTR_ANY_SW_CLEAR_MASK \ + (DW_IC_INTR_ANY_MASK & \ + ~(DW_IC_INTR_TX_EMPTY_MASK | \ + DW_IC_INTR_RX_FULL_MASK)) + +REG32(DW_IC_RX_TL, 0x38) /* I2C receive FIFO threshold */ +REG32(DW_IC_TX_TL, 0x3c) /* I2C transmit FIFO threshold */ +REG32(DW_IC_CLR_INTR, 0x40) +REG32(DW_IC_CLR_RX_UNDER, 0x44) +REG32(DW_IC_CLR_RX_OVER, 0x48) +REG32(DW_IC_CLR_TX_OVER, 0x4c) +REG32(DW_IC_CLR_RD_REQ, 0x50) +REG32(DW_IC_CLR_TX_ABRT, 0x54) +REG32(DW_IC_CLR_RX_DONE, 0x58) +REG32(DW_IC_CLR_ACTIVITY, 0x5c) +REG32(DW_IC_CLR_STOP_DET, 0x60) +REG32(DW_IC_CLR_START_DET, 0x64) +REG32(DW_IC_CLR_GEN_CALL, 0x68) +REG32(DW_IC_ENABLE, 0x6c) /* I2C enable */ + FIELD(DW_IC_ENABLE, TX_CMD_BLOCK, 2, 1) + FIELD(DW_IC_ENABLE, ABORT, 1, 1) + FIELD(DW_IC_ENABLE, ENABLE, 0, 1) +REG32(DW_IC_STATUS, 0x70) /* I2C status */ + FIELD(DW_IC_STATUS, SLV_ACTIVITY, 6, 1) + FIELD(DW_IC_STATUS, MST_ACTIVITY, 5, 1) + FIELD(DW_IC_STATUS, RFF, 4, 1) + FIELD(DW_IC_STATUS, RFNE, 3, 1) + FIELD(DW_IC_STATUS, TFE, 2, 1) + FIELD(DW_IC_STATUS, TFNF, 1, 1) + FIELD(DW_IC_STATUS, ACTIVITY, 0, 1) +REG32(DW_IC_TXFLR, 0x74) /* I2C transmit fifo level */ +REG32(DW_IC_RXFLR, 0x78) /* I2C receive fifo level */ +REG32(DW_IC_SDA_HOLD, 0x7c) /* I2C SDA hold time length */ +REG32(DW_IC_TX_ABRT_SOURCE, 0x80) /* The I2C transmit abort source */ + FIELD(DW_IC_TX_ABRT_SOURCE, USER_ABRT, 16, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, SLVRD_INTX, 15, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, SLV_ARBLOST, 14, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, SLVFLUSH_TXFIFO, 13, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, ARB_LOST, 12, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, MASTER_DIS, 11, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, 10B_RD_NORSTRT, 10, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_NORSTRT, 9, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, HS_NORSTRT, 8, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_ACKDET, 7, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, HS_ACKDET, 6, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_READ, 5, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_NOACK, 4, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, TXDATA_NOACK, 3, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR2_NOACK, 2, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR1_NOACK, 1, 1) + FIELD(DW_IC_TX_ABRT_SOURCE, 7B_ADDR_NOACK, 0, 1) +REG32(DW_IC_SLV_DATA_NACK_ONLY, 0x84) +REG32(DW_IC_DMA_CR, 0x88) +REG32(DW_IC_DMA_TDLR, 0x8c) +REG32(DW_IC_DMA_RDLR, 0x90) +REG32(DW_IC_SDA_SETUP, 0x94) /* I2C SDA setup */ +REG32(DW_IC_ACK_GENERAL_CALL, 0x98) +REG32(DW_IC_ENABLE_STATUS, 0x9c) /* I2C enable status */ + FIELD(DW_IC_ENABLE_STATUS, SLV_RX_DATA_LOST, 2, 1) + FIELD(DW_IC_ENABLE_STATUS, SLV_DISABLED_WHILE_BUSY, 1, 1) + FIELD(DW_IC_ENABLE_STATUS, IC_EN, 0, 1) +REG32(DW_IC_FS_SPKLEN, 0xa0) /* I2C SS, FS or FM+ spike suppressi= on limit */ +REG32(DW_IC_CLR_RESTART_DET, 0xa8) +REG32(DW_IC_COMP_PARAM_1, 0xf4) /* Component parameter */ + FIELD(DW_IC_COMP_PARAM_1, TX_FIFO_SIZE, 16, 8) + FIELD(DW_IC_COMP_PARAM_1, RX_FIFO_SIZE, 8, 8) + FIELD(DW_IC_COMP_PARAM_1, HAS_ENCODED_PARAMS, 7, 1) + FIELD(DW_IC_COMP_PARAM_1, HAS_DMA, 6, 1) + FIELD(DW_IC_COMP_PARAM_1, INTR_IO, 5, 1) + FIELD(DW_IC_COMP_PARAM_1, HC_COUNT_VAL, 4, 1) + FIELD(DW_IC_COMP_PARAM_1, HIGH_SPEED_MODE, 2, 2) + FIELD(DW_IC_COMP_PARAM_1, APB_DATA_WIDTH_32, 0, 2) +REG32(DW_IC_COMP_VERSION, 0xf8) /* I2C component version */ +REG32(DW_IC_COMP_TYPE, 0xfc) /* I2C component type */ =20 static void dw_i2c_update_irq(DesignWareI2CState *s) { - int level; - uint32_t intr =3D s->ic_raw_intr_stat & s->ic_intr_mask; - - level =3D !!((intr & DW_IC_INTR_RX_UNDER) | - (intr & DW_IC_INTR_RX_OVER) | - (intr & DW_IC_INTR_RX_FULL) | - (intr & DW_IC_INTR_TX_OVER) | - (intr & DW_IC_INTR_TX_EMPTY) | - (intr & DW_IC_INTR_RD_REQ) | - (intr & DW_IC_INTR_TX_ABRT) | - (intr & DW_IC_INTR_RX_DONE) | - (intr & DW_IC_INTR_ACTIVITY) | - (intr & DW_IC_INTR_STOP_DET) | - (intr & DW_IC_INTR_START_DET) | - (intr & DW_IC_INTR_GEN_CALL) | - (intr & DW_IC_INTR_RESTART_DET) - ); - qemu_set_irq(s->irq, level); + uint32_t intr =3D s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INT= R_MASK]; + + qemu_set_irq(s->irq, !!(intr & DW_IC_INTR_ANY_MASK)); } =20 -static uint8_t dw_i2c_read_ic_data_cmd(DesignWareI2CState *s) +static uint64_t dw_ic_data_cmd_reg_post_read(RegisterInfo *reg, uint64_t v= alue) { + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + g_assert(value =3D=3D 0); + if (s->status !=3D DW_I2C_STATUS_RECEIVING) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempted to read from RX fifo when not in rece= ive " "state.\n", DEVICE(s)->canonical_path); if (s->status !=3D DW_I2C_STATUS_IDLE) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_UNDER; + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, + DW_IC_INTR_RX_UNDER, 1); dw_i2c_update_irq(s); } return 0; } =20 - g_assert(s->ic_rxflr =3D=3D fifo8_num_used(&s->rx_fifo)); + g_assert(s->regs[R_DW_IC_RXFLR] =3D=3D fifo8_num_used(&s->rx_fifo)); =20 if (fifo8_is_empty(&s->rx_fifo)) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_UNDER; + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR= _RX_UNDER, 1); dw_i2c_update_irq(s); return 0; } =20 - s->ic_rxflr--; - if (s->ic_rxflr <=3D s->ic_rx_tl) { - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; + s->regs[R_DW_IC_RXFLR]--; + if (s->regs[R_DW_IC_RXFLR] <=3D s->regs[R_DW_IC_RX_TL]) { + SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR= _RX_FULL, 0); dw_i2c_update_irq(s); } =20 return fifo8_pop(&s->rx_fifo); } =20 -static uint64_t dw_i2c_read(void *opaque, hwaddr offset, unsigned size) +static uint64_t dw_ic_clr_intr_reg_post_read(RegisterInfo *reg, uint64_t v= alue) { - uint64_t value =3D 0; + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); =20 - DesignWareI2CState *s =3D opaque; + g_assert(value =3D=3D 0); =20 - switch (offset) { - case DW_IC_CON: - value =3D s->ic_con; + switch (reg->access->addr) { + case A_DW_IC_CLR_INTR: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_ANY_SW_CLEAR_MASK; break; - case DW_IC_TAR: - value =3D s->ic_tar; + case A_DW_IC_CLR_RX_UNDER: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_UNDER_MASK; break; - case DW_IC_SAR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_sar\n", - DEVICE(s)->canonical_path); - value =3D s->ic_sar; - break; - case DW_IC_DATA_CMD: - value =3D dw_i2c_read_ic_data_cmd(s); - break; - case DW_IC_SS_SCL_HCNT: - value =3D s->ic_ss_scl_hcnt; + case A_DW_IC_CLR_RX_OVER: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_OVER_MASK; break; - case DW_IC_SS_SCL_LCNT: - value =3D s->ic_ss_scl_lcnt; + case A_DW_IC_CLR_TX_OVER: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_TX_OVER_MASK; break; - case DW_IC_FS_SCL_HCNT: - value =3D s->ic_fs_scl_hcnt; + case A_DW_IC_CLR_RD_REQ: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RD_REQ_MASK; break; - case DW_IC_FS_SCL_LCNT: - value =3D s->ic_fs_scl_lcnt; + case A_DW_IC_CLR_TX_ABRT: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_TX_ABRT_MASK; break; - case DW_IC_INTR_STAT: - value =3D s->ic_raw_intr_stat & s->ic_intr_mask; + case A_DW_IC_CLR_RX_DONE: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_DONE_MASK; break; - case DW_IC_INTR_MASK: - value =3D s->ic_intr_mask; + case A_DW_IC_CLR_ACTIVITY: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_ACTIVITY_MASK; break; - case DW_IC_RAW_INTR_STAT: - value =3D s->ic_raw_intr_stat; + case A_DW_IC_CLR_STOP_DET: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_STOP_DET_MASK; break; - case DW_IC_RX_TL: - value =3D s->ic_rx_tl; + case A_DW_IC_CLR_START_DET: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_START_DET_MASK; break; - case DW_IC_TX_TL: - value =3D s->ic_tx_tl; - break; - case DW_IC_CLR_INTR: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_GEN_CALL | - DW_IC_INTR_RESTART_DET | - DW_IC_INTR_START_DET | - DW_IC_INTR_STOP_DET | - DW_IC_INTR_ACTIVITY | - DW_IC_INTR_RX_DONE | - DW_IC_INTR_TX_ABRT | - DW_IC_INTR_RD_REQ | - DW_IC_INTR_TX_OVER | - DW_IC_INTR_RX_OVER | - DW_IC_INTR_RX_UNDER); - s->ic_tx_abrt_source =3D 0; - dw_i2c_update_irq(s); + case A_DW_IC_CLR_GEN_CALL: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_GEN_CALL_MASK; break; - case DW_IC_CLR_RX_UNDER: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_UNDER); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_RX_OVER: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_OVER); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_TX_OVER: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_TX_OVER); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_RD_REQ: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RD_REQ); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_TX_ABRT: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_TX_ABRT); - s->ic_tx_abrt_source =3D 0; - dw_i2c_update_irq(s); + case A_DW_IC_CLR_RESTART_DET: + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RESTART_DET_MASK; break; - case DW_IC_CLR_RX_DONE: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RX_DONE); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_ACTIVITY: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_ACTIVITY); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_STOP_DET: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_STOP_DET); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_START_DET: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_START_DET); - dw_i2c_update_irq(s); - break; - case DW_IC_CLR_GEN_CALL: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_GEN_CALL); - dw_i2c_update_irq(s); - break; - case DW_IC_ENABLE: - value =3D s->ic_enable; - break; - case DW_IC_STATUS: - value =3D s->ic_status; - break; - case DW_IC_TXFLR: - value =3D s->ic_txflr; - break; - case DW_IC_RXFLR: - value =3D s->ic_rxflr; - break; - case DW_IC_SDA_HOLD: - value =3D s->ic_sda_hold; - break; - case DW_IC_TX_ABRT_SOURCE: - value =3D s->ic_tx_abrt_source; - break; - case DW_IC_SLV_DATA_NACK_ONLY: - qemu_log_mask(LOG_UNIMP, - "%s: unsupported read - ic_slv_data_nack_only\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_CR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_cr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_TDLR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_tdlr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_RDLR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_dma_rdlr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_SDA_SETUP: - value =3D s->ic_sda_setup; - break; - case DW_IC_ACK_GENERAL_CALL: - qemu_log_mask(LOG_UNIMP, "%s: unsupported read - ic_ack_general_ca= ll\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_ENABLE_STATUS: - value =3D s->ic_enable_status; - break; - case DW_IC_FS_SPKLEN: - value =3D s->ic_fs_spklen; - break; - case DW_IC_CLR_RESTART_DET: - s->ic_raw_intr_stat &=3D ~(DW_IC_INTR_RESTART_DET); - dw_i2c_update_irq(s); - break; - case DW_IC_COMP_PARAM_1: - value =3D s->ic_comp_param_1; - break; - case DW_IC_COMP_VERSION: - value =3D s->ic_comp_version; - break; - case DW_IC_COMP_TYPE: - value =3D s->ic_comp_type; - break; - - /* This register is invalid at this point. */ default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: read from invalid offset 0x%" HWADDR_PRIx "\n", - DEVICE(s)->canonical_path, offset); - break; + g_assert_not_reached(); } =20 - trace_dw_i2c_read(DEVICE(s)->canonical_path, offset, value); + dw_i2c_update_irq(s); =20 - return value; + return 0; } =20 -static void dw_i2c_write_ic_con(DesignWareI2CState *s, uint32_t value) +static uint64_t dw_ic_intr_stat_reg_post_read(RegisterInfo *reg, uint64_t = value) { - if (value & DW_IC_CON_RX_FIFO_FULL_HLD_CTRL) { - qemu_log_mask(LOG_UNIMP, - "%s: unsupported ic_con flag - RX_FIFO_FULL_HLD_CTRL= \n", - DEVICE(s)->canonical_path); - } + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); =20 - if (!(s->ic_enable & DW_IC_ENABLE_ENABLE)) { - s->ic_con =3D value & DW_IC_CON_MASK; - } else { + g_assert(value =3D=3D 0); + + return s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INTR_MASK]; +} + +static uint64_t dw_ic_unsupported_reg_post_read(RegisterInfo *reg, uint64_= t value) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unsupported read - %s\n", + DEVICE(s)->canonical_path, reg->access->name); + + return 0; +} + +static uint64_t dw_ic_unsupported_reg_pre_write(RegisterInfo *reg, uint64_= t value) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unsupported write - %s\n", + DEVICE(s)->canonical_path, reg->access->name); + + return 0; +} + +static uint64_t dw_ic_con_reg_pre_write(RegisterInfo *reg, uint64_t value) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + if (s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid setting to ic_con %d when ic_enable[0]= =3D=3D1\n", - DEVICE(s)->canonical_path, value); + DEVICE(s)->canonical_path, (int)value); + return s->regs[R_DW_IC_CON]; /* keep old value */ } + + return value; } =20 static void dw_i2c_reset_to_idle(DesignWareI2CState *s) { - s->ic_enable_status &=3D ~DW_IC_ENABLE_STATUS_IC_EN; - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_TX_EMPTY; - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_UNDER; - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_OVER; - s->ic_rxflr =3D 0; + s->regs[R_DW_IC_ENABLE_STATUS] &=3D ~R_DW_IC_ENABLE_STATUS_IC_EN_M= ASK; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_TX_EMPTY_MASK; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_FULL_MASK; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_UNDER_MASK; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_OVER_MASK; + s->regs[R_DW_IC_RXFLR] =3D 0; fifo8_reset(&s->rx_fifo); - s->ic_status &=3D ~DW_IC_STATUS_ACTIVITY; + s->regs[R_DW_IC_STATUS] &=3D ~R_DW_IC_STATUS_ACTIVITY_MASK; s->status =3D DW_I2C_STATUS_IDLE; dw_i2c_update_irq(s); } =20 static void dw_ic_tx_abort(DesignWareI2CState *s, uint32_t src) { - s->ic_tx_abrt_source |=3D src; - s->ic_raw_intr_stat |=3D DW_IC_INTR_TX_ABRT; + s->regs[R_DW_IC_TX_ABRT_SOURCE] |=3D src; + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_TX_ABRT_MASK; dw_i2c_reset_to_idle(s); dw_i2c_update_irq(s); } =20 -static void dw_i2c_write_ic_data_cmd(DesignWareI2CState *s, uint32_t value) +static void dw_ic_data_cmd_reg_post_write(RegisterInfo *reg, uint64_t valu= e) { - int recv =3D !!(value & DW_IC_DATA_CMD_CMD); + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + int recv =3D !!(value & R_DW_IC_DATA_CMD_CMD_MASK); + + s->regs[R_DW_IC_DATA_CMD] =3D 0; /* Register has no storage */ =20 if (s->status =3D=3D DW_I2C_STATUS_IDLE || - s->ic_raw_intr_stat & DW_IC_INTR_TX_ABRT) { + s->regs[R_DW_IC_RAW_INTR_STAT] & DW_IC_INTR_TX_ABRT_MASK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempted to write to TX fifo when it is held i= n " "reset.\n", DEVICE(s)->canonical_path); @@ -470,9 +330,10 @@ static void dw_i2c_write_ic_data_cmd(DesignWareI2CStat= e *s, uint32_t value) =20 /* Send the address if it hasn't been sent yet. */ if (s->status =3D=3D DW_I2C_STATUS_SENDING_ADDRESS) { - int rv =3D i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar)= , recv); + int rv =3D i2c_start_transfer(s->bus, + ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv); if (rv) { - dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK); + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK); return; } s->status =3D recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDI= NG; @@ -480,25 +341,27 @@ static void dw_i2c_write_ic_data_cmd(DesignWareI2CSta= te *s, uint32_t value) =20 /* Send data */ if (!recv) { - int rv =3D i2c_send(s->bus, DW_IC_DATA_CMD_DAT(value)); + int rv =3D i2c_send(s->bus, FIELD_EX32(value, DW_IC_DATA_CMD, DAT)= ); if (rv) { i2c_end_transfer(s->bus); - dw_ic_tx_abort(s, DW_IC_TX_ABRT_TXDATA_NOACK); + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_TXDATA_NOACK_MASK); return; } dw_i2c_update_irq(s); } =20 /* Restart command */ - if (value & DW_IC_DATA_CMD_RESTART && s->ic_con & DW_IC_CON_IC_RESTART= _EN) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RESTART_DET | - DW_IC_INTR_START_DET | - DW_IC_INTR_ACTIVITY; - s->ic_status |=3D DW_IC_STATUS_ACTIVITY; + if (value & R_DW_IC_DATA_CMD_RESTART_MASK && + s->regs[R_DW_IC_CON] & R_DW_IC_CON_IC_RESTART_EN_MASK) { + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_RESTART_DET_MASK | + DW_IC_INTR_START_DET_MASK | + DW_IC_INTR_ACTIVITY_MASK; + s->regs[R_DW_IC_STATUS] |=3D R_DW_IC_STATUS_ACTIVITY_MASK; dw_i2c_update_irq(s); =20 - if (i2c_start_transfer(s->bus, DW_IC_TAR_ADDRESS(s->ic_tar), recv)= ) { - dw_ic_tx_abort(s, DW_IC_TX_ABRT_7B_ADDR_NOACK); + if (i2c_start_transfer(s->bus, + ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv)) { + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK); return; } =20 @@ -507,87 +370,113 @@ static void dw_i2c_write_ic_data_cmd(DesignWareI2CSt= ate *s, uint32_t value) =20 /* Receive data */ if (recv) { - g_assert(s->ic_rxflr =3D=3D fifo8_num_used(&s->rx_fifo)); + g_assert(s->regs[R_DW_IC_RXFLR] =3D=3D fifo8_num_used(&s->rx_fifo)= ); =20 if (!fifo8_is_full(&s->rx_fifo)) { fifo8_push(&s->rx_fifo, i2c_recv(s->bus)); - s->ic_rxflr++; + s->regs[R_DW_IC_RXFLR]++; } else { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_OVER; + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_RX_OVER_MASK; dw_i2c_update_irq(s); } =20 - if (s->ic_rxflr > s->ic_rx_tl) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_FULL; + if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL]) { + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_RX_FULL_MASK; dw_i2c_update_irq(s); } - if (value & DW_IC_DATA_CMD_STOP) { + if (value & R_DW_IC_DATA_CMD_STOP_MASK) { i2c_nack(s->bus); } } =20 /* Stop command */ - if (value & DW_IC_DATA_CMD_STOP) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_STOP_DET; - s->ic_status &=3D ~DW_IC_STATUS_ACTIVITY; - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_TX_EMPTY; + if (value & R_DW_IC_DATA_CMD_STOP_MASK) { + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_STOP_DET_MASK; + s->regs[R_DW_IC_STATUS] &=3D ~R_DW_IC_STATUS_ACTIVITY_MASK; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_TX_EMPTY_MASK; i2c_end_transfer(s->bus); dw_i2c_update_irq(s); } } =20 -static void dw_i2c_write_ic_enable(DesignWareI2CState *s, uint32_t value) +static void dw_ic_intr_mask_reg_post_write(RegisterInfo *reg, uint64_t val= ue) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + dw_i2c_update_irq(s); +} + +static uint64_t dw_ic_enable_reg_pre_write(RegisterInfo *reg, uint64_t val= ue) { - if (value & DW_IC_ENABLE_ENABLE && !(s->ic_con & DW_IC_CON_SLAVE_DISAB= LE)) { + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + if (value & R_DW_IC_ENABLE_ENABLE_MASK && + !(s->regs[R_DW_IC_CON] & R_DW_IC_CON_SLAVE_DISABLE_MASK)) { qemu_log_mask(LOG_UNIMP, "%s: Designware I2C slave mode is not supported.\n", DEVICE(s)->canonical_path); - return; + return s->regs[R_DW_IC_ENABLE]; /* keep old value */ } =20 - s->ic_enable =3D value & DW_IC_ENABLE_MASK; + return value; +} + +static void dw_ic_enable_reg_post_write(RegisterInfo *reg, uint64_t value) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + s->regs[R_DW_IC_ENABLE] =3D value & R_DW_IC_ENABLE_ENABLE_MASK; =20 - if (value & DW_IC_ENABLE_ABORT || value & DW_IC_ENABLE_TX_CMD_BLOCK) { - dw_ic_tx_abort(s, DW_IC_TX_ABRT_USER_ABRT); + if (value & R_DW_IC_ENABLE_ABORT_MASK || value & R_DW_IC_ENABLE_TX_CMD= _BLOCK_MASK) { + dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_USER_ABRT_MASK); return; } =20 - if (value & DW_IC_ENABLE_ENABLE) { - s->ic_enable_status |=3D DW_IC_ENABLE_STATUS_IC_EN; - s->ic_status |=3D DW_IC_STATUS_ACTIVITY; - s->ic_raw_intr_stat |=3D DW_IC_INTR_ACTIVITY | - DW_IC_INTR_START_DET | - DW_IC_INTR_TX_EMPTY; + if (value & R_DW_IC_ENABLE_ENABLE_MASK) { + s->regs[R_DW_IC_ENABLE_STATUS] |=3D R_DW_IC_ENABLE_STATUS_IC_EN_MA= SK; + s->regs[R_DW_IC_STATUS] |=3D R_DW_IC_STATUS_ACTIVITY_MASK; + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_ACTIVITY_MASK | + DW_IC_INTR_START_DET_MASK | + DW_IC_INTR_TX_EMPTY_MASK; s->status =3D DW_I2C_STATUS_SENDING_ADDRESS; dw_i2c_update_irq(s); - } else if ((value & DW_IC_ENABLE_ENABLE) =3D=3D 0) { + } else if ((value & R_DW_IC_ENABLE_ENABLE_MASK) =3D=3D 0) { dw_i2c_reset_to_idle(s); } - } =20 -static void dw_i2c_write_ic_rx_tl(DesignWareI2CState *s, uint32_t value) +static uint64_t dw_ic_rx_tl_reg_pre_write(RegisterInfo *reg, uint64_t valu= e) { + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + /* Note that a value of 0 for ic_rx_tl indicates a threashold of 1. */ if (value > DESIGNWARE_I2C_RX_FIFO_SIZE - 1) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid setting to ic_rx_tl %d\n", - DEVICE(s)->canonical_path, value); - s->ic_rx_tl =3D DESIGNWARE_I2C_RX_FIFO_SIZE - 1; - } else { - s->ic_rx_tl =3D value; + DEVICE(s)->canonical_path, (int)value); + return DESIGNWARE_I2C_RX_FIFO_SIZE - 1; } =20 - if (s->ic_rxflr > s->ic_rx_tl && s->ic_enable & DW_IC_ENABLE_ENABLE) { - s->ic_raw_intr_stat |=3D DW_IC_INTR_RX_FULL; + return value; +} + +static void dw_ic_rx_tl_reg_post_write(RegisterInfo *reg, uint64_t value) +{ + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + + if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL] && + s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) { + s->regs[R_DW_IC_RAW_INTR_STAT] |=3D DW_IC_INTR_RX_FULL_MASK; } else { - s->ic_raw_intr_stat &=3D ~DW_IC_INTR_RX_FULL; + s->regs[R_DW_IC_RAW_INTR_STAT] &=3D ~DW_IC_INTR_RX_FULL_MASK; } dw_i2c_update_irq(s); } =20 -static void dw_i2c_write_ic_tx_tl(DesignWareI2CState *s, uint32_t value) +static uint64_t dw_ic_tx_tl_reg_pre_write(RegisterInfo *reg, uint64_t valu= e) { + DesignWareI2CState *s =3D DESIGNWARE_I2C(reg->opaque); + /* * Note that a value of 0 for ic_tx_tl indicates a threashold of 1. * However, the tx threshold is not used in the model because commands= are @@ -596,106 +485,154 @@ static void dw_i2c_write_ic_tx_tl(DesignWareI2CStat= e *s, uint32_t value) if (value > DESIGNWARE_I2C_TX_FIFO_SIZE - 1) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid setting to ic_tx_tl %d\n", - DEVICE(s)->canonical_path, value); - s->ic_tx_tl =3D DESIGNWARE_I2C_TX_FIFO_SIZE - 1; - } else { - s->ic_tx_tl =3D value; + DEVICE(s)->canonical_path, (int)value); + return DESIGNWARE_I2C_TX_FIFO_SIZE - 1; } -} =20 -static void dw_i2c_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - DesignWareI2CState *s =3D opaque; - - trace_dw_i2c_write(DEVICE(s)->canonical_path, offset, value); - - /* The order of the registers are their order in memory. */ - switch (offset) { - case DW_IC_CON: - dw_i2c_write_ic_con(s, value); - break; - case DW_IC_TAR: - s->ic_tar =3D value & DW_IC_TAR_MASK; - break; - case DW_IC_SAR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_sar\n", - DEVICE(s)->canonical_path); - s->ic_sar =3D value & DW_IC_SAR_MASK; - break; - case DW_IC_DATA_CMD: - dw_i2c_write_ic_data_cmd(s, value); - break; - case DW_IC_SS_SCL_HCNT: - s->ic_ss_scl_hcnt =3D value & DW_IC_SS_SCL_HCNT_MASK; - break; - case DW_IC_SS_SCL_LCNT: - s->ic_ss_scl_lcnt =3D value & DW_IC_SS_SCL_LCNT_MASK; - break; - case DW_IC_FS_SCL_HCNT: - s->ic_fs_scl_hcnt =3D value & DW_IC_FS_SCL_HCNT_MASK; - break; - case DW_IC_FS_SCL_LCNT: - s->ic_fs_scl_lcnt =3D value & DW_IC_FS_SCL_LCNT_MASK; - break; - case DW_IC_INTR_MASK: - s->ic_intr_mask =3D value & DW_IC_INTR_MASK_MASK; - dw_i2c_update_irq(s); - break; - case DW_IC_RX_TL: - dw_i2c_write_ic_rx_tl(s, value); - break; - case DW_IC_TX_TL: - dw_i2c_write_ic_tx_tl(s, value); - break; - case DW_IC_ENABLE: - dw_i2c_write_ic_enable(s, value); - break; - case DW_IC_SDA_HOLD: - s->ic_sda_hold =3D value & DW_IC_SDA_HOLD_MASK; - break; - case DW_IC_SLV_DATA_NACK_ONLY: - qemu_log_mask(LOG_UNIMP, - "%s: unsupported write - ic_slv_data_nack_only\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_CR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_cr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_TDLR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_tdlr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_DMA_RDLR: - qemu_log_mask(LOG_UNIMP, "%s: unsupported write - ic_dma_rdlr\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_SDA_SETUP: - s->ic_sda_setup =3D value & DW_IC_SDA_SETUP_MASK; - break; - case DW_IC_ACK_GENERAL_CALL: - qemu_log_mask(LOG_UNIMP, - "%s: unsupported write - ic_ack_general_call\n", - DEVICE(s)->canonical_path); - break; - case DW_IC_FS_SPKLEN: - s->ic_fs_spklen =3D value & DW_IC_FS_SPKLEN_MASK; - break; + return value; +} =20 - /* This register is invalid at this point. */ - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: write to invalid offset or readonly register 0x= %" - HWADDR_PRIx "\n", - DEVICE(s)->canonical_path, offset); - break; +static const RegisterAccessInfo designware_i2c_regs_info[] =3D { + { .name =3D "DW_IC_CON", .addr =3D A_DW_IC_CON, + .reset =3D 0x7d, + .unimp =3D 0xfffffc00, + .unimp =3D R_DW_IC_CON_RX_FIFO_FULL_HLD_CTRL_MASK, + .pre_write =3D dw_ic_con_reg_pre_write, + },{ .name =3D "DW_IC_TAR", .addr =3D A_DW_IC_TAR, + .reset =3D 0x1055, + .unimp =3D 0xfffff000, + },{ .name =3D "DW_IC_SAR", .addr =3D A_DW_IC_SAR, + .reset =3D 0x55, + .unimp =3D 0xfffffc00, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_DATA_CMD", .addr =3D A_DW_IC_DATA_CMD, + .post_read =3D dw_ic_data_cmd_reg_post_read, + .post_write =3D dw_ic_data_cmd_reg_post_write, + },{ .name =3D "DW_IC_SS_SCL_HCNT", .addr =3D A_DW_IC_SS_SCL_HCNT, + .reset =3D 0x190, + .unimp =3D 0xffff0000, + },{ .name =3D "DW_IC_SS_SCL_LCNT", .addr =3D A_DW_IC_SS_SCL_LCNT, + .reset =3D 0x1d6, + .unimp =3D 0xffff0000, + },{ .name =3D "DW_IC_FS_SCL_HCNT", .addr =3D A_DW_IC_FS_SCL_HCNT, + .reset =3D 0x3c, + .unimp =3D 0xffff0000, + },{ .name =3D "DW_IC_FS_SCL_LCNT", .addr =3D A_DW_IC_FS_SCL_LCNT, + .reset =3D 0x82, + .unimp =3D 0xffff0000, + },{ .name =3D "DW_IC_INTR_STAT", .addr =3D A_DW_IC_INTR_STAT, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_intr_stat_reg_post_read, + },{ .name =3D "DW_IC_INTR_MASK", .addr =3D A_DW_IC_INTR_MASK, + .reset =3D 0x8ff, + .unimp =3D 0xffff8000, + .post_write =3D dw_ic_intr_mask_reg_post_write, + },{ .name =3D "DW_IC_RAW_INTR_STAT", .addr =3D A_DW_IC_RAW_INTR_STAT, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_RX_TL", .addr =3D A_DW_IC_RX_TL, + .pre_write =3D dw_ic_rx_tl_reg_pre_write, + .post_write =3D dw_ic_rx_tl_reg_post_write, + },{ .name =3D "DW_IC_TX_TL", .addr =3D A_DW_IC_TX_TL, + .pre_write =3D dw_ic_tx_tl_reg_pre_write, + },{ .name =3D "DW_IC_CLR_INTR", .addr =3D A_DW_IC_CLR_INTR, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_RX_UNDER", .addr =3D A_DW_IC_CLR_RX_UNDER, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_RX_OVER", .addr =3D A_DW_IC_CLR_RX_OVER, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_TX_OVER", .addr =3D A_DW_IC_CLR_TX_OVER, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_RD_REQ", .addr =3D A_DW_IC_CLR_RD_REQ, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_TX_ABRT", .addr =3D A_DW_IC_CLR_TX_ABRT, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_RX_DONE", .addr =3D A_DW_IC_CLR_RX_DONE, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_ACTIVITY", .addr =3D A_DW_IC_CLR_ACTIVITY, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_STOP_DET", .addr =3D A_DW_IC_CLR_STOP_DET, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_START_DET", .addr =3D A_DW_IC_CLR_START_DET, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_CLR_GEN_CALL", .addr =3D A_DW_IC_CLR_GEN_CALL, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_ENABLE", .addr =3D A_DW_IC_ENABLE, + .unimp =3D 0xfffffff8, + .pre_write =3D dw_ic_enable_reg_pre_write, + .post_write =3D dw_ic_enable_reg_post_write, + },{ .name =3D "DW_IC_STATUS", .addr =3D A_DW_IC_STATUS, + .reset =3D 0x6, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_TXFLR", .addr =3D A_DW_IC_TXFLR, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_RXFLR", .addr =3D A_DW_IC_RXFLR, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_SDA_HOLD", .addr =3D A_DW_IC_SDA_HOLD, + .reset =3D 0x1, + .unimp =3D 0xff000000, + },{ .name =3D "DW_IC_TX_ABRT_SOURCE", .addr =3D A_DW_IC_TX_ABRT_SOURC= E, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_SLV_DATA_NACK_ONLY", .addr =3D A_DW_IC_SLV_DATA_= NACK_ONLY, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_DMA_CR", .addr =3D A_DW_IC_DMA_CR, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_DMA_TDLR", .addr =3D A_DW_IC_DMA_TDLR, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_DMA_RDLR", .addr =3D A_DW_IC_DMA_RDLR, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_SDA_SETUP", .addr =3D A_DW_IC_SDA_SETUP, + .reset =3D 0x64, + .unimp =3D 0xffffff00, + },{ .name =3D "DW_IC_ACK_GENERAL_CALL", .addr =3D A_DW_IC_ACK_GENERAL= _CALL, + .post_read =3D dw_ic_unsupported_reg_post_read, + .pre_write =3D dw_ic_unsupported_reg_pre_write, + },{ .name =3D "DW_IC_ENABLE_STATUS", .addr =3D A_DW_IC_ENABLE_STATUS, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_FS_SPKLEN", .addr =3D A_DW_IC_FS_SPKLEN, + .reset =3D 0x2, + .ro =3D 0xffffff00, + },{ .name =3D "DW_IC_CLR_RESTART_DET", .addr =3D A_DW_IC_CLR_RESTART_= DET, + .ro =3D 0xffffffff, + .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_COMP_PARAM_1", .addr =3D A_DW_IC_COMP_PARAM_1, + .reset =3D /* HAS_DMA and HC_COUNT_VAL are disabled */ + ((2 << R_DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32_SHIFT) | + R_DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE_MASK | + R_DW_IC_COMP_PARAM_1_INTR_IO_MASK | + R_DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS_MASK | + ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1) + << R_DW_IC_COMP_PARAM_1_RX_FIFO_SIZE_SHIFT) | + ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1) + << R_DW_IC_COMP_PARAM_1_TX_FIFO_SIZE_SHIFT)), + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_COMP_VERSION", .addr =3D A_DW_IC_COMP_VERSION, + .reset =3D 0x3132302a, + .ro =3D 0xffffffff, + },{ .name =3D "DW_IC_COMP_TYPE", .addr =3D A_DW_IC_COMP_TYPE, + .reset =3D 0x44570140, + .ro =3D 0xffffffff, } -} +}; =20 static const MemoryRegionOps designware_i2c_ops =3D { - .read =3D dw_i2c_read, - .write =3D dw_i2c_write, + .read =3D register_read_memory, + .write =3D register_write_memory, .endianness =3D DEVICE_LITTLE_ENDIAN, .impl =3D { .min_access_size =3D 4, @@ -711,30 +648,11 @@ static const MemoryRegionOps designware_i2c_ops =3D { static void designware_i2c_enter_reset(Object *obj, ResetType type) { DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); + unsigned int i; =20 - s->ic_con =3D DW_IC_CON_INIT_VAL; - s->ic_tar =3D DW_IC_TAR_INIT_VAL; - s->ic_sar =3D DW_IC_SAR_INIT_VAL; - s->ic_ss_scl_hcnt =3D DW_IC_SS_SCL_HCNT_INIT_VAL; - s->ic_ss_scl_lcnt =3D DW_IC_SS_SCL_LCNT_INIT_VAL; - s->ic_fs_scl_hcnt =3D DW_IC_FS_SCL_HCNT_INIT_VAL; - s->ic_fs_scl_lcnt =3D DW_IC_FS_SCL_LCNT_INIT_VAL; - s->ic_intr_mask =3D DW_IC_INTR_MASK_INIT_VAL; - s->ic_raw_intr_stat =3D 0; - s->ic_rx_tl =3D 0; - s->ic_tx_tl =3D 0; - s->ic_enable =3D 0; - s->ic_status =3D DW_IC_STATUS_INIT_VAL; - s->ic_txflr =3D 0; - s->ic_rxflr =3D 0; - s->ic_sda_hold =3D DW_IC_SDA_HOLD_INIT_VAL; - s->ic_tx_abrt_source =3D 0; - s->ic_sda_setup =3D DW_IC_SDA_SETUP_INIT_VAL; - s->ic_enable_status =3D 0; - s->ic_fs_spklen =3D DW_IC_FS_SPKLEN_INIT_VAL; - s->ic_comp_param_1 =3D DW_IC_COMP_PARAM_1_INIT_VAL; - s->ic_comp_version =3D DW_IC_COMP_VERSION_INIT_VAL; - s->ic_comp_type =3D DW_IC_COMP_TYPE_INIT_VAL; + for (i =3D 0; i < ARRAY_SIZE(s->regs); ++i) { + register_reset(&s->regs_info[i]); + } =20 fifo8_reset(&s->rx_fifo); =20 @@ -753,29 +671,7 @@ static const VMStateDescription vmstate_designware_i2c= =3D { .version_id =3D 0, .minimum_version_id =3D 0, .fields =3D (const VMStateField[]) { - VMSTATE_UINT32(ic_con, DesignWareI2CState), - VMSTATE_UINT32(ic_tar, DesignWareI2CState), - VMSTATE_UINT32(ic_sar, DesignWareI2CState), - VMSTATE_UINT32(ic_ss_scl_hcnt, DesignWareI2CState), - VMSTATE_UINT32(ic_ss_scl_lcnt, DesignWareI2CState), - VMSTATE_UINT32(ic_fs_scl_hcnt, DesignWareI2CState), - VMSTATE_UINT32(ic_fs_scl_lcnt, DesignWareI2CState), - VMSTATE_UINT32(ic_intr_mask, DesignWareI2CState), - VMSTATE_UINT32(ic_raw_intr_stat, DesignWareI2CState), - VMSTATE_UINT32(ic_rx_tl, DesignWareI2CState), - VMSTATE_UINT32(ic_tx_tl, DesignWareI2CState), - VMSTATE_UINT32(ic_enable, DesignWareI2CState), - VMSTATE_UINT32(ic_status, DesignWareI2CState), - VMSTATE_UINT32(ic_txflr, DesignWareI2CState), - VMSTATE_UINT32(ic_rxflr, DesignWareI2CState), - VMSTATE_UINT32(ic_sda_hold, DesignWareI2CState), - VMSTATE_UINT32(ic_tx_abrt_source, DesignWareI2CState), - VMSTATE_UINT32(ic_sda_setup, DesignWareI2CState), - VMSTATE_UINT32(ic_enable_status, DesignWareI2CState), - VMSTATE_UINT32(ic_fs_spklen, DesignWareI2CState), - VMSTATE_UINT32(ic_comp_param_1, DesignWareI2CState), - VMSTATE_UINT32(ic_comp_version, DesignWareI2CState), - VMSTATE_UINT32(ic_comp_type, DesignWareI2CState), + VMSTATE_UINT32_ARRAY(regs, DesignWareI2CState, DESIGNWARE_I2C_R_MA= X), VMSTATE_FIFO8(rx_fifo, DesignWareI2CState), VMSTATE_UINT32(status, DesignWareI2CState), VMSTATE_END_OF_LIST(), @@ -786,6 +682,7 @@ static void designware_i2c_smbus_init(Object *obj) { DesignWareI2CState *s =3D DESIGNWARE_I2C(obj); SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + RegisterInfoArray *reg_array; =20 fifo8_create(&s->rx_fifo, DESIGNWARE_I2C_RX_FIFO_SIZE); =20 @@ -796,6 +693,15 @@ static void designware_i2c_smbus_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); =20 s->bus =3D i2c_init_bus(DEVICE(s), "i2c-bus"); + + memory_region_init(&s->iomem, obj, TYPE_DESIGNWARE_I2C, 4 * KiB); + reg_array =3D register_init_block32(DEVICE(obj), designware_i2c_regs_i= nfo, + ARRAY_SIZE(designware_i2c_regs_info), + s->regs_info, s->regs, + &designware_i2c_ops, + DESIGNWARE_I2C_ERR_DEBUG, + DESIGNWARE_I2C_R_MAX * 4); + memory_region_add_subregion(&s->iomem, 0, ®_array->mem); } =20 static void designware_i2c_finalize(Object *obj) diff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2= c.h index affaf983a2..54112c38e7 100644 --- a/include/hw/i2c/designware_i2c.h +++ b/include/hw/i2c/designware_i2c.h @@ -11,9 +11,11 @@ #include "qemu/fifo8.h" #include "hw/i2c/i2c.h" #include "hw/core/irq.h" +#include "hw/core/register.h" #include "hw/core/sysbus.h" =20 -/* Size of the FIFO buffers. */ +#define DESIGNWARE_I2C_R_MAX (0x100 / 4) + #define DESIGNWARE_I2C_RX_FIFO_SIZE 16 #define DESIGNWARE_I2C_TX_FIFO_SIZE 16 =20 @@ -28,31 +30,6 @@ typedef enum DesignWareI2CStatus { * struct DesignWareI2CState - DesignWare I2C device state. * @bus: The underlying I2C Bus * @irq: GIC interrupt line to fire on events - * @ic_con: : I2C control register - * @ic_tar: I2C target address register - * @ic_sar: I2C slave address register - * @ic_ss_scl_hcnt: Standard speed i2c clock scl high count register - * @ic_ss_scl_lcnt: Standard speed i2c clock scl low count register - * @ic_fs_scl_hcnt: Fast mode or fast mode plus i2c clock scl high count - * register - * @ic_fs_scl_lcnt:Fast mode or fast mode plus i2c clock scl low count - * register - * @ic_intr_mask: I2C Interrupt Mask Register - * @ic_raw_intr_stat: I2C raw interrupt status register - * @ic_rx_tl: I2C receive FIFO threshold register - * @ic_tx_tl: I2C transmit FIFO threshold register - * @ic_enable: I2C enable register - * @ic_status: I2C status register - * @ic_txflr: I2C transmit fifo level register - * @ic_rxflr: I2C receive fifo level register - * @ic_sda_hold: I2C SDA hold time length register - * @ic_tx_abrt_source: The I2C transmit abort source register - * @ic_sda_setup: I2C SDA setup register - * @ic_enable_status: I2C enable status register - * @ic_fs_spklen: I2C SS, FS or FM+ spike suppression limit - * @ic_comp_param_1: Component parameter register - * @ic_comp_version: I2C component version register - * @ic_comp_type: I2C component type register * @rx_fifo: The FIFO buffer for receiving in FIFO mode. */ typedef struct DesignWareI2CState { @@ -63,31 +40,10 @@ typedef struct DesignWareI2CState { I2CBus *bus; qemu_irq irq; =20 - uint32_t ic_con; - uint32_t ic_tar; - uint32_t ic_sar; - uint32_t ic_ss_scl_hcnt; - uint32_t ic_ss_scl_lcnt; - uint32_t ic_fs_scl_hcnt; - uint32_t ic_fs_scl_lcnt; - uint32_t ic_intr_mask; - uint32_t ic_raw_intr_stat; - uint32_t ic_rx_tl; - uint32_t ic_tx_tl; - uint32_t ic_enable; - uint32_t ic_status; - uint32_t ic_txflr; - uint32_t ic_rxflr; - uint32_t ic_sda_hold; - uint32_t ic_tx_abrt_source; - uint32_t ic_sda_setup; - uint32_t ic_enable_status; - uint32_t ic_fs_spklen; - uint32_t ic_comp_param_1; - uint32_t ic_comp_version; - uint32_t ic_comp_type; + uint32_t regs[DESIGNWARE_I2C_R_MAX]; + RegisterInfo regs_info[DESIGNWARE_I2C_R_MAX]; =20 - /* fifo8_num_used(rx_fifo) should always equal ic_rxflr */ + /* fifo8_num_used(rx_fifo) should always equal DW_IC_RXFLR */ Fifo8 rx_fifo; =20 DesignWareI2CStatus status; --=20 2.53.0 From nobody Sat May 30 16:35:39 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1778155651; cv=none; d=zohomail.com; s=zohoarc; b=LvVY7mkaYzpgyTb8SA8SHuRur3sr/VmIczTNSnaFlJ5Zs1PhEJBN+wK/kg7rHMtPJtMhr1jFeue45IhCDKNvhXBUjtoAy5drdquEZQwDgPXZBoSqiTKz7tT+hsy9pBqxoHnEHFYKbEiU9OnS7znI52UQt0C+eNKHlGV7OE5TIvg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1778155651; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Z6f/BxqM4oPn2RXFraAVD3TGlPXbRYNoGHUCSl7Ed+w=; b=euIqgYYcad4R3Ggrop/xtgEjsLiHwSaF3mgeS6HhZTg4dWUqEwcoZPbTUD3MWeFR2IBhEEVQii7z0fZSCFHYmwaeJMBVUDOu3zNX5W5ejWyAdEV5LjIuiztAdSspMeAgAHQ1xOQGoLeZCwY36UPO2yVmkVZYwAZ65NCrUKIrrMg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1778155651555391.8252920444579; Thu, 7 May 2026 05:07:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wKxUY-00005m-Pd; Thu, 07 May 2026 08:06:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wKxUL-0008V4-Ro for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:58 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wKxUK-0002CW-EC for qemu-devel@nongnu.org; Thu, 07 May 2026 08:05:57 -0400 Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-83659d38e38so290755b3a.1 for ; Thu, 07 May 2026 05:05:56 -0700 (PDT) Received: from localhost (124.158.97.178.qld.leaptel.network. [124.158.97.178]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965945c1bsm9028002b3a.15.2026.05.07.05.05.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 05:05:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778155555; x=1778760355; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Z6f/BxqM4oPn2RXFraAVD3TGlPXbRYNoGHUCSl7Ed+w=; b=UecgS1XmZCx5uy0YsgSwuYzels+aumMybTpEbqSQ2Cg0VGLDFEWN44ReY981USPbGF HKKWFS8pZd0Oins8Ka8okrobNjl7ZbxIZjcUW9SNDYU2QAsMvky3GYvNoECD71ac7UhA U3sxnCSTTm883c5zEnYCMKKUvjg70FHeLw1lmmw+ab+zdP3DBHLOpsh8P9MBicAG9SSI hFP7cgiXN6WDtNlySgGe2Zcym7z0ZcUzT9HWIxb7oymuZcRB3M4/ZnB/mqWTG5glwrxB tLBMP1KU7QMYVLGEKuCNobVoTziy7lDXNhO1eHDMn7q3NYTAE2IjXj1djdXPUfmQz7Kf bDaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778155555; x=1778760355; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Z6f/BxqM4oPn2RXFraAVD3TGlPXbRYNoGHUCSl7Ed+w=; b=eYbXQpZmudkaln9UZO3ciV3JQPoDiSMsbk3K4mJodnGgL15wYoTV4k5F9wvn4rjx+Y 4jzkBguFOPkDox7nkPNKhBEkuvBq1F4iObTxIOAzvnU/MVr8qsN0SNVD2RPEH4XW3Noh ZeQKOJS1cvOu3CwFgZF88lJE7AEXwlRoly7B5gHc2jop+so9oRAhwJXe1h8vrD9v3iZK ZBOfEZ+3zXQ454fj5JYwIMnAcrUkQoSKd5buq3Sv5yB9iQk2XArgMABR8XCX24GcDDV3 Zv0y3/LSC+/KztKNC4khJPyLnnQVb2LgNoJXpbDfEPQxfLhmIRWPwYAAIaU0mBSXhREz F1JQ== X-Forwarded-Encrypted: i=1; AFNElJ+gy+x8jgtLJO97BFik9WYECNMQom3DYYyaNwTE0D/vOxPV1GiE6t10oCobrUGbEDqSVlPnjNpIYZnj@nongnu.org X-Gm-Message-State: AOJu0YzIxqq5md6CCb0KjNyvGS1oaiiKVIfJdInmpl54vN+tl8xOtQNC umJ2UiG37MhIQR79xNPKi3jO1AK6BiBmKwpdbhuyPjyWbUejq9CtS7GA X-Gm-Gg: AeBDietPPtkzLbqFoNp2KvE1/00UjxAk+lsprWLuiro7ieSsSd7T1v3DwuQoU99BJSA zvg9XaUZPv36tqL1ovtKo4SvRxWqrOAOBffpTzfX4rS2R/K+j7thOkLOy5xunJ751eqpNgaeVRq GljfiORTVr1G7SXX687tca64ZGBPSwgUbvHoYzoR68r10di6k9cJkd6d1gUPC2+4KLAFpFxM666 tpdTRVdLsUGi5ty4YSo/rrf0DFPOkl1UNE0EzUTjQYYIQOJMsy1WAI4IZ4bFnAlFxtJj3KUZC7U 6e58PEQnUdAPn3mLxuYztgGSBWta0HQjpmTzOuC79ByZogekyEKNA/JEkZ76iH1yYiNYu9y4gBU 8MFnIwQKJBz1fEBu842pAWS49HKsm8MddIucI9Ne6SqG9wALSVN1VBoY7g2ZOZnckudqmi002qv bMcLnFCRynyuy8HPgFSqI+1/ahZISybAGgRsefTZGuxwlZdJvTVDzQrFqAqKy2HulmYUTAjoXiO V+VIKOoyWe82apP1rw= X-Received: by 2002:a05:6a00:408f:b0:829:8c08:d1f4 with SMTP id d2e1a72fcca58-83a5dd577f2mr7942689b3a.39.1778155554521; Thu, 07 May 2026 05:05:54 -0700 (PDT) From: Nicholas Piggin To: Corey Minyard Cc: Nicholas Piggin , Alistair Francis , Daniel Henrique Barboza , Chao Liu , Chris Rauer , Michael Ellerman , Joel Stanley , Anirudh Srinivasan , Portia Stephens , qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Hao Wu , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [PATCH 4/4] [RFC] hw/i2c/designware_i2c: add SMBUS_INTR_MASK Date: Thu, 7 May 2026 22:05:22 +1000 Message-ID: <20260507120524.111056-5-npiggin@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260507120524.111056-1-npiggin@gmail.com> References: <20260507120524.111056-1-npiggin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::42f; envelope-from=npiggin@gmail.com; helo=mail-pf1-x42f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1778155653304158500 Content-Type: text/plain; charset="utf-8" QEMU complains about access to unimplemented register when Linux inits the controller. It is the SMBUS interrupt mask which the driver unmasks. Since the model implements no SMBUS interrupts, the mask can be implemented trivially. Signed-off-by: Nicholas Piggin Acked-by: Corey Minyard Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/i2c/designware_i2c.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c index b7be4d68c4..cc37bde2ae 100644 --- a/hw/i2c/designware_i2c.c +++ b/hw/i2c/designware_i2c.c @@ -142,6 +142,7 @@ REG32(DW_IC_ENABLE_STATUS, 0x9c) /* I2C enable sta= tus */ FIELD(DW_IC_ENABLE_STATUS, IC_EN, 0, 1) REG32(DW_IC_FS_SPKLEN, 0xa0) /* I2C SS, FS or FM+ spike suppressi= on limit */ REG32(DW_IC_CLR_RESTART_DET, 0xa8) +REG32(DW_IC_SMBUS_INTR_MASK, 0xcc) /* SMBus Interrupt Mask */ REG32(DW_IC_COMP_PARAM_1, 0xf4) /* Component parameter */ FIELD(DW_IC_COMP_PARAM_1, TX_FIFO_SIZE, 16, 8) FIELD(DW_IC_COMP_PARAM_1, RX_FIFO_SIZE, 8, 8) @@ -610,6 +611,10 @@ static const RegisterAccessInfo designware_i2c_regs_in= fo[] =3D { },{ .name =3D "DW_IC_CLR_RESTART_DET", .addr =3D A_DW_IC_CLR_RESTART_= DET, .ro =3D 0xffffffff, .post_read =3D dw_ic_clr_intr_reg_post_read, + },{ .name =3D "DW_IC_SMBUS_INTR_MASK", .addr =3D A_DW_IC_SMBUS_INTR_M= ASK, + /* No SMBus interrupts are implemented, Linux updates the mask */ + .reset =3D 0x7ff, + .unimp =3D 0xfffff800, },{ .name =3D "DW_IC_COMP_PARAM_1", .addr =3D A_DW_IC_COMP_PARAM_1, .reset =3D /* HAS_DMA and HC_COUNT_VAL are disabled */ ((2 << R_DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32_SHIFT) | --=20 2.53.0