master
c 385 lines 13.4 KB
Raw
1 /*
2 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 *
5 * QTest testcase for the QCT QTimer
6 */
7
8 #include "qemu/osdep.h"
9 #include "libqtest-single.h"
10 #include "hw/hexagon/hexagon.h"
11 #include "qemu/bitops.h"
12
13 #include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
14 #include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
15
16 #define QTIMER_DEFAULT_FREQ_HZ 19200000ULL
17
18 #define QCT_QTIMER_CNTPCT_LO (0x000)
19 #define QCT_QTIMER_CNTPCT_HI (0x004)
20 #define QCT_QTIMER_CNT_FREQ (0x010)
21 #define QCT_QTIMER_CNTP_CVAL_LO (0x020)
22 #define QCT_QTIMER_CNTP_TVAL (0x028)
23 #define QCT_QTIMER_CNTP_CTL (0x02c)
24 #define QCT_QTIMER_CNTP_CTL_ENABLE (1 << 0)
25
26 #define QTIMER_FRAME_STRIDE 0x1000
27 /* Frames instantiated by hex-subsys, and the L2VIC input frame 0 drives. */
28 #define QTIMER_NR_FRAMES 3
29 #define QTIMER_L2VIC_IRQ_BASE 2
30
31 #define QCT_QTIMER_AC_CNTFRQ (0x000)
32 #define QCT_QTIMER_AC_CNTSR (0x004)
33 #define QCT_QTIMER_AC_CNTTID_0 (0x08)
34 #define QCT_QTIMER_AC_CNTACR_START (0x40)
35 #define QCT_QTIMER_AC_CNTACR_ALL (0x3f)
36 #define QCT_QTIMER_AC_CNTACR_RWPT (1 << 5) /* R/W of CNTP_* regs */
37 #define QCT_QTIMER_AC_CNTACR_RFRQ (1 << 2) /* R/W of CNTFRQ register */
38 #define QCT_QTIMER_AC_CNTACR_RPCT (1 << 0) /* R/W of CNTPCT register */
39
40 static uint64_t qtimer_view_base;
41 static uint64_t qtimer_ac_base;
42
43 #define TIMER_TEST_OFFSET 1000
44 /* TIMER_TEST_OFFSET ticks expressed in nanoseconds of QEMU_CLOCK_VIRTUAL */
45 #define TIMER_TEST_NS \
46 ((TIMER_TEST_OFFSET * 1000000000ULL) / QTIMER_DEFAULT_FREQ_HZ)
47
48 static uint32_t qtimer_read32(uint64_t base, uint32_t offset)
49 {
50 return readl(base + offset);
51 }
52
53 static void qtimer_write32(uint64_t base, uint32_t offset, uint32_t value)
54 {
55 writel(base + offset, value);
56 }
57
58 static uint64_t qtimer_read64(uint64_t base, uint32_t offset)
59 {
60 uint32_t lo = qtimer_read32(base, offset);
61 uint32_t hi = qtimer_read32(base, offset + 4);
62
63 return ((uint64_t)hi << 32) | lo;
64 }
65
66 static void qtimer_write64(uint64_t base, uint32_t offset, uint64_t value)
67 {
68 qtimer_write32(base, offset, extract64(value, 0, 32));
69 qtimer_write32(base, offset + 4, extract64(value, 32, 32));
70 }
71
72 static void test_qtimer_basic_access(void)
73 {
74 uint32_t val;
75
76 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ);
77 g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ);
78 }
79
80 static void test_qtimer_multiple_frames(void)
81 {
82 uint32_t val;
83 uint64_t frame0_base = qtimer_view_base;
84 uint64_t frame1_base = qtimer_view_base + 0x1000;
85
86 val = qtimer_read32(frame0_base, QCT_QTIMER_CNT_FREQ);
87 g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ);
88
89 val = qtimer_read32(frame1_base, QCT_QTIMER_CNT_FREQ);
90 g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ);
91 }
92
93 static void test_qtimer_register_reads(void)
94 {
95 qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ);
96 qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
97 qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
98 qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
99 qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL);
100 }
101
102 static void test_qtimer_control_registers(void)
103 {
104 uint32_t ctl_val;
105 uint64_t cval_before, cval_after;
106
107 cval_before = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
108
109 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL, 1000);
110
111 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1);
112 ctl_val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
113 g_assert_cmpuint(ctl_val & 1, ==, 1);
114
115 /* CVAL should be greater than before since we set TVAL */
116 cval_after = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
117 g_assert_cmpuint(cval_after, >, cval_before);
118
119 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 0);
120 ctl_val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
121 g_assert_cmpuint(ctl_val & 1, ==, 0);
122 }
123
124 static void test_qtimer_cval_access(void)
125 {
126 uint64_t current_time, test_cval, read_cval;
127
128 current_time = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
129 test_cval = current_time + 10000;
130
131 qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, test_cval);
132 read_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
133 g_assert_cmpuint(read_cval, ==, test_cval);
134 }
135
136 static void test_qtimer_counter_progression(void)
137 {
138 uint32_t freq;
139 uint64_t count1, count2;
140
141 /*
142 * In qtest mode the virtual clock does not advance on its own, so
143 * reading the counter twice must give the same value.
144 */
145 count1 = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
146 count2 = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
147 g_assert_cmpuint(count2, ==, count1);
148
149 freq = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ);
150 g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ);
151 }
152
153 static void test_qtimer_timer_behavior(void)
154 {
155 uint64_t current_count, target_count, read_cval, new_count;
156 uint64_t ctl_val, count_after_disable;
157
158 current_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
159
160 target_count = current_count + TIMER_TEST_OFFSET;
161 qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, target_count);
162
163 read_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
164 g_assert_cmpuint(read_cval, ==, target_count);
165
166 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1);
167
168 ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
169 /* EN set, IMASK clear, ISTAT not yet pending */
170 g_assert_cmpuint(ctl_val, ==, 0x1);
171
172 /* Step forward but not past the target */
173 qtest_clock_step(global_qtest, TIMER_TEST_NS / 2);
174 new_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
175 g_assert_cmpuint(new_count, >=, current_count);
176
177 /* Step past the target */
178 qtest_clock_step(global_qtest, TIMER_TEST_NS);
179 new_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
180 g_assert_cmpuint(new_count, >=, target_count);
181
182 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 0);
183
184 ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
185 /* EN cleared, ISTAT set since new_count >= target_count */
186 g_assert_cmpuint(ctl_val, ==, 0x4);
187
188 /*
189 * CNTPCT runs independently of CNTP_CTL.EN: only the compare/IRQ
190 * logic is gated by EN, so the counter must keep advancing.
191 */
192 qtest_clock_step(global_qtest, TIMER_TEST_NS / 2);
193 count_after_disable = qtimer_read64(qtimer_view_base,
194 QCT_QTIMER_CNTPCT_LO);
195 g_assert_cmpuint(count_after_disable, >, new_count);
196
197 /* ISTAT remains set while CNTPCT >= CVAL, even with EN=0 */
198 ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
199 g_assert_cmpuint(ctl_val, ==, 0x4);
200 }
201
202 /* Test the access-control region: CNTFRQ, CNTSR, CNTTID_0, CNTACR frame 0 */
203 static void test_qtimer_ac_region(void)
204 {
205 uint32_t freq, sr, tid0, acr0;
206
207 freq = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ);
208 g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ);
209
210 /* A write of 0 to CNTFRQ must be ignored (freq-hz must stay nonzero). */
211 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ, 0);
212 freq = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ);
213 g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ);
214
215 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTSR, 0x3);
216 sr = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTSR);
217 g_assert_cmpuint(sr, ==, 0x3);
218
219 tid0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTTID_0);
220 g_assert_cmpuint(tid0, ==, 0x111);
221
222 /* CNTACR for frame 0 defaults to full read/write permissions. */
223 acr0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START);
224 g_assert_cmpuint(acr0, !=, 0);
225
226 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, 0);
227 acr0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START);
228 g_assert_cmpuint(acr0, ==, 0);
229
230 /* Restore full permissions so later view-region tests keep working. */
231 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START,
232 QCT_QTIMER_AC_CNTACR_ALL);
233 }
234
235 static void test_qtimer_access_denied(void)
236 {
237 uint32_t acr_all = QCT_QTIMER_AC_CNTACR_ALL;
238 uint64_t cval, saved_cval;
239 uint32_t val;
240
241 /* Park CVAL at a known nonzero value while access is still permitted. */
242 saved_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO) + 10000;
243 qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, saved_cval);
244 g_assert_cmpuint(qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO),
245 ==, saved_cval);
246
247 /* Clearing RFRQ denies CNTFRQ reads. */
248 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START,
249 acr_all & ~QCT_QTIMER_AC_CNTACR_RFRQ);
250 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ);
251 g_assert_cmpuint(val, ==, 0);
252
253 /* Clearing RPCT denies CNTPCT reads, both halves. */
254 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START,
255 acr_all & ~QCT_QTIMER_AC_CNTACR_RPCT);
256 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTPCT_LO);
257 g_assert_cmpuint(val, ==, 0);
258 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTPCT_HI);
259 g_assert_cmpuint(val, ==, 0);
260
261 /*
262 * Clearing RWPT denies the whole CNTP_* set: CVAL/TVAL/CTL reads all
263 * read back 0 even though CVAL holds saved_cval.
264 */
265 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START,
266 acr_all & ~QCT_QTIMER_AC_CNTACR_RWPT);
267 cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
268 g_assert_cmpuint(cval, ==, 0);
269 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL);
270 g_assert_cmpuint(val, ==, 0);
271 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
272 g_assert_cmpuint(val, ==, 0);
273
274 /* Denied writes must be dropped rather than applied. */
275 qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, 0x1234);
276 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL, 0x5678);
277 qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1);
278
279 /* Restoring RWPT reveals that CVAL still holds the pre-denial value. */
280 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, acr_all);
281 cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO);
282 g_assert_cmpuint(cval, ==, saved_cval);
283 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL);
284 g_assert_cmpuint(val & 1, ==, 0);
285
286 /* CNTFRQ and CNTPCT work again once permissions are back. */
287 val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ);
288 g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ);
289
290 /*
291 * An unimplemented offset in the view region is also an access error,
292 * and reads back as 0.
293 */
294 val = qtimer_read32(qtimer_view_base, 0x100);
295 g_assert_cmpuint(val, ==, 0);
296
297 /* Leave the frame with full permissions for any later test. */
298 qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, acr_all);
299 }
300
301 static void test_qtimer_frame_irq_routing(void)
302 {
303 unsigned int frame, other;
304 uint64_t frame_base;
305
306 qtest_irq_intercept_in(global_qtest, "/machine/l2vic");
307
308 for (frame = 0; frame < QTIMER_NR_FRAMES; frame++) {
309 frame_base = qtimer_view_base + frame * QTIMER_FRAME_STRIDE;
310
311 qtimer_write32(frame_base, QCT_QTIMER_CNTP_TVAL, TIMER_TEST_OFFSET);
312 qtimer_write32(frame_base, QCT_QTIMER_CNTP_CTL,
313 QCT_QTIMER_CNTP_CTL_ENABLE);
314 g_assert_false(qtest_get_irq(global_qtest,
315 QTIMER_L2VIC_IRQ_BASE + frame));
316
317 /* Step past the deadline so the frame raises its interrupt. */
318 qtest_clock_step(global_qtest, TIMER_TEST_NS * 2);
319 g_assert_true(qtest_get_irq(global_qtest,
320 QTIMER_L2VIC_IRQ_BASE + frame));
321
322 /* No other frame's line may be disturbed. */
323 for (other = 0; other < QTIMER_NR_FRAMES; other++) {
324 if (other != frame) {
325 g_assert_false(qtest_get_irq(global_qtest,
326 QTIMER_L2VIC_IRQ_BASE + other));
327 }
328 }
329
330 /* Clearing EN drops the interrupt, leaving a clean slate. */
331 qtimer_write32(frame_base, QCT_QTIMER_CNTP_CTL, 0);
332 g_assert_false(qtest_get_irq(global_qtest,
333 QTIMER_L2VIC_IRQ_BASE + frame));
334 }
335 }
336
337 typedef struct {
338 const char *machine;
339 const struct hexagon_machine_config *cfg;
340 } QtimerMachineCfg;
341
342 static const QtimerMachineCfg qtimer_machines[] = {
343 { "virt", &v68n_1024 },
344 { "V66G_1024", &v66g_1024 },
345 };
346
347 static void test_qtimer_on_machine(gconstpointer data)
348 {
349 const QtimerMachineCfg *mc = data;
350 g_autofree char *args = g_strdup_printf(
351 "-machine %s -global qct-qtimer.freq-scale=1", mc->machine);
352
353 qtimer_view_base = mc->cfg->qtmr_region;
354 qtimer_ac_base = mc->cfg->csr_base;
355
356 qtest_start(args);
357
358 test_qtimer_basic_access();
359 test_qtimer_multiple_frames();
360 test_qtimer_register_reads();
361 test_qtimer_control_registers();
362 test_qtimer_cval_access();
363 test_qtimer_counter_progression();
364 test_qtimer_timer_behavior();
365 test_qtimer_ac_region();
366 test_qtimer_access_denied();
367 test_qtimer_frame_irq_routing();
368
369 qtest_end();
370 }
371
372 int main(int argc, char **argv)
373 {
374 size_t i;
375
376 g_test_init(&argc, &argv, NULL);
377
378 for (i = 0; i < ARRAY_SIZE(qtimer_machines); i++) {
379 g_autofree char *path = g_strdup_printf("/qct-qtimer/%s/all-tests",
380 qtimer_machines[i].machine);
381 qtest_add_data_func(path, &qtimer_machines[i], test_qtimer_on_machine);
382 }
383
384 return g_test_run();
385 }