On Thu, Jul 16, 2026 at 09:24:23PM +0800, Junze Cao wrote:
> Add qtests for DDRC and PHY reset values, register access policy, the
> software-update handshake, and PHY register ownership.
> 
> Exercise PHY training and mailbox acknowledgement through the DFI
> initialization sequence. Include negative coverage to ensure DFI cannot
> complete before PHY training or enter Normal mode before completion is
> enabled.
> 
> Signed-off-by: Junze Cao <[email protected]>
Suggested-by: Chao Liu <[email protected]>

Thanks,
Chao

> ---
>  MAINTAINERS                 |   1 +
>  tests/qtest/k230-ddr-test.c | 226 ++++++++++++++++++++++++++++++++++++
>  tests/qtest/meson.build     |   3 +-
>  3 files changed, 229 insertions(+), 1 deletion(-)
>  create mode 100644 tests/qtest/k230-ddr-test.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1cb3ef6c02..ace7def55e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1833,6 +1833,7 @@ F: include/hw/misc/k230_ddr.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-ddr-test.c
>  F: tests/qtest/k230-wdt-test.c
>  
>  RX Machines
> diff --git a/tests/qtest/k230-ddr-test.c b/tests/qtest/k230-ddr-test.c
> new file mode 100644
> index 0000000000..72362929bc
> --- /dev/null
> +++ b/tests/qtest/k230-ddr-test.c
> @@ -0,0 +1,226 @@
> +/*
> + * QTest testcase for the K230 DDR controller and PHY
> + *
> + * Exercises register access, reset, PHY ownership, training mailbox, and DFI
> + * initialization.
> + *
> + * Copyright (c) 2026 Junze Cao <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +
> +#define K230_DDRC_BASE    UINT64_C(0x98000000)
> +#define K230_DDR_PHY_BASE UINT64_C(0x9a000000)
> +
> +#define K230_DDRC_MSTR    0x000
> +#define K230_DDRC_STAT    0x004
> +#define K230_DDRC_DRAMTMG4 0x110
> +#define K230_DDRC_DFIMISC 0x1b0
> +#define K230_DDRC_DFISTAT 0x1bc
> +#define K230_DDRC_SWCTL   0x320
> +#define K230_DDRC_SWSTAT  0x324
> +
> +#define K230_DDRC_STAT_OPERATING_MODE_MASK          0x7
> +#define K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK    0x1
> +
> +#define K230_DDR_PHY_CSR(index) \
> +    (K230_DDR_PHY_BASE + (uint64_t)(index) * sizeof(uint32_t))
> +
> +#define K230_DDR_PHY_ATX_IMPEDANCE      0x00043
> +#define K230_DDR_PHY_TX_IMPEDANCE_CTRL1 0x10049
> +#define K230_DDR_PHY_VREF_IN_GLOBAL     0x200b2
> +#define K230_DDR_PHY_MICRO_CONT_MUX_SEL 0xd0000
> +#define K230_DDR_PHY_TRAINING_STATUS    0xd0004
> +#define K230_DDR_PHY_TRAINING_ACK       0xd0031
> +#define K230_DDR_PHY_TRAINING_MESSAGE   0xd0032
> +#define K230_DDR_PHY_TRAINING_TRIGGER   0xd0099
> +
> +static void complete_phy_training(QTestState *qts)
> +{
> +    qtest_writel(qts,
> +                 K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL), 1);
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 9);
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 1);
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 0);
> +}
> +
> +static void test_reset_and_register_access(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
> +                    ==, 0x01040000);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT),
> +                    ==, 0x00000000);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4),
> +                    ==, 0x05040405);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC),
> +                    ==, 0x00000001);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWCTL),
> +                    ==, 0x00000001);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
> +                    ==, 0x00000001);
> +
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE)),
> +                    ==, 0x03ff);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_TX_IMPEDANCE_CTRL1)),
> +                    ==, 0x0fff);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
> +                    ==, 0x0200);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_MSTR, 0x01040008);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
> +                    ==, 0x01040008);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_STAT, 0xffffffff);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT),
> +                    ==, 0x00000000);
> +
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL),
> +                 0xffffffff);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
> +                    ==, 0x7fff);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4, 0);
> +
> +    qtest_system_reset(qts);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
> +                    ==, 0x01040000);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4),
> +                    ==, 0x05040405);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
> +                    ==, 0x0200);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_software_update_handshake(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 0);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
> +                    ==, 0);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 1);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
> +                    ==, 1);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT, 0);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
> +                    ==, 1);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_phy_ownership(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +    uint64_t atx = K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE);
> +    uint64_t mux = K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL);
> +
> +    qtest_writel(qts, atx, 0x155);
> +    g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155);
> +
> +    qtest_writel(qts, mux, 1);
> +    qtest_writel(qts, atx, 0x2aa);
> +    g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155);
> +
> +    qtest_writel(qts, mux, 0);
> +    qtest_writel(qts, atx, 0x2aa);
> +    g_assert_cmphex(qtest_readl(qts, atx), ==, 0x2aa);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_dfi_prerequisites(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
> +
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDRC_BASE + K230_DDRC_DFISTAT) &
> +                    K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK,
> +                    ==, 0);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) &
> +                    K230_DDRC_STAT_OPERATING_MODE_MASK,
> +                    ==, 0);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_dfi_complete_enable(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    complete_phy_training(qts);
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
> +
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDRC_BASE + K230_DDRC_DFISTAT) &
> +                    K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK,
> +                    ==, 1);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) &
> +                    K230_DDRC_STAT_OPERATING_MODE_MASK,
> +                    ==, 0);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_training_and_dfi_handshake(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    complete_phy_training(qts);
> +
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)),
> +                    ==, 0);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_MESSAGE)),
> +                    ==, 0x07);
> +
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 0);
> +    g_assert_cmphex(qtest_readl(qts,
> +                    K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)),
> +                    ==, 1);
> +    qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 1);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFISTAT),
> +                    ==, 1);
> +
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0);
> +    qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 1);
> +    g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) & 0x7,
> +                    ==, 1);
> +
> +    qtest_quit(qts);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    g_test_init(&argc, &argv, NULL);
> +
> +    qtest_add_func("/k230-ddr/reset-and-register-access",
> +                   test_reset_and_register_access);
> +    qtest_add_func("/k230-ddr/software-update-handshake",
> +                   test_software_update_handshake);
> +    qtest_add_func("/k230-ddr/phy-ownership", test_phy_ownership);
> +    qtest_add_func("/k230-ddr/dfi-prerequisites", test_dfi_prerequisites);
> +    qtest_add_func("/k230-ddr/dfi-complete-enable",
> +                   test_dfi_complete_enable);
> +    qtest_add_func("/k230-ddr/training-and-dfi-handshake",
> +                   test_training_and_dfi_handshake);
> +
> +    return g_test_run();
> +}
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 56ff860e21..dc110f72c8 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -297,7 +297,8 @@ 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-ddr-test', 'k230-wdt-test'] : [])
>  
>  qtests_hexagon = ['boot-serial-test']
>  
> -- 
> 2.53.0
> 

Reply via email to