Re: [PATCH 3/5] tests/qtest: add K230 I2C controller tests
Daniel Henrique Barboza <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
On 8/7/2026 12:28 PM, Wang Zhongyu wrote: > 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 <[email protected]> > --- Reviewed-by: Daniel Henrique Barboza <[email protected]> > 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 > > 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 <[email protected]> > + * > + * 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] = { > + K230_I2C0_BASE, > + K230_I2C1_BASE, > + K230_I2C2_BASE, > + K230_I2C3_BASE, > + K230_I2C4_BASE, > +}; > + > +static void test_reset_values(void) > +{ > + QTestState *qts = qtest_init("-machine k230"); > + uint32_t status; > + > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), > + ==, 0x7f); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), > + ==, 0x55); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), > + ==, 0x55); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_HS_MADDR), > + ==, 0x1); > + > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_ENABLE), > + ==, 0); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), > + ==, 0); > + > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TXFLR), > + ==, 0); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_RXFLR), > + ==, 0); > + > + status = qtest_readl(qts, K230_I2C0_BASE + K230_IC_STATUS); > + g_assert_cmphex(status, ==, IC_STATUS_TFNF | IC_STATUS_TFE); > + > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT), > + ==, 0); > + > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_COMP_PARAM_1), > + ==, K230_IC_COMP_PARAM_1_VALUE); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_COMP_VERSION), > + ==, K230_IC_COMP_VERSION_VALUE); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_COMP_TYPE), > + ==, K230_IC_COMP_TYPE_VALUE); > + > + qtest_quit(qts); > +} > + > +static void test_all_instances(void) > +{ > + QTestState *qts = qtest_init("-machine k230"); > + > + for (int i = 0; i < K230_I2C_COUNT; i++) { > + g_assert_cmphex(qtest_readl(qts, > + k230_i2c_base[i] + > + K230_IC_COMP_TYPE), > + ==, K230_IC_COMP_TYPE_VALUE); > + } > + > + qtest_quit(qts); > +} > + > +static void test_register_access(void) > +{ > + QTestState *qts = 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), > + ==, 0x7f); > + > + qtest_writel(qts, K230_I2C0_BASE + K230_IC_TAR, UINT32_MAX); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_TAR), > + ==, 0xfff); > + > + qtest_writel(qts, K230_I2C0_BASE + K230_IC_SAR, UINT32_MAX); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_SAR), > + ==, 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), > + ==, 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), > + ==, 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), > + ==, 32); > + > + qtest_quit(qts); > +} > + > +static void test_register_lock_while_enabled(void) > +{ > + QTestState *qts = 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), > + ==, 0x22); > + g_assert_cmphex(qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON), > + ==, 0x7f); > + > + qtest_quit(qts); > +} > + > +static void test_enable_disable(void) > +{ > + QTestState *qts = 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), > + ==, 1); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), > + ==, 1); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, ==, 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), > + ==, 0); > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_ENABLE_STATUS), > + ==, 0); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, ==, 0); > + > + qtest_quit(qts); > +} > + > +static void test_interrupt_mask(void) > +{ > + QTestState *qts = qtest_init("-machine k230"); > + uint32_t raw; > + uint32_t stat; > + > + qtest_writel(qts, K230_I2C0_BASE + K230_IC_ENABLE, 1); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, ==, IC_INTR_TX_EMPTY); > + > + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, 0); > + > + stat = qtest_readl(qts, K230_I2C0_BASE + K230_IC_INTR_STAT); > + g_assert_cmphex(stat, ==, 0); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_TX_EMPTY, ==, IC_INTR_TX_EMPTY); > + > + qtest_writel(qts, K230_I2C0_BASE + K230_IC_INTR_MASK, > + IC_INTR_TX_EMPTY); > + > + stat = qtest_readl(qts, K230_I2C0_BASE + K230_IC_INTR_STAT); > + g_assert_cmphex(stat & IC_INTR_TX_EMPTY, ==, IC_INTR_TX_EMPTY); > + > + qtest_quit(qts); > +} > + > +static void test_rx_underflow(void) > +{ > + QTestState *qts = qtest_init("-machine k230"); > + uint32_t raw; > + > + g_assert_cmphex(qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_DATA_CMD), > + ==, 0); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_RX_UNDER, ==, IC_INTR_RX_UNDER); > + > + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_RX_UNDER); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + g_assert_cmphex(raw & IC_INTR_RX_UNDER, ==, 0); > + > + qtest_quit(qts); > +} > + > +static void test_address_nack(void) > +{ > + QTestState *qts = 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 = qtest_readl(qts, K230_I2C0_BASE + K230_IC_CON); > + con &= ~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 = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + source = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); > + > + g_assert_cmphex(raw & IC_INTR_TX_ABRT, ==, IC_INTR_TX_ABRT); > + g_assert_cmphex(source & IC_ABRT_7B_ADDR_NOACK, > + ==, IC_ABRT_7B_ADDR_NOACK); > + > + qtest_readl(qts, K230_I2C0_BASE + K230_IC_CLR_TX_ABRT); > + > + raw = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_RAW_INTR_STAT); > + source = qtest_readl(qts, > + K230_I2C0_BASE + K230_IC_TX_ABRT_SOURCE); > + > + g_assert_cmphex(raw & IC_INTR_TX_ABRT, ==, 0); > + g_assert_cmphex(source, ==, 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 = ['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'] : []) > > qtests_hexagon = ['boot-serial-test'] >