tests/qtest: Add K230 DDR controller tests
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. Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Suggested-by: Chao Liu <chao.liu@processmission.com> Signed-off-by: Junze Cao <caojunze424@gmail.com> Message-ID: <20260807-k230-ddr-v2-v2-3-c531308ae819@gmail.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Junze Cao committed
Aug 7, 2026 at 18:21 UTC
98911b604bcd881276202c4e2dd51c68b69ed4dd
3 files changed
+229
-1
MAINTAINERS
+1
@@ -1851,6 +1851,7 @@ F: include/hw/misc/k230_ddr.h
1851
F: include/hw/riscv/k230.h
1852
F: include/hw/watchdog/k230_wdt.h
1853
F: tests/functional/riscv64/test_k230.py
1854
+F: tests/qtest/k230-ddr-test.c
1855
F: tests/qtest/k230-wdt-test.c
1856
1857
RX Machines
tests/qtest/k230-ddr-test.c
new
+226
@@ -0,0 +1,226 @@
1
+/*
2
+ * QTest testcase for the K230 DDR controller and PHY
3
+ *
4
+ * Exercises register access, reset, PHY ownership, training mailbox, and DFI
5
+ * initialization.
6
+ *
7
+ * Copyright (c) 2026 Junze Cao <caojunze424@gmail.com>
8
+ *
9
+ * SPDX-License-Identifier: GPL-2.0-or-later
10
+ */
11
+
12
+#include "qemu/osdep.h"
13
+#include "libqtest.h"
14
+
15
+#define K230_DDRC_BASE UINT64_C(0x98000000)
16
+#define K230_DDR_PHY_BASE UINT64_C(0x9a000000)
17
+
18
+#define K230_DDRC_MSTR 0x000
19
+#define K230_DDRC_STAT 0x004
20
+#define K230_DDRC_DRAMTMG4 0x110
21
+#define K230_DDRC_DFIMISC 0x1b0
22
+#define K230_DDRC_DFISTAT 0x1bc
23
+#define K230_DDRC_SWCTL 0x320
24
+#define K230_DDRC_SWSTAT 0x324
25
+
26
+#define K230_DDRC_STAT_OPERATING_MODE_MASK 0x7
27
+#define K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK 0x1
28
+
29
+#define K230_DDR_PHY_CSR(index) \
30
+ (K230_DDR_PHY_BASE + (uint64_t)(index) * sizeof(uint32_t))
31
+
32
+#define K230_DDR_PHY_ATX_IMPEDANCE 0x00043
33
+#define K230_DDR_PHY_TX_IMPEDANCE_CTRL1 0x10049
34
+#define K230_DDR_PHY_VREF_IN_GLOBAL 0x200b2
35
+#define K230_DDR_PHY_MICRO_CONT_MUX_SEL 0xd0000
36
+#define K230_DDR_PHY_TRAINING_STATUS 0xd0004
37
+#define K230_DDR_PHY_TRAINING_ACK 0xd0031
38
+#define K230_DDR_PHY_TRAINING_MESSAGE 0xd0032
39
+#define K230_DDR_PHY_TRAINING_TRIGGER 0xd0099
40
+
41
+static void complete_phy_training(QTestState *qts)
42
+{
43
+ qtest_writel(qts,
44
+ K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL), 1);
45
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 9);
46
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 1);
47
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 0);
48
+}
49
+
50
+static void test_reset_and_register_access(void)
51
+{
52
+ QTestState *qts = qtest_init("-machine k230");
53
+
54
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
55
+ ==, 0x01040000);
56
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT),
57
+ ==, 0x00000000);
58
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4),
59
+ ==, 0x05040405);
60
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC),
61
+ ==, 0x00000001);
62
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWCTL),
63
+ ==, 0x00000001);
64
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
65
+ ==, 0x00000001);
66
+
67
+ g_assert_cmphex(qtest_readl(qts,
68
+ K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE)),
69
+ ==, 0x03ff);
70
+ g_assert_cmphex(qtest_readl(qts,
71
+ K230_DDR_PHY_CSR(K230_DDR_PHY_TX_IMPEDANCE_CTRL1)),
72
+ ==, 0x0fff);
73
+ g_assert_cmphex(qtest_readl(qts,
74
+ K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
75
+ ==, 0x0200);
76
+
77
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_MSTR, 0x01040008);
78
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
79
+ ==, 0x01040008);
80
+
81
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_STAT, 0xffffffff);
82
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT),
83
+ ==, 0x00000000);
84
+
85
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL),
86
+ 0xffffffff);
87
+ g_assert_cmphex(qtest_readl(qts,
88
+ K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
89
+ ==, 0x7fff);
90
+
91
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4, 0);
92
+
93
+ qtest_system_reset(qts);
94
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR),
95
+ ==, 0x01040000);
96
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4),
97
+ ==, 0x05040405);
98
+ g_assert_cmphex(qtest_readl(qts,
99
+ K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)),
100
+ ==, 0x0200);
101
+
102
+ qtest_quit(qts);
103
+}
104
+
105
+static void test_software_update_handshake(void)
106
+{
107
+ QTestState *qts = qtest_init("-machine k230");
108
+
109
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 0);
110
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
111
+ ==, 0);
112
+
113
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 1);
114
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
115
+ ==, 1);
116
+
117
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT, 0);
118
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT),
119
+ ==, 1);
120
+
121
+ qtest_quit(qts);
122
+}
123
+
124
+static void test_phy_ownership(void)
125
+{
126
+ QTestState *qts = qtest_init("-machine k230");
127
+ uint64_t atx = K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE);
128
+ uint64_t mux = K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL);
129
+
130
+ qtest_writel(qts, atx, 0x155);
131
+ g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155);
132
+
133
+ qtest_writel(qts, mux, 1);
134
+ qtest_writel(qts, atx, 0x2aa);
135
+ g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155);
136
+
137
+ qtest_writel(qts, mux, 0);
138
+ qtest_writel(qts, atx, 0x2aa);
139
+ g_assert_cmphex(qtest_readl(qts, atx), ==, 0x2aa);
140
+
141
+ qtest_quit(qts);
142
+}
143
+
144
+static void test_dfi_prerequisites(void)
145
+{
146
+ QTestState *qts = qtest_init("-machine k230");
147
+
148
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
149
+
150
+ g_assert_cmphex(qtest_readl(qts,
151
+ K230_DDRC_BASE + K230_DDRC_DFISTAT) &
152
+ K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK,
153
+ ==, 0);
154
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) &
155
+ K230_DDRC_STAT_OPERATING_MODE_MASK,
156
+ ==, 0);
157
+
158
+ qtest_quit(qts);
159
+}
160
+
161
+static void test_dfi_complete_enable(void)
162
+{
163
+ QTestState *qts = qtest_init("-machine k230");
164
+
165
+ complete_phy_training(qts);
166
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
167
+
168
+ g_assert_cmphex(qtest_readl(qts,
169
+ K230_DDRC_BASE + K230_DDRC_DFISTAT) &
170
+ K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK,
171
+ ==, 1);
172
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) &
173
+ K230_DDRC_STAT_OPERATING_MODE_MASK,
174
+ ==, 0);
175
+
176
+ qtest_quit(qts);
177
+}
178
+
179
+static void test_training_and_dfi_handshake(void)
180
+{
181
+ QTestState *qts = qtest_init("-machine k230");
182
+
183
+ complete_phy_training(qts);
184
+
185
+ g_assert_cmphex(qtest_readl(qts,
186
+ K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)),
187
+ ==, 0);
188
+ g_assert_cmphex(qtest_readl(qts,
189
+ K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_MESSAGE)),
190
+ ==, 0x07);
191
+
192
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 0);
193
+ g_assert_cmphex(qtest_readl(qts,
194
+ K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)),
195
+ ==, 1);
196
+ qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 1);
197
+
198
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20);
199
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFISTAT),
200
+ ==, 1);
201
+
202
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0);
203
+ qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 1);
204
+ g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) & 0x7,
205
+ ==, 1);
206
+
207
+ qtest_quit(qts);
208
+}
209
+
210
+int main(int argc, char **argv)
211
+{
212
+ g_test_init(&argc, &argv, NULL);
213
+
214
+ qtest_add_func("/k230-ddr/reset-and-register-access",
215
+ test_reset_and_register_access);
216
+ qtest_add_func("/k230-ddr/software-update-handshake",
217
+ test_software_update_handshake);
218
+ qtest_add_func("/k230-ddr/phy-ownership", test_phy_ownership);
219
+ qtest_add_func("/k230-ddr/dfi-prerequisites", test_dfi_prerequisites);
220
+ qtest_add_func("/k230-ddr/dfi-complete-enable",
221
+ test_dfi_complete_enable);
222
+ qtest_add_func("/k230-ddr/training-and-dfi-handshake",
223
+ test_training_and_dfi_handshake);
224
+
225
+ return g_test_run();
226
+}
tests/qtest/meson.build
+2
-1
@@ -299,7 +299,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
299
(config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
300
config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
301
['iommu-riscv-test'] : []) + \
302
- (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
302
+ (config_all_devices.has_key('CONFIG_K230') ?
303
+ ['k230-ddr-test', 'k230-wdt-test'] : [])
304
305
qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test']
306