[PATCH 3/5] tests/qtest: add K230 I2C controller tests
Wang Zhongyu <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
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]> --- 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'] -- 2.43.0