From nobody Mon Sep 28 01:13:34 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=1786120890; cv=none; d=zohomail.com; s=zohoarc; b=WYBLSjp8PO7SsI6Kjao6zxuSFP3IhClmSPg3rcdZfj4BirUHs5hyKcbnLhW9GV+5MSWrgLwnaYtf/MtppCGAz2j/ML3B+xtX1GrXQ57f73zNU1yVkC0Hdp4rIiT3bWAExX4OAi9YvPY6q+RrL3pblwYtJXApcjft6c/timMRzwk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786120890; 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=0zdTbKI8WpzuthzzDx8V6I4YNlT6+oO5xIBGtVH+zmo=; b=EwEdqEs7UFfGe3wCkjAIDCE9nQdnpw3bD7e3NTdmmmbx4WqswckJ/cl1Slw2F1HwBOH/KS0zftfy+nLk9KFLPItLbMEwZ0N7Zcbxvw6B2TMnI8HGLPqWWfBAiCZtg++t+TkaJTD9X51iO4W+1R8DMBcpyoM1r8Yzd0jTODeMjEs= 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 1786120890007681.3657987261707; Fri, 7 Aug 2026 09:41:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wsNd0-0001cX-BW; Fri, 07 Aug 2026 12:41:02 -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 1wsMVK-0004J4-Pp for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:02 -0400 Received: from mail-pl1-x629.google.com ([2607:f8b0:4864:20::629]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wsMVH-0007N8-8M for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:02 -0400 Received: by mail-pl1-x629.google.com with SMTP id d9443c01a7336-2cab973140bso49706135ad.3 for ; Fri, 07 Aug 2026 08:28:58 -0700 (PDT) Received: from localhost.localdomain ([2406:da14:1cf8:d800:471c:a879:4603:554f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14ccae6f8sm10953895ad.1.2026.08.07.08.28.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 08:28:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786116538; x=1786721338; 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:content-type; bh=0zdTbKI8WpzuthzzDx8V6I4YNlT6+oO5xIBGtVH+zmo=; b=cm8IKcgMHBendxaUVfatx+uCLR6j5JX4HdjH/NLDmnLYEMDawhC5Qz3RuLNBZg0FWd HpYZkGs4RlQq6eLRSKn8pY8abMpEd51DR8SLfkwjyisNWmqqr0lj8ed1YX/F4pyvCF2B wQM4+Yzg0kIKeBwPbokzMIu4kdvmkBi/8+PHkewWoL/Ctx8iLAbUzAf6jFsZMz8OKHkP 4ceRfV15u1h3Btp4kghwnEibN4gtn/DZCDhvSOObqT2IC/Gk7XpACp9GF6pzZ3R5BUgK vaz0ebmpXw7Vk93cJYASdBsd9T8C5PPkVocbJiEhnc3LghfwDwGwhULk/bkaiBQHvHId AMoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786116538; x=1786721338; 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:content-type; bh=0zdTbKI8WpzuthzzDx8V6I4YNlT6+oO5xIBGtVH+zmo=; b=iUe0TJQnGbheaQydtZx+8j7+FnOV+oNOcgUjIhtbLQo7Ki5+JPiGiM7eg1avbfxjhg 67ZPXUVLc0b4QGtRYBdcJCjYRyOKaKBVgRHWy7sSJsvKhNuOI7BscDHYbkYi4p0Hcl8X 0M7zKwvjsxDoQn4Ov/+aJkJOizup8BlIktjCGYXXy3gUsMkYQFXUcuO5xJqBiyUmMQyC an20egIed4zYnSjihpP8zc/yj/ESnZg85RzIV9te1SVBh5v7nS7uuaYUZouA5OR5gplp IYSZijVShxiQQM2RYEdRfLy9jxVyJJvssMqYnHBVyp2eJ4q5Ct/AnJLf/oKzlM0xcBR+ k1fQ== X-Gm-Message-State: AOJu0YwBzCsPlALncbmme0zkevZ8TAaKhxGPxf7U9Rxt6agjGk4R/lmW RpmvGPiRZ8arcXiz0T3pzAR/LkicMHPsE7xnATwXTXcWKYDPc2CjH8TE X-Gm-Gg: AR+sD12FnQ4Oe8x3IT8Sm3XlqPLGFe4Y4hLWifK57ijv9uk03mHEMe67pH9lCszAHNq LHr3+i/BlQcPxiji6zik6TnCkMVNX/2wdMTcx3KK2QHOfRfVq+WxTvhkOuAqgi4cm/UyImI5Iiw pQ1lfK50B0SQsziPUAEnslViiUs+WEV8H0jncJFIsbURylsWvhu1n0YSuyJN4HSJ8PWWIoJ4gnN /MlHxjFSpqxeWlVCbizBTvx0ES4N5ai3YOBAbRjnykd8xO7NriiD2tBQbXFm9JDJqazmohxCHD6 RX1LBfTp89gJjKQqbDj4lf6bjeI28VieTYOQIF41nYD6ai7QRhEPRScZocPZeLGusb/afNkMI5w 9cPa2jGNUR88MA328vdWsCpaokN/0M/7vS8kAYrhvxk8D6kIDjRfCtron3bw5NwX4KFSzkPsGW/ EAB5JcODzUmXUOvSaeYsBexNlnZVZqVgtJQo7f6P1hZDJWe0FwckZ+tumE2pqcwpDut4uYWwG3U Gef9HZRsN0= X-Received: by 2002:a17:902:ef0c:b0:2d0:cc92:f7c2 with SMTP id d9443c01a7336-2d2a8457180mr20408855ad.1.1786116537267; Fri, 07 Aug 2026 08:28:57 -0700 (PDT) From: Wang Zhongyu To: Chao Liu Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org, Paolo Bonzini , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei Subject: [PATCH 1/5] hw/i2c: add K230 I2C controller model Date: Fri, 7 Aug 2026 23:28:26 +0800 Message-ID: <20260807152830.6833-2-wzy15515798875@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260807152830.6833-1-wzy15515798875@gmail.com> References: <20260807152830.6833-1-wzy15515798875@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::629; envelope-from=wzy15515798875@gmail.com; helo=mail-pl1-x629.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, FROM_LOCAL_DIGITS=0.001, FROM_LOCAL_HEX=0.006, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 Aug 2026 12:41:00 -0400 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: 1786120891975158500 Content-Type: text/plain; charset="utf-8" Add a model of the I2C controller used by the Kendryte K230 SoC. The model supports master-mode 7-bit transfers, TX and RX FIFOs, interrupt status and masking, repeated START and STOP handling, General Call writes, reset, and migration state. DMA, 10-bit addressing, bus clear, Device ID transactions, and raw START BYTE transmission are not implemented. Signed-off-by: Wang Zhongyu Reviewed-by: Daniel Henrique Barboza --- MAINTAINERS | 2 + hw/i2c/Kconfig | 4 + hw/i2c/k230_i2c.c | 1083 +++++++++++++++++++++++++++++++++++++ hw/i2c/meson.build | 1 + include/hw/i2c/k230_i2c.h | 72 +++ 5 files changed, 1162 insertions(+) create mode 100644 hw/i2c/k230_i2c.c create mode 100644 include/hw/i2c/k230_i2c.h diff --git a/MAINTAINERS b/MAINTAINERS index 902db77218..ac61054dd1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1827,8 +1827,10 @@ M: Chao Liu L: qemu-riscv@nongnu.org S: Maintained F: docs/system/riscv/k230.rst +F: hw/i2c/k230_i2c.c F: hw/riscv/k230.c F: hw/watchdog/k230_wdt.c +F: include/hw/i2c/k230_i2c.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: tests/functional/riscv64/test_k230.py diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 0766130b59..f2a2ea6169 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -54,3 +54,7 @@ config PMBUS config BCM2835_I2C bool select I2C + +config K230_I2C + bool + select I2C diff --git a/hw/i2c/k230_i2c.c b/hw/i2c/k230_i2c.c new file mode 100644 index 0000000000..cc328736a4 --- /dev/null +++ b/hw/i2c/k230_i2c.c @@ -0,0 +1,1083 @@ +/* + * K230 DesignWare I2C controller + * + * Copyright (c) 2026 Wang Zhongyu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/k230_i2c.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/bitops.h" +#include "hw/core/irq.h" +#include "qemu/fifo8.h" +#include "qemu/fifo32.h" + +#define K230_I2C_MMIO_SIZE 0x1000 + +#define K230_IC_CON 0x00 +#define K230_IC_TAR 0x04 +#define K230_IC_SAR 0x08 +#define K230_IC_HS_MADDR 0x0c +#define K230_IC_DATA_CMD 0x10 +#define K230_IC_SS_SCL_HCNT 0x14 +#define K230_IC_SS_SCL_LCNT 0x18 +#define K230_IC_FS_SCL_HCNT 0x1c +#define K230_IC_FS_SCL_LCNT 0x20 +#define K230_IC_HS_SCL_HCNT 0x24 +#define K230_IC_HS_SCL_LCNT 0x28 +#define K230_IC_INTR_STAT 0x2c +#define K230_IC_INTR_MASK 0x30 +#define K230_IC_RAW_INTR_STAT 0x34 +#define K230_IC_RX_TL 0x38 +#define K230_IC_TX_TL 0x3c +#define K230_IC_CLR_INTR 0x40 +#define K230_IC_CLR_RX_UNDER 0x44 +#define K230_IC_CLR_RX_OVER 0x48 +#define K230_IC_CLR_TX_OVER 0x4c +#define K230_IC_CLR_RD_REQ 0x50 +#define K230_IC_CLR_TX_ABRT 0x54 +#define K230_IC_CLR_RX_DONE 0x58 +#define K230_IC_CLR_ACTIVITY 0x5c +#define K230_IC_CLR_STOP_DET 0x60 +#define K230_IC_CLR_START_DET 0x64 +#define K230_IC_CLR_GEN_CALL 0x68 +#define K230_IC_ENABLE 0x6c +#define K230_IC_STATUS 0x70 +#define K230_IC_TXFLR 0x74 +#define K230_IC_RXFLR 0x78 +/* 0x7C reserved */ +#define K230_IC_TX_ABRT_SOURCE 0x80 +#define K230_IC_SLV_DATA_NACK_ONLY 0x84 +#define K230_IC_DMA_CR 0x88 +#define K230_IC_DMA_TDLR 0x8c +#define K230_IC_DMA_RDLR 0x90 +#define K230_IC_SDA_SETUP 0x94 +#define K230_IC_ACK_GENERAL_CALL 0x98 +#define K230_IC_ENABLE_STATUS 0x9c +#define K230_IC_COMP_PARAM_1 0xf4 +#define K230_IC_COMP_VERSION 0xf8 +#define K230_IC_COMP_TYPE 0xfc +/* + * Optional bus-clear support is outside the scope of the initial model. + * Unimplemented register offsets read as zero and ignore writes. + */ + +/* IC_CON bit definitions */ +#define IC_CON_MASTER_MODE BIT(0) +#define IC_CON_SPEED (0x3U << 1) +#define IC_CON_10BITADDR_SLAVE BIT(3) +#define IC_CON_10BITADDR_MASTER BIT(4) +#define IC_CON_RESTART_EN BIT(5) +#define IC_CON_SLAVE_DISABLE BIT(6) +#define IC_CON_VALID_MASK \ + (IC_CON_MASTER_MODE | \ + IC_CON_SPEED | \ + IC_CON_10BITADDR_SLAVE | \ + IC_CON_10BITADDR_MASTER | \ + IC_CON_RESTART_EN | \ + IC_CON_SLAVE_DISABLE) + +/* IC_TAR bit definitions */ +#define IC_TAR (0x3ffU) +#define IC_TAR_GC_OR_START BIT(10) +#define IC_TAR_SPECIAL BIT(11) +/* + * This implementation selects the master addressing mode through + * IC_CON[4]. IC_TAR[12] is not modeled as writable. + */ +#define IC_TAR_VALID_MASK \ + (IC_TAR | \ + IC_TAR_GC_OR_START | \ + IC_TAR_SPECIAL) + +/* IC_SAR bit definitions */ +#define IC_SAR (0x3ffU) +#define IC_SAR_VALID_MASK IC_SAR + +/* IC_HS_MADDR bit definitions */ +#define IC_HS_MAR (0x7U) +#define IC_HS_MAR_VALID_MASK IC_HS_MAR + +/* IC_DATA_CMD bit definitions */ +#define IC_DAT (0xffU) +#define IC_CMD BIT(8) +#define IC_STOP BIT(9) +#define IC_RESTART BIT(10) +#define IC_DATA_CMD_VALID_MASK (IC_DAT | IC_CMD | IC_STOP | IC_RES= TART) + +/* + * The SCL count registers are retained for software compatibility. + * QEMU's I2C bus API does not model cycle-accurate bus timing, so these + * values do not change the duration of a transfer. + */ +#define IC_SS_SCL_HCNT_VALID_MASK (0xffffU) +#define IC_SS_SCL_LCNT_VALID_MASK (0xffffU) +#define IC_FS_SCL_HCNT_VALID_MASK (0xffffU) +#define IC_FS_SCL_LCNT_VALID_MASK (0xffffU) +#define IC_HS_SCL_HCNT_VALID_MASK (0xffffU) +#define IC_HS_SCL_LCNT_VALID_MASK (0xffffU) + +/* IC_INTR bit definitions */ +#define IC_INTR_RX_UNDER BIT(0) +#define IC_INTR_RX_OVER BIT(1) +#define IC_INTR_RX_FULL BIT(2) +#define IC_INTR_TX_OVER BIT(3) +#define IC_INTR_TX_EMPTY BIT(4) +#define IC_INTR_RD_REQ BIT(5) +#define IC_INTR_TX_ABRT BIT(6) +#define IC_INTR_RX_DONE BIT(7) +#define IC_INTR_ACTIVITY BIT(8) +#define IC_INTR_STOP_DET BIT(9) +#define IC_INTR_START_DET BIT(10) +#define IC_INTR_GEN_CALL BIT(11) +#define IC_INTR_VALID_MASK (0xfffU) +#define IC_INTR_SW_CLEAR_MASK \ + (IC_INTR_RX_UNDER | IC_INTR_RX_OVER | \ + IC_INTR_TX_OVER | IC_INTR_RD_REQ | \ + IC_INTR_TX_ABRT | IC_INTR_RX_DONE | \ + IC_INTR_STOP_DET | IC_INTR_START_DET | \ + IC_INTR_GEN_CALL | IC_INTR_ACTIVITY) + +/* IC_RX_TL and IC_TX_TL bit definitions */ +#define IC_RX_TL (0xffU) +#define IC_TX_TL (0xffU) + +/* CLR Reg bit definitions */ +#define IC_CLR_INTR BIT(0) +#define IC_CLR_RX_UNDER BIT(0) +#define IC_CLR_RX_OVER BIT(0) +#define IC_CLR_TX_OVER BIT(0) +#define IC_CLR_RD_REQ BIT(0) +#define IC_CLR_TX_ABRT BIT(0) +#define IC_CLR_RX_DONE BIT(0) +#define IC_CLR_ACTIVITY BIT(0) +#define IC_CLR_STOP_DET BIT(0) +#define IC_CLR_START_DET BIT(0) +#define IC_CLR_GEN_CALL BIT(0) + +/* IC_ENABLE bit definitions */ +#define IC_ENABLE BIT(0) + +/* IC_STATUS bit definitions */ +#define IC_ACTIVITY BIT(0) +#define IC_TFNF BIT(1) +#define IC_TFE BIT(2) +#define IC_RFNE BIT(3) +#define IC_RFF BIT(4) +#define IC_MST_ACTIVITY BIT(5) +#define IC_SLV_ACTIVITY BIT(6) +#define IC_STATUS_VALID_MASK \ + (IC_ACTIVITY | \ + IC_TFNF | \ + IC_TFE | \ + IC_RFNE | \ + IC_RFF | \ + IC_MST_ACTIVITY | \ + IC_SLV_ACTIVITY) + +/* FIFO level register bit definitions */ +#define IC_TXFLR (0x3fU) +#define IC_RXFLR (0x7fU) + +/* IC_TX_ABRT_SOURCE bit definitions */ +#define IC_ABRT_7B_ADDR_NOACK BIT(0) +#define IC_ABRT_10ADDR1_NOACK BIT(1) +#define IC_ABRT_10ADDR2_NOACK BIT(2) +#define IC_ABRT_TXDATA_NOACK BIT(3) +#define IC_ABRT_GCALL_NOACK BIT(4) +#define IC_ABRT_GCALL_READ BIT(5) +#define IC_ABRT_HS_ACKDET BIT(6) +#define IC_ABRT_SBYTE_ACKDET BIT(7) +#define IC_ABRT_HS_NORSTRT BIT(8) +#define IC_ABRT_SBYTE_NORSTRT BIT(9) +#define IC_ABRT_10B_RD_NORSTRT BIT(10) +#define IC_ABRT_MASTER_DIS BIT(11) +#define IC_ARB_LOST BIT(12) +#define IC_ABRT_SLVFLUSH_TXFIFO BIT(13) +#define IC_ABRT_SLV_ARBLOST BIT(14) +#define IC_ABRT_SLVRD_INTX BIT(15) +#define IC_ABRT_VALID_MASK 0xffffU + +/* IC_SLV_DATA_NACK_ONLY bit definitions */ +#define IC_SLV_NACK BIT(0) + +/* + * DMA support is not modeled by this implementation. DMA register writes + * are ignored, the registers remain at their reset values, and + * IC_COMP_PARAM_1 reports HAS_DMA as clear. + */ +#define IC_SDA_SETUP (0xffU) +#define IC_ACK_GEN_CALL BIT(0) + +/* IC_ENABLE_STATUS bit definitions */ +#define IC_EN BIT(0) +#define SLV_DISABLED_WHILE_BUSY BIT(1) +#define SLV_RX_DATA_LOST BIT(2) + +/* IC_COMP_PARAM_1 bit definitions */ +#define IC_COMP_PARAM_APB_DATA_WIDTH (0x3U) +#define IC_COMP_PARAM_MAX_SPEED_MODE (0x3U << 2) +#define IC_COMP_PARAM_HC_COUNT_VALUES BIT(4) +#define IC_COMP_PARAM_INTR_IO BIT(5) +#define IC_COMP_PARAM_HAS_DMA BIT(6) +#define IC_COMP_PARAM_ADD_ENCODED_PARAMS BIT(7) +#define IC_COMP_PARAM_RX_BUFFER_DEPTH (0xffU << 8) +#define IC_COMP_PARAM_TX_BUFFER_DEPTH (0xffU << 16) + +#define K230_IC_COMP_PARAM_1_VALUE \ + (2U | \ + (3U << 2) | \ + IC_COMP_PARAM_INTR_IO | \ + IC_COMP_PARAM_ADD_ENCODED_PARAMS | \ + ((K230_I2C_RX_FIFO_SIZE - 1U) << 8) | \ + ((K230_I2C_TX_FIFO_SIZE - 1U) << 16)) + +static void k230_i2c_update_irq(K230I2CState *s) +{ + uint32_t intr; + intr =3D s->ic_raw_intr_stat & s->ic_intr_mask & IC_INTR_VALID_MASK; + qemu_set_irq(s->irq, intr !=3D 0); +} + +static uint64_t k230_i2c_clear_intr(K230I2CState *s, uint32_t mask) +{ + s->ic_raw_intr_stat &=3D ~mask; + k230_i2c_update_irq(s); + + return 0; +} + +static bool k230_i2c_is_activity(K230I2CState *s) +{ + return (s->transfer_state !=3D K230_I2C_STATE_IDLE); +} + +static uint32_t k230_i2c_get_status(K230I2CState *s) +{ + uint32_t status =3D 0; + + if (k230_i2c_is_activity(s)) { + status |=3D IC_ACTIVITY; + status |=3D IC_MST_ACTIVITY; + } + + if (!fifo32_is_full(&s->tx_fifo)) { + status |=3D IC_TFNF; + } + + if (fifo32_is_empty(&s->tx_fifo)) { + status |=3D IC_TFE; + } + + if (!fifo8_is_empty(&s->rx_fifo)) { + status |=3D IC_RFNE; + } + + if (fifo8_is_full(&s->rx_fifo)) { + status |=3D IC_RFF; + } + return status; +} + +static bool k230_i2c_clear_tx_abrt_bit9(K230I2CState *s) +{ + return (s->ic_con & IC_CON_RESTART_EN) || + !(s->ic_tar & IC_TAR_SPECIAL) || + !(s->ic_tar & IC_TAR_GC_OR_START); +} + +static void k230_i2c_update_fifo_intr(K230I2CState *s) +{ + uint32_t rx_level =3D fifo8_num_used(&s->rx_fifo); + uint32_t tx_level =3D fifo32_num_used(&s->tx_fifo); + + if (!(s->ic_enable & IC_ENABLE)) { + s->ic_raw_intr_stat &=3D ~(IC_INTR_RX_FULL | IC_INTR_TX_EMPTY); + return; + } + + if (rx_level > s->ic_rx_tl) { + s->ic_raw_intr_stat |=3D IC_INTR_RX_FULL; + } else { + s->ic_raw_intr_stat &=3D ~IC_INTR_RX_FULL; + } + + if (!(s->ic_raw_intr_stat & IC_INTR_TX_ABRT) && + tx_level <=3D s->ic_tx_tl) { + s->ic_raw_intr_stat |=3D IC_INTR_TX_EMPTY; + } else { + s->ic_raw_intr_stat &=3D ~IC_INTR_TX_EMPTY; + } +} + +static uint64_t k230_i2c_clear_tx_abrt(K230I2CState *s) +{ + bool clr_bit9 =3D k230_i2c_clear_tx_abrt_bit9(s); + bool had_bit9 =3D !!(s->ic_tx_abrt_source & IC_ABRT_SBYTE_NORSTRT); + + s->ic_raw_intr_stat &=3D ~IC_INTR_TX_ABRT; + s->ic_tx_abrt_source =3D 0; + if (!clr_bit9 && had_bit9) { + s->ic_tx_abrt_source |=3D IC_ABRT_SBYTE_NORSTRT; + s->ic_raw_intr_stat |=3D IC_INTR_TX_ABRT; + } + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); + return 0; +} + +static uint64_t k230_i2c_clear_all_intr(K230I2CState *s) +{ + bool active =3D k230_i2c_is_activity(s); + s->ic_raw_intr_stat &=3D ~IC_INTR_SW_CLEAR_MASK; + if (active) { + s->ic_raw_intr_stat |=3D IC_INTR_ACTIVITY; + } + return k230_i2c_clear_tx_abrt(s); +} + +static uint64_t k230_i2c_read_data_cmd(K230I2CState *s) +{ + uint8_t data; + + if (fifo8_is_empty(&s->rx_fifo)) { + s->ic_raw_intr_stat |=3D IC_INTR_RX_UNDER; + k230_i2c_update_irq(s); + return 0; + } + + data =3D fifo8_pop(&s->rx_fifo); + if (fifo8_num_used(&s->rx_fifo) >=3D s->ic_rx_tl + 1) { + s->ic_raw_intr_stat |=3D IC_INTR_RX_FULL; + } else { + s->ic_raw_intr_stat &=3D ~IC_INTR_RX_FULL; + } + + k230_i2c_update_irq(s); + return data; +} + +static void k230_i2c_write_enable(K230I2CState *s, uint32_t value) +{ + bool enable_flag =3D !!(value & IC_ENABLE); + + if (enable_flag) { + s->ic_enable =3D enable_flag; + s->ic_enable_status =3D enable_flag; + + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); + return; + } + + if (s->transfer_state =3D=3D K230_I2C_STATE_RECEIVING) { + i2c_nack(s->bus); + } + + if (k230_i2c_is_activity(s)) { + i2c_end_transfer(s->bus); + } + + fifo8_reset(&s->rx_fifo); + fifo32_reset(&s->tx_fifo); + + s->transfer_state =3D K230_I2C_STATE_IDLE; + s->ic_enable_status =3D 0; + s->ic_enable =3D 0; + s->ic_raw_intr_stat &=3D ~(IC_INTR_TX_EMPTY | + IC_INTR_RX_FULL | + IC_INTR_ACTIVITY); + k230_i2c_update_irq(s); +} + +static void k230_i2c_abort(K230I2CState *s, uint32_t source) +{ + s->ic_tx_abrt_source |=3D source & IC_ABRT_VALID_MASK; + s->ic_raw_intr_stat |=3D IC_INTR_TX_ABRT; + + if (k230_i2c_is_activity(s)) { + i2c_end_transfer(s->bus); + } + + fifo32_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); + + s->transfer_state =3D K230_I2C_STATE_IDLE; + + s->ic_raw_intr_stat &=3D ~(IC_INTR_TX_EMPTY | IC_INTR_RX_FULL); + + k230_i2c_update_irq(s); +} + +static bool k230_i2c_start_address_phase(K230I2CState *s, bool is_read) +{ + uint8_t address; + uint32_t noack_source; + bool initial_start; + bool special; + bool general_call; + bool start_byte; + + initial_start =3D (s->transfer_state =3D=3D K230_I2C_STATE_IDLE); + + if (!(s->ic_con & IC_CON_MASTER_MODE)) { + k230_i2c_abort(s, IC_ABRT_MASTER_DIS); + return false; + } + + /* + * This implementation handles 7-bit master transfers only. Requests f= or + * 10-bit master mode are aborted rather than treated as 7-bit transfe= rs. + */ + if (s->ic_con & IC_CON_10BITADDR_MASTER) { + qemu_log_mask(LOG_UNIMP, + "k230-i2c: 10-bit master addressing " + "is not implemented\n"); + k230_i2c_abort(s, 0); + return false; + } + + special =3D !!(s->ic_tar & IC_TAR_SPECIAL); + + general_call =3D (special && !(s->ic_tar & IC_TAR_GC_OR_START)); + + start_byte =3D (special && !!(s->ic_tar & IC_TAR_GC_OR_START)); + + /* + * QEMU's I2C bus API cannot emit the raw START byte before the target + * address. Preserve the DW_apb_i2c RESTART_EN requirement, then fall + * back to the normal target-address phase. + */ + if (initial_start && start_byte && !(s->ic_con & IC_CON_RESTART_EN)) { + k230_i2c_abort(s, IC_ABRT_SBYTE_NORSTRT); + return false; + } + + if (general_call) { + if (is_read) { + k230_i2c_abort(s, IC_ABRT_GCALL_READ); + return false; + } + address =3D 0; + noack_source =3D IC_ABRT_GCALL_NOACK; + } else { + address =3D s->ic_tar & 0x7fU; + noack_source =3D IC_ABRT_7B_ADDR_NOACK; + } + + s->ic_raw_intr_stat |=3D IC_INTR_START_DET | IC_INTR_ACTIVITY; + + if (i2c_start_transfer(s->bus, address, is_read)) { + k230_i2c_abort(s, noack_source); + return false; + } + + s->transfer_state =3D is_read ? K230_I2C_STATE_RECEIVING : + K230_I2C_STATE_SENDING; + + return true; +} + +/* + * DATA_CMD writes are executed synchronously. The TX FIFO acts as a + * transient command staging buffer, while the RX FIFO retains received + * data for guest reads and FIFO-level interrupt handling. + */ +static void k230_i2c_write_data_cmd(K230I2CState *s, uint32_t value) +{ + uint32_t command; + uint32_t tx_entry; + uint8_t data; + bool is_read; + bool restart; + bool stop; + bool direction_changed; + bool need_restart; + int ret; + + if (!(s->ic_enable & IC_ENABLE)) { + return; + } + + if (s->ic_raw_intr_stat & IC_INTR_TX_ABRT) { + return; + } + + if (fifo32_is_full(&s->tx_fifo)) { + s->ic_raw_intr_stat |=3D IC_INTR_TX_OVER; + k230_i2c_update_irq(s); + return; + } + + command =3D value & IC_DATA_CMD_VALID_MASK; + + fifo32_push(&s->tx_fifo, command); + + tx_entry =3D fifo32_pop(&s->tx_fifo); + + data =3D tx_entry & IC_DAT; + is_read =3D !!(tx_entry & IC_CMD); + restart =3D !!(tx_entry & IC_RESTART); + stop =3D !!(tx_entry & IC_STOP); + + direction_changed =3D + (s->transfer_state =3D=3D K230_I2C_STATE_SENDING && is_read) || + (s->transfer_state =3D=3D K230_I2C_STATE_RECEIVING && !is_read); + + need_restart =3D restart || direction_changed; + + switch (s->transfer_state) { + case K230_I2C_STATE_IDLE: + if (!k230_i2c_start_address_phase(s, is_read)) { + return; + } + break; + case K230_I2C_STATE_SENDING: + case K230_I2C_STATE_RECEIVING: + if (need_restart) { + if (!(s->ic_con & IC_CON_RESTART_EN)) { + qemu_log_mask(LOG_GUEST_ERROR, + "k230-i2c: restart requested while " + "IC_RESTART_EN is disabled\n"); + k230_i2c_abort(s, 0); + return; + } + + if (s->transfer_state =3D=3D K230_I2C_STATE_RECEIVING) { + i2c_nack(s->bus); + } + + if (!k230_i2c_start_address_phase(s, is_read)) { + return; + } + } + break; + default: + g_assert_not_reached(); + } + + if (is_read) { + data =3D i2c_recv(s->bus); + if (fifo8_is_full(&s->rx_fifo)) { + s->ic_raw_intr_stat |=3D IC_INTR_RX_OVER; + } else { + fifo8_push(&s->rx_fifo, data); + } + } else { + ret =3D i2c_send(s->bus, data); + if (ret) { + k230_i2c_abort(s, IC_ABRT_TXDATA_NOACK); + return; + } + } + + if (stop) { + if (is_read) { + i2c_nack(s->bus); + } + + i2c_end_transfer(s->bus); + + s->transfer_state =3D K230_I2C_STATE_IDLE; + s->ic_raw_intr_stat |=3D IC_INTR_STOP_DET; + } + + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); +} + +static uint64_t k230_i2c_read(void *opaque, hwaddr offset, unsigned size) +{ + K230I2CState *s =3D K230_I2C(opaque); + uint64_t activity_flag; + switch (offset) { + case K230_IC_CON: + return s->ic_con; + case K230_IC_TAR: + return s->ic_tar; + case K230_IC_SAR: + return s->ic_sar; + case K230_IC_HS_MADDR: + return s->ic_hs_maddr; + case K230_IC_DATA_CMD: + return k230_i2c_read_data_cmd(s); + case K230_IC_SS_SCL_HCNT: + return s->ic_ss_scl_hcnt; + case K230_IC_SS_SCL_LCNT: + return s->ic_ss_scl_lcnt; + case K230_IC_FS_SCL_HCNT: + return s->ic_fs_scl_hcnt; + case K230_IC_FS_SCL_LCNT: + return s->ic_fs_scl_lcnt; + case K230_IC_HS_SCL_HCNT: + return s->ic_hs_scl_hcnt; + case K230_IC_HS_SCL_LCNT: + return s->ic_hs_scl_lcnt; + case K230_IC_INTR_STAT: + return s->ic_raw_intr_stat & s->ic_intr_mask; + case K230_IC_INTR_MASK: + return s->ic_intr_mask; + case K230_IC_RAW_INTR_STAT: + return s->ic_raw_intr_stat; + case K230_IC_RX_TL: + return s->ic_rx_tl; + case K230_IC_TX_TL: + return s->ic_tx_tl; + case K230_IC_CLR_INTR: + return k230_i2c_clear_all_intr(s); + case K230_IC_CLR_RX_UNDER: + return k230_i2c_clear_intr(s, IC_INTR_RX_UNDER); + case K230_IC_CLR_RX_OVER: + return k230_i2c_clear_intr(s, IC_INTR_RX_OVER); + case K230_IC_CLR_TX_OVER: + return k230_i2c_clear_intr(s, IC_INTR_TX_OVER); + case K230_IC_CLR_RD_REQ: + return k230_i2c_clear_intr(s, IC_INTR_RD_REQ); + case K230_IC_CLR_TX_ABRT: + return k230_i2c_clear_tx_abrt(s); + case K230_IC_CLR_RX_DONE: + return k230_i2c_clear_intr(s, IC_INTR_RX_DONE); + case K230_IC_CLR_ACTIVITY: + activity_flag =3D !!(s->ic_raw_intr_stat & IC_INTR_ACTIVITY); + if (!k230_i2c_is_activity(s)) { + k230_i2c_clear_intr(s, IC_INTR_ACTIVITY); + } + return activity_flag; + case K230_IC_CLR_STOP_DET: + return k230_i2c_clear_intr(s, IC_INTR_STOP_DET); + case K230_IC_CLR_START_DET: + return k230_i2c_clear_intr(s, IC_INTR_START_DET); + case K230_IC_CLR_GEN_CALL: + return k230_i2c_clear_intr(s, IC_INTR_GEN_CALL); + case K230_IC_ENABLE: + return s->ic_enable; + case K230_IC_STATUS: + return k230_i2c_get_status(s); + case K230_IC_TXFLR: + return fifo32_num_used(&s->tx_fifo); + case K230_IC_RXFLR: + return fifo8_num_used(&s->rx_fifo); + case K230_IC_TX_ABRT_SOURCE: + return s->ic_tx_abrt_source; + case K230_IC_SLV_DATA_NACK_ONLY: + return s->ic_slv_data_nack_only; + case K230_IC_DMA_CR: + return s->ic_dma_cr; + case K230_IC_DMA_TDLR: + return s->ic_dma_tdlr; + case K230_IC_DMA_RDLR: + return s->ic_dma_rdlr; + case K230_IC_SDA_SETUP: + return s->ic_sda_setup; + case K230_IC_ACK_GENERAL_CALL: + return s->ic_ack_general_call; + case K230_IC_ENABLE_STATUS: + return s->ic_enable_status; + case K230_IC_COMP_PARAM_1: + return K230_IC_COMP_PARAM_1_VALUE; + case K230_IC_COMP_VERSION: + return 0x3132302aU; + case K230_IC_COMP_TYPE: + return 0x44570140U; + default: + return 0; + } +} + +static void k230_i2c_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + K230I2CState *s =3D K230_I2C(opaque); + uint32_t val =3D value; + + switch (offset) { + case K230_IC_CON: { + if (s->ic_enable & IC_ENABLE) { + break; + } + s->ic_con =3D val & IC_CON_VALID_MASK; + + if (!((s->ic_con & IC_CON_SPEED) >> 1)) { + s->ic_con |=3D IC_CON_SPEED; + } + s->ic_con |=3D IC_CON_SLAVE_DISABLE; + break; + } + case K230_IC_TAR: { + if (s->ic_enable & IC_ENABLE) { + break; + } + s->ic_tar =3D val & IC_TAR_VALID_MASK; + break; + } + case K230_IC_SAR: { + if (s->ic_enable & IC_ENABLE) { + break; + } + s->ic_sar =3D val & IC_SAR_VALID_MASK; + break; + } + case K230_IC_HS_MADDR: { + if (s->ic_enable & IC_ENABLE) { + break; + } + s->ic_hs_maddr =3D val & IC_HS_MAR_VALID_MASK; + break; + } + case K230_IC_DATA_CMD: { + k230_i2c_write_data_cmd(s, val); + break; + } + case K230_IC_SS_SCL_HCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_SS_SCL_HCNT_VALID_MASK; + + if (count < 6) { + count =3D 6; + } else if (count > 65525) { + qemu_log_mask(LOG_GUEST_ERROR, + "k230-i2c: invalid IC_SS_SCL_HCNT value %u\n", + (unsigned int)count); + break; + } + + s->ic_ss_scl_hcnt =3D count; + + break; + } + case K230_IC_SS_SCL_LCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_SS_SCL_LCNT_VALID_MASK; + + if (count < 8) { + count =3D 8; + } + + s->ic_ss_scl_lcnt =3D count; + + break; + } + case K230_IC_FS_SCL_HCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_FS_SCL_HCNT_VALID_MASK; + + if (count < 6) { + count =3D 6; + } + + s->ic_fs_scl_hcnt =3D count; + + break; + } + case K230_IC_FS_SCL_LCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_FS_SCL_LCNT_VALID_MASK; + + if (count < 8) { + count =3D 8; + } + + s->ic_fs_scl_lcnt =3D count; + + break; + } + case K230_IC_HS_SCL_HCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_HS_SCL_HCNT_VALID_MASK; + + if (count < 6) { + count =3D 6; + } + + s->ic_hs_scl_hcnt =3D count; + + break; + } + case K230_IC_HS_SCL_LCNT: { + uint16_t count; + + if (s->ic_enable & IC_ENABLE) { + break; + } + + count =3D val & IC_HS_SCL_LCNT_VALID_MASK; + + if (count < 8) { + count =3D 8; + } + + s->ic_hs_scl_lcnt =3D count; + + break; + } + case K230_IC_INTR_MASK: { + s->ic_intr_mask =3D val & IC_INTR_VALID_MASK; + + k230_i2c_update_irq(s); + break; + } + case K230_IC_RX_TL: { + uint8_t threshold; + + threshold =3D val & IC_RX_TL; + if (threshold > K230_I2C_RX_FIFO_SIZE - 1) { + threshold =3D K230_I2C_RX_FIFO_SIZE - 1; + } + s->ic_rx_tl =3D threshold; + + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); + + break; + } + case K230_IC_TX_TL: { + uint8_t threshold; + + threshold =3D val & IC_TX_TL; + if (threshold > K230_I2C_TX_FIFO_SIZE) { + threshold =3D K230_I2C_TX_FIFO_SIZE; + } + s->ic_tx_tl =3D threshold; + + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); + + break; + } + case K230_IC_ENABLE: { + k230_i2c_write_enable(s, val); + break; + } + case K230_IC_TX_ABRT_SOURCE: { + s->ic_tx_abrt_source =3D val & IC_ABRT_VALID_MASK; + break; + } + case K230_IC_SLV_DATA_NACK_ONLY: { + /* Slave mode is not supported. */ + break; + } + case K230_IC_DMA_CR: { + break; + } + case K230_IC_DMA_TDLR: { + break; + } + case K230_IC_DMA_RDLR: { + break; + } + case K230_IC_SDA_SETUP: { + s->ic_sda_setup =3D val & IC_SDA_SETUP; + break; + } + case K230_IC_ACK_GENERAL_CALL: { + s->ic_ack_general_call =3D val & IC_ACK_GEN_CALL; + break; + } + default: + return; + } +} + +static void k230_i2c_reset(Object *obj, ResetType type) +{ + K230I2CState *s =3D K230_I2C(obj); + + if (s->transfer_state =3D=3D K230_I2C_STATE_RECEIVING) { + i2c_nack(s->bus); + } + + if (k230_i2c_is_activity(s)) { + i2c_end_transfer(s->bus); + } + + fifo8_reset(&s->rx_fifo); + fifo32_reset(&s->tx_fifo); + + s->transfer_state =3D K230_I2C_STATE_IDLE; + + s->ic_con =3D 0x7f; + s->ic_tar =3D 0x055; + s->ic_sar =3D 0x055; + s->ic_hs_maddr =3D 0x1; + + s->ic_ss_scl_hcnt =3D 0x0190; + s->ic_ss_scl_lcnt =3D 0x01d6; + s->ic_fs_scl_hcnt =3D 0x003c; + s->ic_fs_scl_lcnt =3D 0x0082; + s->ic_hs_scl_hcnt =3D 0x0006; + s->ic_hs_scl_lcnt =3D 0x0010; + + s->ic_intr_mask =3D 0x8ff; + 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_enable_status =3D 0; + + s->ic_tx_abrt_source =3D 0; + s->ic_slv_data_nack_only =3D 0; + + s->ic_dma_cr =3D 0; + s->ic_dma_tdlr =3D 0; + s->ic_dma_rdlr =3D 0; + + s->ic_sda_setup =3D 0x64; + s->ic_ack_general_call =3D 0x1; + + qemu_set_irq(s->irq, 0); +} + +static const MemoryRegionOps k230_i2c_ops =3D { + .read =3D k230_i2c_read, + .write =3D k230_i2c_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static void k230_i2c_init(Object *obj) +{ + K230I2CState *s =3D K230_I2C(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + + fifo8_create(&s->rx_fifo, K230_I2C_RX_FIFO_SIZE); + fifo32_create(&s->tx_fifo, K230_I2C_TX_FIFO_SIZE); + + s->bus =3D i2c_init_bus(DEVICE(obj), "i2c"); + + memory_region_init_io(&s->iomem, obj, + &k230_i2c_ops, s, + TYPE_K230_I2C, K230_I2C_MMIO_SIZE); + + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static void k230_i2c_finalize(Object *obj) +{ + K230I2CState *s =3D K230_I2C(obj); + + fifo8_destroy(&s->rx_fifo); + fifo32_destroy(&s->tx_fifo); +} + +static int k230_i2c_post_load(void *opaque, int version_id) +{ + K230I2CState *s =3D opaque; + + if (s->transfer_state > K230_I2C_STATE_RECEIVING) { + return -EINVAL; + } + + k230_i2c_update_fifo_intr(s); + k230_i2c_update_irq(s); + + return 0; +} + +static const VMStateDescription vmstate_k230_i2c =3D { + .name =3D TYPE_K230_I2C, + .version_id =3D 1, + .minimum_version_id =3D 1, + .post_load =3D k230_i2c_post_load, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT32(ic_con, K230I2CState), + VMSTATE_UINT32(ic_tar, K230I2CState), + VMSTATE_UINT32(ic_sar, K230I2CState), + VMSTATE_UINT32(ic_hs_maddr, K230I2CState), + + VMSTATE_UINT32(ic_ss_scl_hcnt, K230I2CState), + VMSTATE_UINT32(ic_ss_scl_lcnt, K230I2CState), + VMSTATE_UINT32(ic_fs_scl_hcnt, K230I2CState), + VMSTATE_UINT32(ic_fs_scl_lcnt, K230I2CState), + VMSTATE_UINT32(ic_hs_scl_hcnt, K230I2CState), + VMSTATE_UINT32(ic_hs_scl_lcnt, K230I2CState), + + VMSTATE_UINT32(ic_intr_mask, K230I2CState), + VMSTATE_UINT32(ic_raw_intr_stat, K230I2CState), + + VMSTATE_UINT32(ic_rx_tl, K230I2CState), + VMSTATE_UINT32(ic_tx_tl, K230I2CState), + + VMSTATE_UINT32(ic_enable, K230I2CState), + VMSTATE_UINT32(ic_tx_abrt_source, K230I2CState), + + VMSTATE_UINT32(ic_sda_setup, K230I2CState), + VMSTATE_UINT32(ic_slv_data_nack_only, K230I2CState), + + VMSTATE_UINT32(ic_dma_cr, K230I2CState), + VMSTATE_UINT32(ic_dma_tdlr, K230I2CState), + VMSTATE_UINT32(ic_dma_rdlr, K230I2CState), + VMSTATE_UINT32(ic_ack_general_call, K230I2CState), + VMSTATE_UINT32(ic_enable_status, K230I2CState), + + VMSTATE_FIFO8(rx_fifo, K230I2CState), + VMSTATE_FIFO32(tx_fifo, K230I2CState), + + VMSTATE_UINT32(transfer_state, K230I2CState), + + VMSTATE_END_OF_LIST() + }, +}; + +static void k230_i2c_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->vmsd =3D &vmstate_k230_i2c; + rc->phases.hold =3D k230_i2c_reset; +} + +static const TypeInfo k230_i2c_info =3D { + .name =3D TYPE_K230_I2C, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(K230I2CState), + .instance_init =3D k230_i2c_init, + .instance_finalize =3D k230_i2c_finalize, + .class_init =3D k230_i2c_class_init, +}; + +static void k230_i2c_register_types(void) +{ + type_register_static(&k230_i2c_info); +} + +type_init(k230_i2c_register_types) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index 88aea35662..10da237dd9 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -19,4 +19,5 @@ i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_= i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) i2c_ss.add(when: 'CONFIG_BCM2835_I2C', if_true: files('bcm2835_i2c.c')) +i2c_ss.add(when: 'CONFIG_K230_I2C', if_true: files('k230_i2c.c')) system_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/include/hw/i2c/k230_i2c.h b/include/hw/i2c/k230_i2c.h new file mode 100644 index 0000000000..94a4128f46 --- /dev/null +++ b/include/hw/i2c/k230_i2c.h @@ -0,0 +1,72 @@ +/* + * K230 DesignWare I2C controller + * + * Copyright (c) 2026 Wang Zhongyu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_I2C_K230_I2C_H +#define HW_I2C_K230_I2C_H + +#include + +#include "hw/core/sysbus.h" +#include "hw/i2c/i2c.h" +#include "qemu/fifo32.h" +#include "qemu/fifo8.h" + +#define K230_I2C_RX_FIFO_SIZE 64 +#define K230_I2C_TX_FIFO_SIZE 32 + +#define TYPE_K230_I2C "k230-i2c" +OBJECT_DECLARE_SIMPLE_TYPE(K230I2CState, K230_I2C) + +typedef enum K230I2CTransferState { + K230_I2C_STATE_IDLE, + K230_I2C_STATE_SENDING, + K230_I2C_STATE_RECEIVING, +} K230I2CTransferState; + +struct K230I2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + I2CBus *bus; + qemu_irq irq; + + /* K230 I2C register list */ + uint32_t ic_con; + uint32_t ic_tar; + uint32_t ic_sar; + uint32_t ic_hs_maddr; + 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_hs_scl_hcnt; + uint32_t ic_hs_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_tx_abrt_source; + uint32_t ic_sda_setup; + uint32_t ic_slv_data_nack_only; + uint32_t ic_dma_cr; + uint32_t ic_dma_tdlr; + uint32_t ic_dma_rdlr; + uint32_t ic_ack_general_call; + uint32_t ic_enable_status; + + Fifo8 rx_fifo; + Fifo32 tx_fifo; + uint32_t transfer_state; +}; + +#endif /* HW_I2C_K230_I2C_H */ --=20 2.43.0 From nobody Mon Sep 28 01:13:34 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=1786120894; cv=none; d=zohomail.com; s=zohoarc; b=LiJQ+P4RAW4VqC+Jj/MvL1Yje0905QgAmyp6rdJxHRDLwdLZb+o4fqNyso3o9pWz+XianIKqLhoNs1JKVMM3aErjZWFu0lyUtTte/IZmu5HNtAwpBhKi2ZGciJDSDftwREBKYfs1rnTs4t/vt7j4y8sw4cZgRjCHtHuu2Spp5Po= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786120894; 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=I23kL40IdR3TgWRLaRgG60FGmA0UqKqWTKWMYTL83+g=; b=LZ03rY90YxpGqKFaUmOx92gxkcgbPHwDWzWki/UdnL0eMNC3vv6vLT0lHCTnUflvJjxG/JI8+1lkJqWKCSmDUIGHDRCFZf0RLf5ZrK+FNFQ+0+UW8ppY3YJafQ+968DhmDf3p8+SlKO5FR5s801nO4DX7yg4Uu4OasxZp6n3JXQ= 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 1786120894535526.4023070696654; Fri, 7 Aug 2026 09:41:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wsNcz-0001Zp-Fo; Fri, 07 Aug 2026 12:41:01 -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 1wsMVP-0004MQ-Iw for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:07 -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 1wsMVN-0007Ng-A8 for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:07 -0400 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-2cf452def93so17916695ad.1 for ; Fri, 07 Aug 2026 08:29:04 -0700 (PDT) Received: from localhost.localdomain ([2406:da14:1cf8:d800:471c:a879:4603:554f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14ccae6f8sm10953895ad.1.2026.08.07.08.28.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 08:29:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786116544; x=1786721344; 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:content-type; bh=I23kL40IdR3TgWRLaRgG60FGmA0UqKqWTKWMYTL83+g=; b=GbYwPsPU8Xx041aUaxDBh+FzMGYEVEcePJOjF90Ov1XLNASS5nVPwfJdFFXpc7quKv tlnEicXieR14jc0mfoGKHSXy0HCk1veNfv+5sNtqz6Ce2QYB6qzsMJ977aLHRypNA+Sk GXTaDyHOBb2t3195U5CKL/cYDJSgO8o/XKnyR/1bHBanEZbN8TeCR24LidTYefAGXTOu sivq8iTJc/w4MVB7nQfFpFQ6UI4xGXPeNQZY5LwkLK+iXZooQYSJZu8fi2+Fv9r3sHto +C2wmB6lmWwzum+5M1PRxTZa1VaXQVE8En647i3DKCB9uoPuE54A5s/4yV6A1EdMURcn eFVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786116544; x=1786721344; 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:content-type; bh=I23kL40IdR3TgWRLaRgG60FGmA0UqKqWTKWMYTL83+g=; b=JFDZEPe6AMshHEJGb5be94hJDwdsUrzS1jy4Wjue2IVsv2EoMHfYiLtm//Tp3joBx8 Fjz+8NKP9y3zA00bqg4LJAX8MMP1xTF2Rv6dSphwrfyrv98CM7dMp5YWhww/GdhefkmG rNY2qdEiZwlVkqinH2+JfcXpz8p75HbNENiMoDPg1PU3MN0dmlslyXQW0Rxyp5vgVKOU w8fvHVXojahDCTsfwO3pW5pUU+vOtxjexp+VkI/hDjtbEI2Bu8k4xddWGfSkPcwKdYXt tvHMhwSqycXvkFzVpuuSqnXjFNWTFooj61mx6iQpmU2R9FweK7omfx0FuofnFQCJVgvt k3/g== X-Gm-Message-State: AOJu0YyCkhTYwzmsCbDBV1vz40gyErWOQN43zoa3/e/f3qqAY1uyvgxK aBj9+Dgi7yvJIG/JO+F/SOhJ6vyHtJ1VSxDFtsmiCFVaQTNZG0KLuRz1 X-Gm-Gg: AR+sD10JkJ/oVdpUr1lRo8bQnF09+1e6VcNN9QRPLol3pZqV7B8Ze8drTDwKPeTS5ON fRTwL3JJsEY6gh2sH0jDZbdR5/niGpB1XirpAjg3Io6YrAS00Ipp7zv/WPPYZsYJCOP/3VSd3tc dko5XefKxzWk9mGC8BGud+FMEuCOYmkaWzhUToMyuWewjTMFXk76QBfDciT0Yv8TvOISMQFTP9n M0LqRZv1O3ovfbz1N8skLC9PPHiYvlyyIvktCkoqosHtw66N2JZryQCXYTo3MMTzAkRHQ8qm/l+ mxH+I1vBuwmroGAGDGKqROWtDQil/ESd7hD0A4SJVHzC6p06p4wOGp9hvIRe/+tj+DoHMvHgEpM dUvacww6s6PfDBkToV/di2s1P1MffOTC/ssah551svSgAtZ9NQsMH9nuGU+Rjmb3vBCoIuuIrlA 1luMnxpf7pOmHfGo/6MRdLtubOmIy2vC+Z/VDiZsuUgfslRv4YHkwRmBxxClD3addgYoBgUFXKP RwA8GwecjA= X-Received: by 2002:a17:902:f647:b0:2bc:e299:4b3f with SMTP id d9443c01a7336-2d2ada14588mr3871805ad.10.1786116543886; Fri, 07 Aug 2026 08:29:03 -0700 (PDT) From: Wang Zhongyu To: Chao Liu Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org, Paolo Bonzini , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei Subject: [PATCH 2/5] hw/riscv: instantiate K230 I2C controllers Date: Fri, 7 Aug 2026 23:28:27 +0800 Message-ID: <20260807152830.6833-3-wzy15515798875@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260807152830.6833-1-wzy15515798875@gmail.com> References: <20260807152830.6833-1-wzy15515798875@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=wzy15515798875@gmail.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, FROM_LOCAL_DIGITS=0.001, FROM_LOCAL_HEX=0.006, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 Aug 2026 12:41:00 -0400 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: 1786120896199158500 Content-Type: text/plain; charset="utf-8" Instantiate the five K230 I2C controllers, map their MMIO regions, and connect IRQs 21 through 25 to the PLIC. Select the K230 I2C model in the machine configuration and update the K230 machine documentation. Signed-off-by: Wang Zhongyu Reviewed-by: Daniel Henrique Barboza --- docs/system/riscv/k230.rst | 1 + hw/riscv/Kconfig | 1 + hw/riscv/k230.c | 36 +++++++++++++++++++++--------------- include/hw/riscv/k230.h | 8 ++++++++ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst index cea8202e55..7a011903ab 100644 --- a/docs/system/riscv/k230.rst +++ b/docs/system/riscv/k230.rst @@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices: * Core Local Interruptor (CLINT) * Platform-Level Interrupt Controller (PLIC) * 2 K230 Watchdog Timer +* 5 K230 I2C controllers * 5 UART =20 Boot options diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index de37c08cae..d2bd41173d 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -162,3 +162,4 @@ config K230 select SERIAL_MM select UNIMP select K230_WDT + select K230_I2C diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 656f28190c..a42f896c0a 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -110,6 +110,11 @@ static void k230_soc_init(Object *obj) object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT); object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT); + object_initialize_child(obj, "k230-i2c0", &s->i2c[0], TYPE_K230_I2C); + object_initialize_child(obj, "k230-i2c1", &s->i2c[1], TYPE_K230_I2C); + object_initialize_child(obj, "k230-i2c2", &s->i2c[2], TYPE_K230_I2C); + object_initialize_child(obj, "k230-i2c3", &s->i2c[3], TYPE_K230_I2C); + object_initialize_child(obj, "k230-i2c4", &s->i2c[4], TYPE_K230_I2C); =20 qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0); qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C9= 08); @@ -191,6 +196,22 @@ static void k230_soc_realize(DeviceState *dev, Error *= *errp) k230_create_uart(sys_mem, DEVICE(s->c908_plic), i); } =20 + /* I2C */ + for (int i =3D 0; i < K230_I2C_COUNT; i++) { + int i2c_dev =3D K230_DEV_I2C0 + i; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, + memmap[i2c_dev].base); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(DEVICE(s->c908_plic), + K230_I2C0_IRQ + i)); + } + /* Watchdog */ for (int i =3D 0; i < 2; i++) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { @@ -304,21 +325,6 @@ static void k230_soc_realize(DeviceState *dev, Error *= *errp) create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base, memmap[K230_DEV_SECURITY].size); =20 - create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base, - memmap[K230_DEV_I2C0].size); - - create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base, - memmap[K230_DEV_I2C1].size); - - create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base, - memmap[K230_DEV_I2C2].size); - - create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base, - memmap[K230_DEV_I2C3].size); - - create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base, - memmap[K230_DEV_I2C4].size); - create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base, memmap[K230_DEV_PWM].size); =20 diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index 592e1c26bf..4ea927a63b 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -18,8 +18,10 @@ #include "hw/core/boards.h" #include "hw/riscv/riscv_hart.h" #include "hw/watchdog/k230_wdt.h" +#include "hw/i2c/k230_i2c.h" =20 #define C908_CPU_HARTID (0) +#define K230_I2C_COUNT 5 =20 #define TYPE_RISCV_K230_SOC "riscv.k230.soc" #define RISCV_K230_SOC(obj) \ @@ -33,6 +35,7 @@ typedef struct K230SoCState { RISCVHartArrayState c908_cpu; /* Small core */ =20 K230WdtState wdt[2]; + K230I2CState i2c[K230_I2C_COUNT]; MemoryRegion sram; MemoryRegion bootrom; =20 @@ -127,6 +130,11 @@ enum { K230_UART2_IRQ =3D 18, K230_UART3_IRQ =3D 19, K230_UART4_IRQ =3D 20, + K230_I2C0_IRQ =3D 21, + K230_I2C1_IRQ =3D 22, + K230_I2C2_IRQ =3D 23, + K230_I2C3_IRQ =3D 24, + K230_I2C4_IRQ =3D 25, K230_WDT0_IRQ =3D 107, K230_WDT1_IRQ =3D 108, }; --=20 2.43.0 From nobody Mon Sep 28 01:13:34 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=1786120938; cv=none; d=zohomail.com; s=zohoarc; b=goskEPXAn0jFn+H1S2O1H6Txht66DV4htTOGknaO2jjC7WehnkBfH8mqNrkcQyPxASJsQ3okhcEUy1NJiD0mCzdEqm7xrPpJRVFVWMksyo9CFP1XdKgw43rdZaBbVVl72QgVW2rF7y0eE9Z4dlCQwXF5hrsnplap+jPBYrfU1kg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786120938; 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=/Dl+jMIxfRI9WOJazK+zPFzjGcmCKJrAWcw1IrtW8bA=; b=MbHK2hX8AMl+uWnmY1N7pqq+2YoduIF8aAKaKBzAO+IqDbTOL+eSKrGCb7DmyGt/SoJs1rQbQEtiXi0pyZ19AYT+AFy8kwN3/L0/qHTNhFOjqY7ZtdI1BFDNLOcl9XK7ReZo6KhD4JH3/HfgjFP+QUmhe1Wag/xvddsC5cMsOVc= 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 1786120938024967.9223414780121; Fri, 7 Aug 2026 09:42:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wsNd2-0001i7-2L; Fri, 07 Aug 2026 12:41:04 -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 1wsMVV-0004R3-Mp for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:13 -0400 Received: from mail-pl1-x62d.google.com ([2607:f8b0:4864:20::62d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wsMVT-0007Ol-FK for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:13 -0400 Received: by mail-pl1-x62d.google.com with SMTP id d9443c01a7336-2d004f135b1so42611515ad.3 for ; Fri, 07 Aug 2026 08:29:11 -0700 (PDT) Received: from localhost.localdomain ([2406:da14:1cf8:d800:471c:a879:4603:554f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14ccae6f8sm10953895ad.1.2026.08.07.08.29.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 08:29:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786116550; x=1786721350; 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:content-type; bh=/Dl+jMIxfRI9WOJazK+zPFzjGcmCKJrAWcw1IrtW8bA=; b=UHqwV1RKitKnZEjyrPf5Z0KVgNEHihedHnujC7lOcx6K8UgauGRBft9ayoMUJBx5ee CyPJAk27UTpnevYCejY4X+axV2Rk1u5kgs2SdEKzgUDE/lR1sXs9cSzTtcryaELhipiV ea6vv2keDrRYKnXUlv8oj8ikzHw6hVu626d7qNaT3gUSQk5u3gMOufwyq7zbRQgrutcq h6DwH8eAXStysJxtCOGn5kbyfNu+2mqzsp1a+qJny43ritbhy1Yqj1m6+CEzEVhXJ2MB bhmMn+pNjnTJu70C8YviLCp+TbDv31fjkImGlPBZQot+XHDhfvUtYg4MNQQ8O71SA5s6 K9xg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786116550; x=1786721350; 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:content-type; bh=/Dl+jMIxfRI9WOJazK+zPFzjGcmCKJrAWcw1IrtW8bA=; b=q8IdAS2d7UVDtx8NvuyErxz7kh6pFkvBjw4WbQkl0+WgHWEBL++f7AuR/qZksb+Ks7 lF9IFMdKOXv+ttWT2Mde/VNE9LUu7jF/eVh/MaUBxxC3Ns54Bf9JfdgMC2Oqg/ZOlTNS kmDOiuePLmpLNB+eQde0c1O442SRSIy6PwsoKq9RE7iagt89xj1QP/951ikIRxmLSmV9 xSwV1keUFFGCdmHZvV9doslo8wM5RIY7KYFgMKu3IwY41jSvPTcwRFc8XkOz4FmMf6YD vH98Yqbaa8p1FuG0QPP3nANbD6CAxcVZT7l1bak7Qx11UbFnL7oNSKKw9EJR4qdpVeyB vxxg== X-Gm-Message-State: AOJu0YxXVUQN2VEzvCXRGWTq3VUsFLZUWp/yI+vGRNNYZeltQp7cJ5ji FdgNQ4abR/VLJgrLU/iG+yb7CpijHTvA3lK8AGu/P936nZJs5TJjELQ1 X-Gm-Gg: AR+sD12rQSj3yOXOPjwCb9MgHnQguSzrgcfbYFv+prL5xs62l5iiV7UPynk9lv+lo6I 19MjGgyrq4jwsdxzf4uEnuC4uXQLMVvZb0Z7lDXXQVt8ik63papobqwEgroYn3Bu3Vwn1xMKuqD 6sKIuBAO+rXjXToVNJ5aLxn3IfkG+BDtXqZqVQgFSZfsVnOQ0gd7RoyZdaaql8d2j0081s6e4FF pxyizrh5Kwk1PHl53KCeihLhRO7771RXJ3igg4b6AiAZdRJ+cjHi75bk8TfXfB3b+T/aZffylhz HJeAz8yrJykal92eteavJWTc3r8YRHkygEcUyN/a2CEGJlJnS+xjq5jWmAJiPt2FQKDytIn1QQA vLxR2+u0E8lMYREssCi/pP0XWDDy01HAZJgBa/MO6k+MwhVgGghcbhLHYpaevJ7LlXUQus8reR5 uo7dcaAgNpVmBVpSQo8zwZNeDMaL+pfL8+RCTZBttI47G0w9w/6MV8Br94eD+4AYQ6yO3sABVBR FktDzwPZM4= X-Received: by 2002:a17:902:e94c:b0:2c8:4c29:afeb with SMTP id d9443c01a7336-2d0ca7b5520mr304869535ad.8.1786116550071; Fri, 07 Aug 2026 08:29:10 -0700 (PDT) From: Wang Zhongyu To: Chao Liu Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org, Paolo Bonzini , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei Subject: [PATCH 3/5] tests/qtest: add K230 I2C controller tests Date: Fri, 7 Aug 2026 23:28:28 +0800 Message-ID: <20260807152830.6833-4-wzy15515798875@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260807152830.6833-1-wzy15515798875@gmail.com> References: <20260807152830.6833-1-wzy15515798875@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::62d; envelope-from=wzy15515798875@gmail.com; helo=mail-pl1-x62d.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, FROM_LOCAL_DIGITS=0.001, FROM_LOCAL_HEX=0.006, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 Aug 2026 12:41:00 -0400 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: 1786120940319158500 Content-Type: text/plain; charset="utf-8" Add qtests covering reset values, all five controller instances, register access and locking, enable and disable behavior, interrupt masking, RX underflow, and address NACK reporting. Signed-off-by: Wang Zhongyu Reviewed-by: Daniel Henrique Barboza --- MAINTAINERS | 1 + tests/qtest/k230-i2c-test.c | 335 ++++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 3 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/k230-i2c-test.c diff --git a/MAINTAINERS b/MAINTAINERS index ac61054dd1..d0053441a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1834,6 +1834,7 @@ F: include/hw/i2c/k230_i2c.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: tests/functional/riscv64/test_k230.py +F: tests/qtest/k230-i2c-test.c F: tests/qtest/k230-wdt-test.c =20 RX Machines diff --git a/tests/qtest/k230-i2c-test.c b/tests/qtest/k230-i2c-test.c new file mode 100644 index 0000000000..cc8dd54153 --- /dev/null +++ b/tests/qtest/k230-i2c-test.c @@ -0,0 +1,335 @@ +/* + * QTest testcase for K230 DesignWare I2C controller + * + * Copyright (c) 2026 Wang Zhongyu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" + +/* K230 I2C controller base addresses */ +#define K230_I2C0_BASE 0x91405000 +#define K230_I2C1_BASE 0x91406000 +#define K230_I2C2_BASE 0x91407000 +#define K230_I2C3_BASE 0x91408000 +#define K230_I2C4_BASE 0x91409000 + +#define K230_I2C_COUNT 5 + +/* Register offsets used by the tests */ +#define K230_IC_CON 0x00 +#define K230_IC_TAR 0x04 +#define K230_IC_SAR 0x08 +#define K230_IC_HS_MADDR 0x0c +#define K230_IC_DATA_CMD 0x10 +#define K230_IC_INTR_STAT 0x2c +#define K230_IC_INTR_MASK 0x30 +#define K230_IC_RAW_INTR_STAT 0x34 +#define K230_IC_RX_TL 0x38 +#define K230_IC_TX_TL 0x3c +#define K230_IC_CLR_RX_UNDER 0x44 +#define K230_IC_CLR_TX_ABRT 0x54 +#define K230_IC_ENABLE 0x6c +#define K230_IC_STATUS 0x70 +#define K230_IC_TXFLR 0x74 +#define K230_IC_RXFLR 0x78 +#define K230_IC_TX_ABRT_SOURCE 0x80 +#define K230_IC_ENABLE_STATUS 0x9c +#define K230_IC_COMP_PARAM_1 0xf4 +#define K230_IC_COMP_VERSION 0xf8 +#define K230_IC_COMP_TYPE 0xfc + +#define IC_CON_10BITADDR_MASTER BIT(4) + +/* IC_DATA_CMD */ +#define IC_DATA_CMD_STOP BIT(9) + +/* IC_INTR_STAT and IC_RAW_INTR_STAT */ +#define IC_INTR_RX_UNDER BIT(0) +#define IC_INTR_TX_EMPTY BIT(4) +#define IC_INTR_TX_ABRT BIT(6) + +/* IC_STATUS */ +#define IC_STATUS_TFNF BIT(1) +#define IC_STATUS_TFE BIT(2) + +/* IC_TX_ABRT_SOURCE */ +#define IC_ABRT_7B_ADDR_NOACK BIT(0) + +#define K230_IC_COMP_PARAM_1_VALUE 0x001f3fae +#define K230_IC_COMP_VERSION_VALUE 0x3132302a +#define K230_IC_COMP_TYPE_VALUE 0x44570140 + +static const uint64_t k230_i2c_base[K230_I2C_COUNT] =3D { + K230_I2C0_BASE, + K230_I2C1_BASE, + K230_I2C2_BASE, + K230_I2C3_BASE, + K230_I2C4_BASE, +}; + +static void test_reset_values(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t status; + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), + =3D=3D, 0x7f); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x55); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), + =3D=3D, 0x55); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_HS_MADDR), + =3D=3D, 0x1); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_ENABLE), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), + =3D=3D, 0); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TXFLR), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RXFLR), + =3D=3D, 0); + + status =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_STATUS); + g_assert_cmphex(status, =3D=3D, IC_STATUS_TFNF | IC_STATUS_TFE); + + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT), + =3D=3D, 0); + + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_COMP_PARAM_1), + =3D=3D, K230_IC_COMP_PARAM_1_VALUE); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_COMP_VERSION), + =3D=3D, K230_IC_COMP_VERSION_VALUE); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_COMP_TYPE), + =3D=3D, K230_IC_COMP_TYPE_VALUE); + + qtest_quit(qts); +} + +static void test_all_instances(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + for (int i =3D 0; i < K230_I2C_COUNT; i++) { + g_assert_cmphex(qtest_readl(qts, + k230_i2c_base[i] + + K230_IC_COMP_TYPE), + =3D=3D, K230_IC_COMP_TYPE_VALUE); + } + + qtest_quit(qts); +} + +static void test_register_access(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), + =3D=3D, 0x7f); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0xfff); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SAR, UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), + =3D=3D, 0x3ff); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_MADDR, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_HS_MADDR), + =3D=3D, 0x7); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_RX_TL, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RX_TL), + =3D=3D, 63); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TX_TL, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TX_TL), + =3D=3D, 32); + + qtest_quit(qts); +} + +static void test_register_lock_while_enabled(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x22); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x33); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, 0); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x22); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), + =3D=3D, 0x7f); + + qtest_quit(qts); +} + +static void test_enable_disable(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t raw; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_ENABLE), + =3D=3D, 1); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), + =3D=3D, 1); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, =3D=3D, IC_INTR_TX_EMPTY); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 0); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_ENABLE), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), + =3D=3D, 0); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_interrupt_mask(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t raw; + uint32_t stat; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, =3D=3D, IC_INTR_TX_EMPTY); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, 0); + + stat =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_INTR_STAT); + g_assert_cmphex(stat, =3D=3D, 0); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, =3D=3D, IC_INTR_TX_EMPTY); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, + IC_INTR_TX_EMPTY); + + stat =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_INTR_STAT); + g_assert_cmphex(stat & IC_INTR_TX_EMPTY, =3D=3D, IC_INTR_TX_EMPTY); + + qtest_quit(qts); +} + +static void test_rx_underflow(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t raw; + + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_DATA_CMD), + =3D=3D, 0); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, IC_INTR_RX_UNDER); + + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_RX_UNDER); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_address_nack(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t con; + uint32_t raw; + uint32_t source; + + /* + * No slave is attached at address 0x7f, so the address phase + * must terminate with TX_ABRT. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~IC_CON_10BITADDR_MASTER; + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x7f); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_7B_ADDR_NOACK, + =3D=3D, IC_ABRT_7B_ADDR_NOACK); + + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(source, =3D=3D, 0); + + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/k230-i2c/reset-values", + test_reset_values); + qtest_add_func("/k230-i2c/all-instances", + test_all_instances); + qtest_add_func("/k230-i2c/register-access", + test_register_access); + qtest_add_func("/k230-i2c/register-lock-while-enabled", + test_register_lock_while_enabled); + qtest_add_func("/k230-i2c/enable-disable", + test_enable_disable); + qtest_add_func("/k230-i2c/interrupt-mask", + test_interrupt_mask); + qtest_add_func("/k230-i2c/rx-underflow", + test_rx_underflow); + qtest_add_func("/k230-i2c/address-nack", + test_address_nack); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 56ff860e21..56fb0af800 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -297,7 +297,7 @@ qtests_riscv64 =3D ['riscv-csr-test'] + \ (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \ - (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) + (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test', 'k230-i2c= -test'] : []) =20 qtests_hexagon =3D ['boot-serial-test'] =20 --=20 2.43.0 From nobody Mon Sep 28 01:13:34 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=1786120875; cv=none; d=zohomail.com; s=zohoarc; b=Jx+7NaiOb/ZjVZSg541FtofUtKXXPLrGVTZX7LwlaxSDsL8EjnUzK7c+YOpJquwGT1iAJzaaqUkb5SKqTP1RDqqLEG3SzOoZyIW+52UfR0vsa6Q2TNGCX+uHrSO8lpeYjLMoFdGWufzfnw1x/3FC5YdEHA0ZMMiC4UrF0JYc8Zg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786120875; 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=g5/aZDuUgTzjvt17wtPEDLBGnusydhUp0vEqnbq27FU=; b=LhKTkmlvXWw1QUsZOd5meNKvOTjAtUzx3d99U44dT6xVyXRxRwb/MlnE2f4JXXtFUU/M65aXh/zWrLfKzUSOmuknPA2NU5vODm/1+sqm0dJvboeDJfRb6yoMkJ5NP3mSsEmDflmF+/nKDyt0xCo1nNeNeqTF7rYKFY1MkAAmGEo= 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 1786120875546448.2015365374218; Fri, 7 Aug 2026 09:41:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wsNd0-0001ab-01; Fri, 07 Aug 2026 12:41:02 -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 1wsMVc-0004Uw-Nk for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:20 -0400 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wsMVZ-0007Pi-UX for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:20 -0400 Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-2ce7d2adef4so52485765ad.3 for ; Fri, 07 Aug 2026 08:29:17 -0700 (PDT) Received: from localhost.localdomain ([2406:da14:1cf8:d800:471c:a879:4603:554f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14ccae6f8sm10953895ad.1.2026.08.07.08.29.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 08:29:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786116557; x=1786721357; 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:content-type; bh=g5/aZDuUgTzjvt17wtPEDLBGnusydhUp0vEqnbq27FU=; b=kyGyb976FOYZ7xK2n1sztEKGlNctZtXbrL8UdJNJA+maf7okpZizVBMrmeuwDEvuk/ CvjdHE0S/gqkJ39aLGZQhj3TXtnGTaP70Kh9t7K6+rVIBNND/nvTrmJq3FHn8gCOT/Ml tBcZppiyjKKG6ysUnmnchKxsAERHCsfwW7lZ7A9fokqITE1/lUzjHIvoivkhG8ln83Y/ HmzeWche1gcZhwx8N3LBkjSj/BWGzIUgy8qSm6y9lqlaV4h3fTYLsbKVYEt++CysiDb5 ZbxT4DOKJv2xXSHknC5v+DJ5QOQohRoqKdHC2hdvO9cFUPhcLtFQGGPPRnIYUUxGKobJ f7XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786116557; x=1786721357; 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:content-type; bh=g5/aZDuUgTzjvt17wtPEDLBGnusydhUp0vEqnbq27FU=; b=HcH+La7kANMp8/SW2/sSRFCjjG7zZ+aR+/iKm1529IPRY/7Pw7Tp8Xd2O8GWWzp2+3 UeChg6cPYX6yIqqzo9bgwaRZYCR1sZxapyl08t6FEbpaiiWvAZKDZWPMPcUFh3hCMAhC WF3EbYMbpm/alvAekRuDP0avbnagZr3QF267h1j4l0w1ZC4S+7od3nl4ll6+fEvgD/wo FbtLroQnrOI7p/3kzAbu10vHI/mxkXa9P6XyGwRgZWO9TgljczCkqXP3PIwcVrjyYARH IsscnNJ3DcX+RFVXRUN/5cSUtHH3Elfj+7k16jE64NMAhzttvma2BGGGsVt/bVQ4Ytb6 Fa2w== X-Gm-Message-State: AOJu0Yza56fI3Y2izb3fJqTBBBwoTKooDYYE/4i/bF3Tm3xPKT+TE5TB kr+h4p0KpDxgkUWkqoLo+MniEMZUWsbr4BoGvAhmTQeypblCrUxLaKN0 X-Gm-Gg: AR+sD13Dmx3lI13JjZOTZpqad29X+iTtaBgVvKQ3GzLTtbO96NuKIZthhkHp0aIjIt7 HlMNsCG7qdfs8bOhgM9g3J3e2NttwF3YSEHUjDWzEKlbq8O3vit2ph/Pzqkromp2A0+d0KJJstH b2nzpJ5dJTy4PZmxZwazg9fZXd24a34LZn4aRPAf8pwNXs1PkRwO7nBdTFEs5MIG/+10fGSkgGR Zho/w6zu4bdlmxiFzkGVG2oY3WgtDQbSs6gI1aSTxZ8Zx5bcpTdM/grwbiThReNa2Fts1Zl5Agq MVz69miEup5LVdw2pMbOvOfLUvLs2ydCovpw56OVc0TVmnHYzGAhmyMrhDAYtoPUjL4Ti1IIpDk vuPSzHxAyRNGR9cgprSGcxoOrb6VrEtU+iG78apk6ydFe4gtJoPPnFGDwCOdZteU1EpVG3wkK0L +/Q1OpWyDm25vB1h8D/TImEn9l2MzF2xSD7lOxKRQqHyyPH33YPHf9Gm7bpkU/SNxzJDQElk2Gp 24qciwg4R4= X-Received: by 2002:a17:903:40c5:b0:2c7:1200:bd7e with SMTP id d9443c01a7336-2d294c48ec2mr62397915ad.18.1786116556519; Fri, 07 Aug 2026 08:29:16 -0700 (PDT) From: Wang Zhongyu To: Chao Liu Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org, Paolo Bonzini , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei Subject: [PATCH 4/5] tests/qtest: expand K230 I2C controller tests Date: Fri, 7 Aug 2026 23:28:29 +0800 Message-ID: <20260807152830.6833-5-wzy15515798875@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260807152830.6833-1-wzy15515798875@gmail.com> References: <20260807152830.6833-1-wzy15515798875@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::62a; envelope-from=wzy15515798875@gmail.com; helo=mail-pl1-x62a.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, FROM_LOCAL_DIGITS=0.001, FROM_LOCAL_HEX=0.006, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 Aug 2026 12:41:00 -0400 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: 1786120878132158500 Content-Type: text/plain; charset="utf-8" Expand the K230 I2C qtests to cover instance isolation, read-only registers, system reset, read-to-clear interrupts, abort source reporting, and START BYTE abort handling. Signed-off-by: Wang Zhongyu Reviewed-by: Daniel Henrique Barboza --- tests/qtest/k230-i2c-test.c | 532 +++++++++++++++++++++++++++++++++++- 1 file changed, 529 insertions(+), 3 deletions(-) diff --git a/tests/qtest/k230-i2c-test.c b/tests/qtest/k230-i2c-test.c index cc8dd54153..1d134de5d0 100644 --- a/tests/qtest/k230-i2c-test.c +++ b/tests/qtest/k230-i2c-test.c @@ -25,11 +25,18 @@ #define K230_IC_SAR 0x08 #define K230_IC_HS_MADDR 0x0c #define K230_IC_DATA_CMD 0x10 +#define K230_IC_SS_SCL_HCNT 0x14 +#define K230_IC_SS_SCL_LCNT 0x18 +#define K230_IC_FS_SCL_HCNT 0x1c +#define K230_IC_FS_SCL_LCNT 0x20 +#define K230_IC_HS_SCL_HCNT 0x24 +#define K230_IC_HS_SCL_LCNT 0x28 #define K230_IC_INTR_STAT 0x2c #define K230_IC_INTR_MASK 0x30 #define K230_IC_RAW_INTR_STAT 0x34 #define K230_IC_RX_TL 0x38 #define K230_IC_TX_TL 0x3c +#define K230_IC_CLR_INTR 0x40 #define K230_IC_CLR_RX_UNDER 0x44 #define K230_IC_CLR_TX_ABRT 0x54 #define K230_IC_ENABLE 0x6c @@ -37,20 +44,32 @@ #define K230_IC_TXFLR 0x74 #define K230_IC_RXFLR 0x78 #define K230_IC_TX_ABRT_SOURCE 0x80 +#define K230_IC_SDA_SETUP 0x94 +#define K230_IC_ACK_GENERAL_CALL 0x98 #define K230_IC_ENABLE_STATUS 0x9c #define K230_IC_COMP_PARAM_1 0xf4 #define K230_IC_COMP_VERSION 0xf8 #define K230_IC_COMP_TYPE 0xfc =20 +/* IC_CON */ +#define IC_CON_MASTER_MODE BIT(0) #define IC_CON_10BITADDR_MASTER BIT(4) +#define IC_CON_RESTART_EN BIT(5) + +/* IC_TAR */ +#define IC_TAR_GC_OR_START BIT(10) +#define IC_TAR_SPECIAL BIT(11) =20 /* IC_DATA_CMD */ +#define IC_DATA_CMD_READ BIT(8) #define IC_DATA_CMD_STOP BIT(9) =20 /* IC_INTR_STAT and IC_RAW_INTR_STAT */ #define IC_INTR_RX_UNDER BIT(0) #define IC_INTR_TX_EMPTY BIT(4) #define IC_INTR_TX_ABRT BIT(6) +#define IC_INTR_ACTIVITY BIT(8) +#define IC_INTR_START_DET BIT(10) =20 /* IC_STATUS */ #define IC_STATUS_TFNF BIT(1) @@ -58,6 +77,10 @@ =20 /* IC_TX_ABRT_SOURCE */ #define IC_ABRT_7B_ADDR_NOACK BIT(0) +#define IC_ABRT_GCALL_NOACK BIT(4) +#define IC_ABRT_GCALL_READ BIT(5) +#define IC_ABRT_SBYTE_NORSTRT BIT(9) +#define IC_ABRT_MASTER_DIS BIT(11) =20 #define K230_IC_COMP_PARAM_1_VALUE 0x001f3fae #define K230_IC_COMP_VERSION_VALUE 0x3132302a @@ -131,6 +154,38 @@ static void test_all_instances(void) qtest_quit(qts); } =20 +static void test_instance_isolation(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x2a); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_RX_TL, 17); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, 0x41); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x2a); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RX_TL), + =3D=3D, 17); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_INTR_MASK), + =3D=3D, 0x41); + + for (int i =3D 1; i < K230_I2C_COUNT; i++) { + g_assert_cmphex(qtest_readl(qts, + k230_i2c_base[i] + K230_IC_TAR), + =3D=3D, 0x55); + g_assert_cmphex(qtest_readl(qts, + k230_i2c_base[i] + K230_IC_RX_TL), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + k230_i2c_base[i] + + K230_IC_INTR_MASK), + =3D=3D, 0x8ff); + } + + qtest_quit(qts); +} + static void test_register_access(void) { QTestState *qts =3D qtest_init("-machine k230"); @@ -163,6 +218,82 @@ static void test_register_access(void) g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TX_TL), =3D=3D, 32); =20 + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_INTR_MASK), + =3D=3D, 0xfff); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SDA_SETUP, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_SDA_SETUP), + =3D=3D, 0xff); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ACK_GENERAL_CALL, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_ACK_GENERAL_CALL), + =3D=3D, 1); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE, + UINT32_MAX); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_TX_ABRT_SOURCE), + =3D=3D, 0xffff); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_HCNT, + 65525); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_SS_SCL_HCNT), + =3D=3D, 65525); + + /* + * Values greater than 65525 are rejected. The previous valid + * value must be preserved. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_HCNT, + 65526); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_SS_SCL_HCNT), + =3D=3D, 65525); + + qtest_quit(qts); +} + +static void test_readonly_registers(void) +{ + static const struct { + uint32_t offset; + uint32_t expected; + } registers[] =3D { + { K230_IC_INTR_STAT, 0 }, + { K230_IC_RAW_INTR_STAT, 0 }, + { K230_IC_STATUS, IC_STATUS_TFNF | IC_STATUS_TFE }, + { K230_IC_TXFLR, 0 }, + { K230_IC_RXFLR, 0 }, + { K230_IC_ENABLE_STATUS, 0 }, + { K230_IC_COMP_PARAM_1, K230_IC_COMP_PARAM_1_VALUE }, + { K230_IC_COMP_VERSION, K230_IC_COMP_VERSION_VALUE }, + { K230_IC_COMP_TYPE, K230_IC_COMP_TYPE_VALUE }, + }; + QTestState *qts =3D qtest_init("-machine k230"); + + for (size_t i =3D 0; i < G_N_ELEMENTS(registers); i++) { + qtest_writel(qts, + K230_I2C0_BASE + registers[i].offset, + UINT32_MAX); + + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + registers[i].offset), + =3D=3D, registers[i].expected); + } + qtest_quit(qts); } =20 @@ -171,15 +302,78 @@ static void test_register_lock_while_enabled(void) QTestState *qts =3D qtest_init("-machine k230"); =20 qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x22); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SAR, 0x155); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_MADDR, 0x3); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_HCNT, 20); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_LCNT, 21); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_FS_SCL_HCNT, 22); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_FS_SCL_LCNT, 23); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_SCL_HCNT, 24); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_SCL_LCNT, 25); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); =20 - qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x33); + /* + * Configuration registers cannot be changed while the + * controller is enabled. + */ qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, 0); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x33); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SAR, 0x222); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_MADDR, 0x7); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_HCNT, 30); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SS_SCL_LCNT, 31); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_FS_SCL_HCNT, 32); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_FS_SCL_LCNT, 33); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_SCL_HCNT, 34); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_HS_SCL_LCNT, 35); =20 - g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), - =3D=3D, 0x22); g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), =3D=3D, 0x7f); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x22); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), + =3D=3D, 0x155); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_HS_MADDR), + =3D=3D, 0x3); + + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_SS_SCL_HCNT), + =3D=3D, 20); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_SS_SCL_LCNT), + =3D=3D, 21); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_FS_SCL_HCNT), + =3D=3D, 22); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_FS_SCL_LCNT), + =3D=3D, 23); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_HS_SCL_HCNT), + =3D=3D, 24); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_HS_SCL_LCNT), + =3D=3D, 25); + + /* + * Configuration registers become writable again after the + * controller is disabled. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 0); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x33); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x33); =20 qtest_quit(qts); } @@ -281,6 +475,7 @@ static void test_address_nack(void) */ con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); con &=3D ~IC_CON_10BITADDR_MASTER; + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x7f); qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); @@ -310,6 +505,325 @@ static void test_address_nack(void) qtest_quit(qts); } =20 +static void test_system_reset(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t raw; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x2a); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SAR, 0x123); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_RX_TL, 10); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TX_TL, 12); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, 0); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + + /* + * Reading an empty RX FIFO produces RX_UNDER. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_DATA_CMD); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, IC_INTR_RX_UNDER); + + qtest_system_reset(qts); + + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), + =3D=3D, 0x7f); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), + =3D=3D, 0x55); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), + =3D=3D, 0x55); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_HS_MADDR), + =3D=3D, 0x1); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_INTR_MASK), + =3D=3D, 0x8ff); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RX_TL), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TX_TL), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_ENABLE), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + K230_I2C0_BASE + + K230_IC_TX_ABRT_SOURCE), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TXFLR), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RXFLR), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_STATUS), + =3D=3D, IC_STATUS_TFNF | IC_STATUS_TFE); + + qtest_quit(qts); +} + +static void test_clear_on_read(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t con; + uint32_t raw; + uint32_t source; + + /* + * Produce RX_UNDER. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_DATA_CMD); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, IC_INTR_RX_UNDER); + + /* + * Writing a clear register must not clear the interrupt. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CLR_RX_UNDER, 1); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, IC_INTR_RX_UNDER); + + /* + * Produce an independent TX_ABRT interrupt. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~IC_CON_10BITADDR_MASTER; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x7f); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, IC_INTR_RX_UNDER); + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_7B_ADDR_NOACK, + =3D=3D, IC_ABRT_7B_ADDR_NOACK); + + /* + * Reading CLR_RX_UNDER clears only RX_UNDER. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_RX_UNDER); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + + /* + * Writing CLR_TX_ABRT must not clear TX_ABRT. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT, 1); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + + /* + * Reading CLR_TX_ABRT clears TX_ABRT and its source. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(source, =3D=3D, 0); + + /* + * CLR_INTR clears latched interrupts. TX_EMPTY remains asserted + * because it is recalculated from the empty TX FIFO. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_INTR); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + + g_assert_cmphex(raw & IC_INTR_RX_UNDER, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_START_DET, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, =3D=3D, IC_INTR_TX_EMPTY); + + qtest_quit(qts); +} + +static void test_abort_sources(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t con; + uint32_t raw; + uint32_t source; + + /* + * Master mode disabled. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~(IC_CON_MASTER_MODE | IC_CON_10BITADDR_MASTER); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, 0x7f); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_MASTER_DIS, + =3D=3D, IC_ABRT_MASTER_DIS); + + qtest_system_reset(qts); + + /* + * A read command cannot target the General Call address. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~IC_CON_10BITADDR_MASTER; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, + IC_TAR_SPECIAL); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_READ | IC_DATA_CMD_STOP); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_GCALL_READ, + =3D=3D, IC_ABRT_GCALL_READ); + + qtest_system_reset(qts); + + /* + * No slave is attached to acknowledge the General Call. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~IC_CON_10BITADDR_MASTER; + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, + IC_TAR_SPECIAL); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_GCALL_NOACK, + =3D=3D, IC_ABRT_GCALL_NOACK); + + qtest_system_reset(qts); + + /* + * 10-bit master addressing is deliberately unsupported. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source, =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_start_byte_abort(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t con; + uint32_t raw; + uint32_t source; + + /* + * START BYTE requires RESTART_EN. + */ + con =3D qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); + con &=3D ~(IC_CON_10BITADDR_MASTER | IC_CON_RESTART_EN); + + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, + IC_TAR_SPECIAL | IC_TAR_GC_OR_START); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); + qtest_writel(qts, K230_I2C0_BASE + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x55); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_SBYTE_NORSTRT, + =3D=3D, IC_ABRT_SBYTE_NORSTRT); + + /* + * Bit 9 remains set while the invalid configuration remains. + */ + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_SBYTE_NORSTRT, + =3D=3D, IC_ABRT_SBYTE_NORSTRT); + + /* + * Remove the cause by enabling RESTART_EN, then clear again. + */ + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 0); + + con |=3D IC_CON_RESTART_EN; + qtest_writel(qts, K230_I2C0_BASE + K230_IC_CON, con); + + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(source, =3D=3D, 0); + + qtest_quit(qts); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -318,8 +832,12 @@ int main(int argc, char **argv) test_reset_values); qtest_add_func("/k230-i2c/all-instances", test_all_instances); + qtest_add_func("/k230-i2c/instance-isolation", + test_instance_isolation); qtest_add_func("/k230-i2c/register-access", test_register_access); + qtest_add_func("/k230-i2c/readonly-registers", + test_readonly_registers); qtest_add_func("/k230-i2c/register-lock-while-enabled", test_register_lock_while_enabled); qtest_add_func("/k230-i2c/enable-disable", @@ -330,6 +848,14 @@ int main(int argc, char **argv) test_rx_underflow); qtest_add_func("/k230-i2c/address-nack", test_address_nack); + qtest_add_func("/k230-i2c/system-reset", + test_system_reset); + qtest_add_func("/k230-i2c/clear-on-read", + test_clear_on_read); + qtest_add_func("/k230-i2c/abort-sources", + test_abort_sources); + qtest_add_func("/k230-i2c/start-byte-abort", + test_start_byte_abort); =20 return g_test_run(); } --=20 2.43.0 From nobody Mon Sep 28 01:13:34 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=1786120907; cv=none; d=zohomail.com; s=zohoarc; b=lw/aGdYovWVAD/5bKeSYwjW0kER3vaWU0+fPDcVeSkD1E49coMOCIQCBC4GcaL+tdPfL4FIj6pEzH+doOwRflFfbgopTsV/g0rsqMJKIcd7d1j91ExbHTvRE21R3KEdZZnVfwWij2HSXPsdytYkHlOhjIPQH3/1dw9RBCfx5nGI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786120907; 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=WRT7Ht2mEENkwBrIlmhqK7G+z/zY98Xv2eh9U+KRqmw=; b=Z2TjLNQGrZ0wmV4Xue6q2bHinKTOvp+ruXTiGXNDCeSyUE0S0PQlE4en8+sapDTu/Q7aAbPPNogE+gm6uEDU2thsMiP4rl3ACtKodhTUHW5czYO5KyvIRbeM8Ay/6izwBl14sZ4tG7nUSwBpYpoeIgWvQ71EGe0gGhp3P0rPpps= 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 1786120907542999.2056385634525; Fri, 7 Aug 2026 09:41:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wsNd0-0001eV-Ix; Fri, 07 Aug 2026 12:41:02 -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 1wsMVk-0004ZC-9D for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:28 -0400 Received: from mail-pl1-x636.google.com ([2607:f8b0:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wsMVh-0007R3-Fp for qemu-devel@nongnu.org; Fri, 07 Aug 2026 11:29:28 -0400 Received: by mail-pl1-x636.google.com with SMTP id d9443c01a7336-2ce7d2adef4so52488545ad.3 for ; Fri, 07 Aug 2026 08:29:25 -0700 (PDT) Received: from localhost.localdomain ([2406:da14:1cf8:d800:471c:a879:4603:554f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d14ccae6f8sm10953895ad.1.2026.08.07.08.29.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 08:29:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786116564; x=1786721364; 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:content-type; bh=WRT7Ht2mEENkwBrIlmhqK7G+z/zY98Xv2eh9U+KRqmw=; b=H1Ud0nzS9R76fv183XdSoeSqRD9jB2ctPt44D3B3BzCwFGRWxWCMimQlKkFupv8Tw8 PByRIhHWQMlbaWdd+0u7PZx3+0t191mANgKc1BS0Tupj/E5FJC/8Nof/d5J5H3xZVva7 lCFa2e319aMsVlBaAx//QF4y+OaZE5VFfoI2NKiiktEXYocRXV3HqTqW8lxoFru/tgjj 5BwivcPR4/DwVcj6pd0EYYhh1NOkzAVYeHsuSPGxWo5elP6wVLT5s8Mo9Abl+j/BPF0E cOLaf38ze+vP1qKPK75Ne7mnBIyF3H3kMBKBhxG+b5ZRqR/85J/qv1LHKBUlr55osRyC rD/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786116564; x=1786721364; 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:content-type; bh=WRT7Ht2mEENkwBrIlmhqK7G+z/zY98Xv2eh9U+KRqmw=; b=XxxmSXcQdIc2Cq6AcTIWAjzCI60p4EwpG9aU793Pkwd2QUQ58u/17e0jt4lyfN8DC9 VxVPmH8RCGDvdtU0XkQJXg+b//G6tnnaflZeGXtO8EqUKTmv4kBhzAcxqVAQc6WwUKFo Q+8FzgDWZNKeowW/H4+1w7ywCWDQYvP/chsOeYFgw5HCy/+LNtygn12PT6+yYMupwIjO yteYPPZS4SgerSZBj2MxqPdVP+CqISBdhULtjHyWOXEkH8i2NABvLRHW3HOTpfNlxej3 RXJIArqd37D3/zhNawNUKZQaFPBjgMtCK05Nav2FAE/5UCydE359oeTs65yw39gdFAUc jAYg== X-Gm-Message-State: AOJu0YxRWTgzC/c10euQqiZ9l5dZRqUxLEi32u+/1eLydeHsIo7InrUz 4vWD0ifHHGFsN9BlkcNVt4wbv+wWX3rFabdZW+jn3eXK7wcfvLXHCu/W X-Gm-Gg: AR+sD10xlKboZ3BeD8/uKdY6T2uSfAKo9G72WNcDHhw6gjfGoy5Mm/w3qKilEsbAIUM CSKLIavV0USee8UiaeAt2UxgMMpt9YzWIIpRvTM+aYyWqbOMCMFBBkZpSlR7P2mfKEAFUngoomZ IYc+utjkbaioL2Csn/a7D1/zzDl/hr1xHuRBh5d5KsXZwNRR+n8DlQlcnlUVQ99435D0JVr1IpJ PKnY9aGfVSsi11X0RGiwgl3Cv6td1AboHvMor5VehdzddHJeheHKG/+UNAcg786ciaYPGnBO0uA s2w7P/469sH+C9Yyq9cJz7fSXYcBaiKsJW2/Pb3VQQ3AeREyZ8GsbGk1+/eK1gn/RnV+iYe2kLZ ++tgM58IvGrsYgVbjRUAMS5liWrRtpWxRsR01oZgCYyN8bq8RxY9dh65fzzok4nEd2DO+QBFTsD MSaiwfkgNBUKgJbwYBkWMdDNv84lcr2SOpA3tAk0xngLobpHpLQZx/ky2cALsZ/uzAuhOAohn7o Gb+oghE0Ds= X-Received: by 2002:a17:903:3b87:b0:2ce:93a3:c168 with SMTP id d9443c01a7336-2d294b4b57bmr63393675ad.7.1786116564065; Fri, 07 Aug 2026 08:29:24 -0700 (PDT) From: Wang Zhongyu To: Chao Liu Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org, Paolo Bonzini , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei Subject: [PATCH 5/5] tests/qtest: test K230 I2C transfers with slave devices Date: Fri, 7 Aug 2026 23:28:30 +0800 Message-ID: <20260807152830.6833-6-wzy15515798875@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260807152830.6833-1-wzy15515798875@gmail.com> References: <20260807152830.6833-1-wzy15515798875@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::636; envelope-from=wzy15515798875@gmail.com; helo=mail-pl1-x636.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, FROM_LOCAL_DIGITS=0.001, FROM_LOCAL_HEX=0.006, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 Aug 2026 12:41:00 -0400 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: 1786120908099158500 Content-Type: text/plain; charset="utf-8" Add transfer tests using TMP105 and i2c-echo slave devices. Cover single- and multi-byte reads and writes, combined write/read transfers, repeated START and STOP handling, RX threshold and overflow behavior, data NACK reporting, restart-disabled aborts. Signed-off-by: Wang Zhongyu Reviewed-by: Daniel Henrique Barboza --- tests/qtest/k230-i2c-test.c | 598 ++++++++++++++++++++++++++++++++++++ 1 file changed, 598 insertions(+) diff --git a/tests/qtest/k230-i2c-test.c b/tests/qtest/k230-i2c-test.c index 1d134de5d0..ee788216fb 100644 --- a/tests/qtest/k230-i2c-test.c +++ b/tests/qtest/k230-i2c-test.c @@ -38,7 +38,11 @@ #define K230_IC_TX_TL 0x3c #define K230_IC_CLR_INTR 0x40 #define K230_IC_CLR_RX_UNDER 0x44 +#define K230_IC_CLR_RX_OVER 0x48 #define K230_IC_CLR_TX_ABRT 0x54 +#define K230_IC_CLR_ACTIVITY 0x5c +#define K230_IC_CLR_STOP_DET 0x60 +#define K230_IC_CLR_START_DET 0x64 #define K230_IC_ENABLE 0x6c #define K230_IC_STATUS 0x70 #define K230_IC_TXFLR 0x74 @@ -63,20 +67,29 @@ /* IC_DATA_CMD */ #define IC_DATA_CMD_READ BIT(8) #define IC_DATA_CMD_STOP BIT(9) +#define IC_DATA_CMD_RESTART BIT(10) =20 /* IC_INTR_STAT and IC_RAW_INTR_STAT */ #define IC_INTR_RX_UNDER BIT(0) +#define IC_INTR_RX_OVER BIT(1) +#define IC_INTR_RX_FULL BIT(2) #define IC_INTR_TX_EMPTY BIT(4) #define IC_INTR_TX_ABRT BIT(6) #define IC_INTR_ACTIVITY BIT(8) +#define IC_INTR_STOP_DET BIT(9) #define IC_INTR_START_DET BIT(10) =20 /* IC_STATUS */ +#define IC_STATUS_ACTIVITY BIT(0) #define IC_STATUS_TFNF BIT(1) #define IC_STATUS_TFE BIT(2) +#define IC_STATUS_RFNE BIT(3) +#define IC_STATUS_RFF BIT(4) +#define IC_STATUS_MST_ACTIVITY BIT(5) =20 /* IC_TX_ABRT_SOURCE */ #define IC_ABRT_7B_ADDR_NOACK BIT(0) +#define IC_ABRT_TXDATA_NOACK BIT(3) #define IC_ABRT_GCALL_NOACK BIT(4) #define IC_ABRT_GCALL_READ BIT(5) #define IC_ABRT_SBYTE_NORSTRT BIT(9) @@ -86,6 +99,19 @@ #define K230_IC_COMP_VERSION_VALUE 0x3132302a #define K230_IC_COMP_TYPE_VALUE 0x44570140 =20 +#define TMP105_ADDRESS 0x49 +#define I2C_ECHO_ADDRESS 0x50 + +#define TMP105_REG_TEMPERATURE 0x00 +#define TMP105_REG_CONFIG 0x01 +#define TMP105_REG_T_LOW 0x02 +#define TMP105_REG_T_HIGH 0x03 + +#define K230_I2C_SLAVE_MACHINE_ARGS \ + "-machine k230 " \ + "-device tmp105,id=3Dtmp105-test,address=3D0x49 " \ + "-device i2c-echo,id=3Di2c-echo-test,address=3D0x50" + static const uint64_t k230_i2c_base[K230_I2C_COUNT] =3D { K230_I2C0_BASE, K230_I2C1_BASE, @@ -94,6 +120,129 @@ static const uint64_t k230_i2c_base[K230_I2C_COUNT] = =3D { K230_I2C4_BASE, }; =20 +static QTestState *k230_i2c_init_with_slaves(void) +{ + return qtest_init(K230_I2C_SLAVE_MACHINE_ARGS); +} + +static void k230_i2c_configure_master(QTestState *qts, uint64_t base, + uint8_t target, bool restart_enable) +{ + uint32_t con; + + qtest_writel(qts, base + K230_IC_ENABLE, 0); + + con =3D qtest_readl(qts, base + K230_IC_CON); + con |=3D IC_CON_MASTER_MODE; + con &=3D ~IC_CON_10BITADDR_MASTER; + + if (restart_enable) { + con |=3D IC_CON_RESTART_EN; + } else { + con &=3D ~IC_CON_RESTART_EN; + } + + qtest_writel(qts, base + K230_IC_CON, con); + qtest_writel(qts, base + K230_IC_TAR, target); + qtest_writel(qts, base + K230_IC_ENABLE, 1); +} + +static void k230_i2c_assert_no_abort(QTestState *qts, uint64_t base) +{ + uint32_t raw; + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_TX_ABRT_SOURCE), + =3D=3D, 0); +} + +static uint64_t k230_i2c_find_tmp105_bus(QTestState *qts) +{ + for (int i =3D 0; i < K230_I2C_COUNT; i++) { + uint64_t base =3D k230_i2c_base[i]; + uint32_t raw; + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + /* + * A one-byte write selects the temperature register. The + * controller whose bus contains TMP105 completes without aborting. + */ + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | TMP105_REG_TEMPERATURE); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + + if (!(raw & IC_INTR_TX_ABRT)) { + qtest_writel(qts, base + K230_IC_ENABLE, 0); + return base; + } + + qtest_readl(qts, base + K230_IC_CLR_TX_ABRT); + qtest_writel(qts, base + K230_IC_ENABLE, 0); + } + + g_assert_not_reached(); +} + +static void k230_i2c_write_bytes(QTestState *qts, uint64_t base, + const uint8_t *data, size_t len) +{ + g_assert_cmpuint(len, >, 0); + + for (size_t i =3D 0; i < len; i++) { + uint32_t command =3D data[i]; + + if (i =3D=3D len - 1) { + command |=3D IC_DATA_CMD_STOP; + } + + qtest_writel(qts, base + K230_IC_DATA_CMD, command); + } + + k230_i2c_assert_no_abort(qts, base); +} + +static void k230_i2c_select_register(QTestState *qts, uint64_t base, + uint8_t reg) +{ + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | reg); + k230_i2c_assert_no_abort(qts, base); +} + +static void k230_i2c_queue_reads(QTestState *qts, uint64_t base, + size_t len, bool restart_first, + bool stop_last) +{ + g_assert_cmpuint(len, >, 0); + + for (size_t i =3D 0; i < len; i++) { + uint32_t command =3D IC_DATA_CMD_READ; + + if (i =3D=3D 0 && restart_first) { + command |=3D IC_DATA_CMD_RESTART; + } + + if (i =3D=3D len - 1 && stop_last) { + command |=3D IC_DATA_CMD_STOP; + } + + qtest_writel(qts, base + K230_IC_DATA_CMD, command); + } + + k230_i2c_assert_no_abort(qts, base); +} + +static void k230_i2c_tmp105_combined_read(QTestState *qts, uint64_t base, + uint8_t reg, size_t len) +{ + qtest_writel(qts, base + K230_IC_DATA_CMD, reg); + k230_i2c_queue_reads(qts, base, len, true, true); +} + static void test_reset_values(void) { QTestState *qts =3D qtest_init("-machine k230"); @@ -824,6 +973,432 @@ static void test_start_byte_abort(void) qtest_quit(qts); } =20 +static void test_tmp105_config_read_write(void) +{ + static const uint8_t write_data[] =3D { + TMP105_REG_CONFIG, + 0x60, + }; + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + k230_i2c_write_bytes(qts, base, write_data, + G_N_ELEMENTS(write_data)); + + k230_i2c_tmp105_combined_read(qts, base, + TMP105_REG_CONFIG, 1); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 1); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x60); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 0); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_tmp105_limit_read_write(void) +{ + static const uint8_t write_data[] =3D { + TMP105_REG_T_LOW, + 0x12, + 0x34, + }; + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + k230_i2c_write_bytes(qts, base, write_data, + G_N_ELEMENTS(write_data)); + + k230_i2c_tmp105_combined_read(qts, base, + TMP105_REG_T_LOW, 2); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 2); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x12); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x30); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 0); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_tmp105_direct_read(void) +{ + static const uint8_t write_data[] =3D { + TMP105_REG_CONFIG, + 0x20, + }; + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + k230_i2c_write_bytes(qts, base, write_data, + G_N_ELEMENTS(write_data)); + k230_i2c_select_register(qts, base, TMP105_REG_CONFIG); + + /* + * Start a read while the controller is idle. This covers the + * IDLE-to-RECEIVING path without a preceding repeated START. + */ + k230_i2c_queue_reads(qts, base, 1, false, true); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 1); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x20); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_tmp105_read_write_restart(void) +{ + static const uint8_t initial_data[] =3D { + TMP105_REG_CONFIG, + 0x20, + }; + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + k230_i2c_write_bytes(qts, base, initial_data, + G_N_ELEMENTS(initial_data)); + k230_i2c_select_register(qts, base, TMP105_REG_CONFIG); + + /* + * Leave the read transfer active, then switch from receiving to + * sending with a repeated START. + */ + k230_i2c_queue_reads(qts, base, 1, false, false); + + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_RESTART | TMP105_REG_CONFIG); + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x60); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 1); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x20); + + k230_i2c_tmp105_combined_read(qts, base, + TMP105_REG_CONFIG, 1); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x60); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_tmp105_same_direction_restart(void) +{ + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + + /* + * Start in the sending state, issue an explicit repeated START + * without changing direction, and then write the config register. + */ + qtest_writel(qts, base + K230_IC_DATA_CMD, + TMP105_REG_T_LOW); + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_RESTART | TMP105_REG_CONFIG); + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x40); + + k230_i2c_assert_no_abort(qts, base); + + k230_i2c_tmp105_combined_read(qts, base, + TMP105_REG_CONFIG, 1); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x40); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_transfer_status_with_slave(void) +{ + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + uint32_t raw; + uint32_t status; + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + qtest_readl(qts, base + K230_IC_CLR_INTR); + + qtest_writel(qts, base + K230_IC_DATA_CMD, + TMP105_REG_CONFIG); + + status =3D qtest_readl(qts, base + K230_IC_STATUS); + g_assert_cmphex(status & IC_STATUS_ACTIVITY, + =3D=3D, IC_STATUS_ACTIVITY); + g_assert_cmphex(status & IC_STATUS_MST_ACTIVITY, + =3D=3D, IC_STATUS_MST_ACTIVITY); + g_assert_cmphex(status & IC_STATUS_TFNF, + =3D=3D, IC_STATUS_TFNF); + g_assert_cmphex(status & IC_STATUS_TFE, + =3D=3D, IC_STATUS_TFE); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_START_DET, + =3D=3D, IC_INTR_START_DET); + g_assert_cmphex(raw & IC_INTR_ACTIVITY, + =3D=3D, IC_INTR_ACTIVITY); + + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x20); + + status =3D qtest_readl(qts, base + K230_IC_STATUS); + g_assert_cmphex(status & IC_STATUS_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_MST_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_TFNF, + =3D=3D, IC_STATUS_TFNF); + g_assert_cmphex(status & IC_STATUS_TFE, + =3D=3D, IC_STATUS_TFE); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_STOP_DET, + =3D=3D, IC_INTR_STOP_DET); + g_assert_cmphex(raw & IC_INTR_ACTIVITY, + =3D=3D, IC_INTR_ACTIVITY); + + qtest_readl(qts, base + K230_IC_CLR_START_DET); + qtest_readl(qts, base + K230_IC_CLR_STOP_DET); + qtest_readl(qts, base + K230_IC_CLR_ACTIVITY); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_START_DET, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_STOP_DET, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_ACTIVITY, =3D=3D, 0); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_rx_threshold_with_slave(void) +{ + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + uint32_t raw; + uint32_t stat; + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + qtest_writel(qts, base + K230_IC_RX_TL, 1); + qtest_writel(qts, base + K230_IC_INTR_MASK, + IC_INTR_RX_FULL); + + k230_i2c_select_register(qts, base, TMP105_REG_T_LOW); + qtest_readl(qts, base + K230_IC_CLR_INTR); + + k230_i2c_queue_reads(qts, base, 1, false, false); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_FULL, =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 1); + + k230_i2c_queue_reads(qts, base, 1, false, true); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + stat =3D qtest_readl(qts, base + K230_IC_INTR_STAT); + + g_assert_cmphex(raw & IC_INTR_RX_FULL, + =3D=3D, IC_INTR_RX_FULL); + g_assert_cmphex(stat & IC_INTR_RX_FULL, + =3D=3D, IC_INTR_RX_FULL); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 2); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x4b); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_FULL, =3D=3D, 0); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x00); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_rx_overflow_with_slave(void) +{ + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + uint32_t raw; + uint32_t status; + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, true); + qtest_writel(qts, base + K230_IC_RX_TL, 63); + qtest_writel(qts, base + K230_IC_INTR_MASK, + IC_INTR_RX_FULL | IC_INTR_RX_OVER); + + k230_i2c_select_register(qts, base, TMP105_REG_T_LOW); + qtest_readl(qts, base + K230_IC_CLR_INTR); + + /* + * TMP105 returns two register bytes and then 0xff. Sixty-five + * read commands therefore fill the 64-byte RX FIFO and overflow + * on the final command. + */ + k230_i2c_queue_reads(qts, base, 65, false, true); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 64); + + status =3D qtest_readl(qts, base + K230_IC_STATUS); + g_assert_cmphex(status & IC_STATUS_RFNE, + =3D=3D, IC_STATUS_RFNE); + g_assert_cmphex(status & IC_STATUS_RFF, + =3D=3D, IC_STATUS_RFF); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_FULL, + =3D=3D, IC_INTR_RX_FULL); + g_assert_cmphex(raw & IC_INTR_RX_OVER, + =3D=3D, IC_INTR_RX_OVER); + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x4b); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_DATA_CMD), + =3D=3D, 0x00); + + for (int i =3D 0; i < 62; i++) { + g_assert_cmphex(qtest_readl(qts, + base + K230_IC_DATA_CMD), + =3D=3D, 0xff); + } + + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 0); + + status =3D qtest_readl(qts, base + K230_IC_STATUS); + g_assert_cmphex(status & IC_STATUS_RFNE, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_RFF, =3D=3D, 0); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_FULL, =3D=3D, 0); + g_assert_cmphex(raw & IC_INTR_RX_OVER, + =3D=3D, IC_INTR_RX_OVER); + + qtest_readl(qts, base + K230_IC_CLR_RX_OVER); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_RX_OVER, =3D=3D, 0); + + k230_i2c_assert_no_abort(qts, base); + qtest_quit(qts); +} + +static void test_restart_disabled_abort(void) +{ + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + uint32_t raw; + uint32_t status; + + k230_i2c_configure_master(qts, base, TMP105_ADDRESS, false); + + qtest_writel(qts, base + K230_IC_DATA_CMD, + TMP105_REG_CONFIG); + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_READ | IC_DATA_CMD_STOP); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + status =3D qtest_readl(qts, base + K230_IC_STATUS); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, + =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(qtest_readl(qts, + base + K230_IC_TX_ABRT_SOURCE), + =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_MST_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_TXFLR), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 0); + + qtest_readl(qts, base + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_echo_data_nack(void) +{ + static const uint8_t accepted_data[] =3D { + 0x7f, + 0x11, + 0x22, + }; + QTestState *qts =3D k230_i2c_init_with_slaves(); + uint64_t base =3D k230_i2c_find_tmp105_bus(qts); + uint32_t raw; + uint32_t source; + uint32_t status; + + k230_i2c_configure_master(qts, base, I2C_ECHO_ADDRESS, true); + + for (size_t i =3D 0; i < G_N_ELEMENTS(accepted_data); i++) { + qtest_writel(qts, base + K230_IC_DATA_CMD, + accepted_data[i]); + } + + /* + * i2c-echo accepts three bytes. The fourth byte is rejected, + * allowing the controller's TXDATA_NOACK path to be tested. + */ + qtest_writel(qts, base + K230_IC_DATA_CMD, + IC_DATA_CMD_STOP | 0x33); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, base + K230_IC_TX_ABRT_SOURCE); + status =3D qtest_readl(qts, base + K230_IC_STATUS); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, + =3D=3D, IC_INTR_TX_ABRT); + g_assert_cmphex(source & IC_ABRT_TXDATA_NOACK, + =3D=3D, IC_ABRT_TXDATA_NOACK); + g_assert_cmphex(source & IC_ABRT_7B_ADDR_NOACK, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(status & IC_STATUS_MST_ACTIVITY, =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_TXFLR), + =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, base + K230_IC_RXFLR), + =3D=3D, 0); + + qtest_readl(qts, base + K230_IC_CLR_TX_ABRT); + + raw =3D qtest_readl(qts, base + K230_IC_RAW_INTR_STAT); + source =3D qtest_readl(qts, base + K230_IC_TX_ABRT_SOURCE); + + g_assert_cmphex(raw & IC_INTR_TX_ABRT, =3D=3D, 0); + g_assert_cmphex(source, =3D=3D, 0); + + qtest_quit(qts); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -857,5 +1432,28 @@ int main(int argc, char **argv) qtest_add_func("/k230-i2c/start-byte-abort", test_start_byte_abort); =20 + if (qtest_has_device("tmp105") && qtest_has_device("i2c-echo")) { + qtest_add_func("/k230-i2c/tmp105-config-read-write", + test_tmp105_config_read_write); + qtest_add_func("/k230-i2c/tmp105-limit-read-write", + test_tmp105_limit_read_write); + qtest_add_func("/k230-i2c/tmp105-direct-read", + test_tmp105_direct_read); + qtest_add_func("/k230-i2c/tmp105-read-write-restart", + test_tmp105_read_write_restart); + qtest_add_func("/k230-i2c/tmp105-same-direction-restart", + test_tmp105_same_direction_restart); + qtest_add_func("/k230-i2c/transfer-status-with-slave", + test_transfer_status_with_slave); + qtest_add_func("/k230-i2c/rx-threshold-with-slave", + test_rx_threshold_with_slave); + qtest_add_func("/k230-i2c/rx-overflow-with-slave", + test_rx_overflow_with_slave); + qtest_add_func("/k230-i2c/restart-disabled-abort", + test_restart_disabled_abort); + qtest_add_func("/k230-i2c/echo-data-nack", + test_echo_data_nack); + } + return g_test_run(); } --=20 2.43.0