On Tue, Jul 14, 2026 at 06:22:02PM +0800, Kangjie Huang wrote:
> Cover the 64 documented reset values, writable field storage and
> masking, read-modify-write accesses, the final IO63 register, reserved
> offsets, and system reset.
> 
> Signed-off-by: Kangjie Huang <[email protected]>
> ---
>  tests/qtest/k230-iomux-test.c | 155 ++++++++++++++++++++++++++++++++++
k230-iomux-test.c needs to be added to MAINTAINERS.

>  tests/qtest/meson.build       |   5 +-
>  2 files changed, 159 insertions(+), 1 deletion(-)
>  create mode 100644 tests/qtest/k230-iomux-test.c
> 
> diff --git a/tests/qtest/k230-iomux-test.c b/tests/qtest/k230-iomux-test.c
> new file mode 100644
> index 0000000000..39653cf832
> --- /dev/null
> +++ b/tests/qtest/k230-iomux-test.c
> @@ -0,0 +1,155 @@
> +/*
> + * QTest testcase for Kendryte K230 IOMUX
> + *
> + * Copyright (c) 2026 Kangjie Huang <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides test coverage for the Function IO configuration registers.
> + *
> + * K230 Technical Reference Manual V0.3.1 (2024-11-18):
> + * 
> https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "hw/misc/k230_iomux.h"
> +
> +#define K230_IOMUX_BASE 0x91105000
> +#define K230_IOMUX_IO0  (K230_IOMUX_BASE + 0x00)
> +#define K230_IOMUX_IO1  (K230_IOMUX_BASE + 0x04)
> +#define K230_IOMUX_IO63 (K230_IOMUX_BASE + 0xfc)
> +#define K230_IOMUX_RESERVED_FIRST (K230_IOMUX_BASE + 0x100)
> +#define K230_IOMUX_RESERVED_LAST \
> +    (K230_IOMUX_BASE + K230_IOMUX_MMIO_SIZE - 4)
> +#define K230_IOMUX_IO_SEL_MASK (0x7 << 11)
> +#define K230_IOMUX_IO_SEL(value) ((value) << 11)
> +
> +static const uint32_t k230_iomux_reset_values[K230_IOMUX_NUM_REGS] = {
> +    0x944, 0x944, 0x929, 0x908, 0x888, 0x908, 0x948, 0x890,
> +    0x890, 0x890, 0x910, 0x890, 0x890, 0x8a9, 0xa9e, 0xabf,
> +    0xb9e, 0xb9e, 0xb9e, 0xb9e, 0xb9e, 0xb9e, 0xb9e, 0xb9e,
> +    0xb1e, 0xa90, 0xabf, 0xb9e, 0xb9e, 0xb9e, 0xb9e, 0xb9e,
> +    0xbd0, 0xbd0, 0xbd0, 0xbd0, 0xbd0, 0xbd0, 0x890, 0x910,
> +    0x890, 0x910, 0x890, 0x910, 0x890, 0x910, 0x890, 0x910,
> +    0x890, 0x910, 0x890, 0x910, 0x890, 0x910, 0x89e, 0x89f,
> +    0x99e, 0x99e, 0x99e, 0x99e, 0x890, 0x890, 0x8a9, 0x8a9,
> +};
> +
> +static void test_reset_values(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    for (size_t i = 0; i < G_N_ELEMENTS(k230_iomux_reset_values); i++) {
> +        g_assert_cmphex(qtest_readl(qts, K230_IOMUX_BASE +
> +                                    i * sizeof(uint32_t)), ==,
> +                        k230_iomux_reset_values[i]);
> +    }
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_rw(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_IOMUX_IO0, 0x00001234);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==, 0x00001234);
> +
> +    qtest_writel(qts, K230_IOMUX_IO1, 0x00002abc);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO1), ==, 0x00002abc);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==, 0x00001234);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_write_mask(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_IOMUX_IO0, UINT32_MAX);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==,
> +                    K230_IOMUX_WRITABLE_MASK);
Please use a separate mask in the test. Reusing the implementation’s mask
could let the test pass even if the mask is wrong. A short comment explaining
the mask would also be helpful.

    /* Bits 13:0 are RW; bits 30:14 are reserved; bit 31 (DI) is RO. */
    #define K230_IOMUX_EXPECTED_WRITABLE_MASK 0x00003fff

    [...]

    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==,
                    K230_IOMUX_EXPECTED_WRITABLE_MASK);

Thanks,
Chao
> +    qtest_quit(qts);
> +}
> +
> +static void test_rmw(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +    uint32_t value;
> +
> +    value = qtest_readl(qts, K230_IOMUX_IO0);
> +    value = (value & ~K230_IOMUX_IO_SEL_MASK) | K230_IOMUX_IO_SEL(3);
> +    qtest_writel(qts, K230_IOMUX_IO0, value);
> +
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==,
> +                    (k230_iomux_reset_values[0] &
> +                     ~K230_IOMUX_IO_SEL_MASK) | K230_IOMUX_IO_SEL(3));
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_io63_rw(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_IOMUX_IO63, 0x00000abc);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO63), ==, 0x00000abc);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_reserved_offsets(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_IOMUX_RESERVED_FIRST, 0x00001234);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_RESERVED_FIRST), ==, 0);
> +
> +    qtest_writel(qts, K230_IOMUX_RESERVED_LAST, 0x00002abc);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_RESERVED_LAST), ==, 0);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_reset_after_write(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_IOMUX_IO0, 0x00001234);
> +    qtest_writel(qts, K230_IOMUX_IO1, 0x00002abc);
> +    qtest_writel(qts, K230_IOMUX_IO63, 0x00000abc);
> +
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==, 0x00001234);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO1), ==, 0x00002abc);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO63), ==, 0x00000abc);
> +
> +    qtest_system_reset(qts);
> +
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO0), ==,
> +                    k230_iomux_reset_values[0]);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO1), ==,
> +                    k230_iomux_reset_values[1]);
> +    g_assert_cmphex(qtest_readl(qts, K230_IOMUX_IO63), ==,
> +                    k230_iomux_reset_values[63]);
> +
> +    qtest_quit(qts);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    g_test_init(&argc, &argv, NULL);
> +
> +    qtest_add_func("/k230-iomux/reset", test_reset_values);
> +    qtest_add_func("/k230-iomux/rw", test_rw);
> +    qtest_add_func("/k230-iomux/write-mask", test_write_mask);
> +    qtest_add_func("/k230-iomux/rmw", test_rmw);
> +    qtest_add_func("/k230-iomux/io63-rw", test_io63_rw);
> +    qtest_add_func("/k230-iomux/reserved-offsets", test_reserved_offsets);
> +    qtest_add_func("/k230-iomux/reset-after-write", test_reset_after_write);
> +
> +    return g_test_run();
> +}
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 56ff860e21..cb8001ecbf 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -297,7 +297,10 @@ 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-iomux-test',
> +  ] : [])
>  
>  qtests_hexagon = ['boot-serial-test']
>  
> -- 
> 2.43.0
> 

Reply via email to