master
c 249 lines 8.01 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 L2VIC Interrupt Controller
6 */
7
8 #include "qemu/osdep.h"
9 #include "libqtest-single.h"
10 #include "hw/hexagon/hexagon.h"
11
12 #include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
13 #include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
14
15 /* L2VIC register offsets exercised by this test */
16 #define L2VIC_INT_ENABLEn 0x100 /* Read/Write */
17 #define L2VIC_INT_ENABLE_CLEARn 0x180 /* Write */
18 #define L2VIC_INT_ENABLE_SETn 0x200 /* Write */
19 #define L2VIC_INT_TYPEn 0x280 /* Read/Write */
20 #define L2VIC_INT_STATUSn 0x380 /* Read */
21 #define L2VIC_INT_CLEARn 0x400 /* Write */
22 #define L2VIC_SOFT_INTn 0x480 /* Write */
23 #define L2VIC_INT_PENDINGn 0x500 /* Read */
24 #define L2VIC_INT_GRPn_0 0x600 /* Read/Write */
25 #define L2VIC_INT_GRPn_1 0x680 /* Read/Write */
26 #define L2VIC_INT_GRPn_2 0x700 /* Read/Write */
27 #define L2VIC_INT_GRPn_3 0x780 /* Read/Write */
28
29 /*
30 * VID group readback: records which irq last fired through each VID
31 * group. Outputs themselves are momentary pulses (see l2vic_update()),
32 * so these registers -- not the qtest IRQ level snapshot -- are how the
33 * test observes VID steering.
34 */
35 #define L2VIC_VID_GRP_0 0x0
36 #define L2VIC_VID_GRP_1 0x4
37 #define L2VIC_VID_GRP_2 0x8
38 #define L2VIC_VID_GRP_3 0xC
39
40 typedef struct {
41 const char *machine;
42 const struct hexagon_machine_config *cfg;
43 } L2VICMachineCfg;
44
45 static const L2VICMachineCfg l2vic_machines[] = {
46 { "virt", &v68n_1024 },
47 { "V66G_1024", &v66g_1024 },
48 };
49
50 static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
51 {
52 return readl(base + offset);
53 }
54
55 static void l2vic_write32(uint64_t base, uint32_t offset, uint32_t value)
56 {
57 writel(base + offset, value);
58 }
59
60 static void test_l2vic_register_access(uint64_t base)
61 {
62 uint32_t val;
63
64 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x1);
65 val = l2vic_read32(base, L2VIC_INT_ENABLEn);
66 g_assert_cmpuint(val & 0x1, ==, 0x1);
67
68 l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0x1);
69 val = l2vic_read32(base, L2VIC_INT_ENABLEn);
70 g_assert_cmpuint(val & 0x1, ==, 0x0);
71 }
72
73 static void test_l2vic_interrupt_enable(uint64_t base)
74 {
75 uint32_t val;
76
77 val = l2vic_read32(base, L2VIC_INT_ENABLEn);
78 g_assert_cmpuint(val, ==, 0);
79
80 /* Enable IRQ 0 and 2 */
81 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x5);
82 val = l2vic_read32(base, L2VIC_INT_ENABLEn);
83 g_assert_cmpuint(val & 0x5, ==, 0x5);
84
85 /* Disable IRQ 0, leaving IRQ 2 enabled */
86 l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0x1);
87 val = l2vic_read32(base, L2VIC_INT_ENABLEn);
88 g_assert_cmpuint(val & 0x1, ==, 0x0);
89 g_assert_cmpuint(val & 0x4, ==, 0x4);
90 }
91
92 static void test_l2vic_basic_functionality(uint64_t base)
93 {
94 l2vic_read32(base, L2VIC_INT_ENABLEn);
95 l2vic_read32(base, L2VIC_INT_PENDINGn);
96 l2vic_read32(base, L2VIC_INT_STATUSn);
97 l2vic_read32(base, L2VIC_INT_TYPEn);
98
99 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0);
100 l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0);
101 }
102
103 /*
104 * IRQs 0-7 pack their group-enable/VID-select nibbles into
105 * L2VIC_INT_GRPn_0 (int_group_n[0]), 4 bits per irq: bit 3 enables
106 * VID steering, bits 0-2 select the VID group (0-3), which pulses
107 * output line vid+2.
108 */
109 static void l2vic_set_vid_group(uint64_t base, int irq, int vid)
110 {
111 uint32_t val = l2vic_read32(base, L2VIC_INT_GRPn_0);
112 uint32_t nibble = 0x8 | (vid & 0x7);
113
114 val &= ~(0xFu << (irq * 4));
115 val |= nibble << (irq * 4);
116 l2vic_write32(base, L2VIC_INT_GRPn_0, val);
117 }
118
119 static void test_l2vic_irq_outputs(uint64_t base)
120 {
121 uint32_t val;
122
123 l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0xFFFFFFFF);
124 l2vic_write32(base, L2VIC_INT_CLEARn, 0xFFFFFFFF);
125 l2vic_write32(base, L2VIC_INT_TYPEn, 0);
126 l2vic_write32(base, L2VIC_INT_GRPn_0, 0);
127
128 /* Group 0 / IRQ2: soft interrupts require edge-triggered config */
129 l2vic_write32(base, L2VIC_INT_TYPEn, 0x1);
130 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x1);
131 l2vic_write32(base, L2VIC_SOFT_INTn, 0x1);
132
133 val = l2vic_read32(base, L2VIC_INT_STATUSn);
134 g_assert_cmpuint(val & 0x1, ==, 0x1);
135 /* Default VID group (0) records the delivering irq, output line 2 */
136 g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_0), ==, 0);
137
138 l2vic_write32(base, L2VIC_INT_CLEARn, 0x1);
139 val = l2vic_read32(base, L2VIC_INT_STATUSn);
140 g_assert_cmpuint(val & 0x1, ==, 0x0);
141
142 /* IRQ1 steered to VID group 1 -> output line 3 */
143 l2vic_write32(base, L2VIC_INT_TYPEn, 0x2);
144 l2vic_set_vid_group(base, 1, 1);
145 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x2);
146 l2vic_write32(base, L2VIC_SOFT_INTn, 0x2);
147
148 val = l2vic_read32(base, L2VIC_INT_STATUSn);
149 g_assert_cmpuint(val & 0x2, ==, 0x2);
150 g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_1), ==, 1);
151
152 l2vic_write32(base, L2VIC_INT_CLEARn, 0x2);
153
154 /* IRQ4 steered to VID group 2 -> output line 4 */
155 l2vic_write32(base, L2VIC_INT_TYPEn, 0x10);
156 l2vic_set_vid_group(base, 4, 2);
157 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x10);
158 l2vic_write32(base, L2VIC_SOFT_INTn, 0x10);
159
160 val = l2vic_read32(base, L2VIC_INT_STATUSn);
161 g_assert_cmpuint(val & 0x10, ==, 0x10);
162 g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_2), ==, 4);
163
164 l2vic_write32(base, L2VIC_INT_CLEARn, 0x10);
165
166 /* IRQ5 steered to VID group 3 -> output line 5 */
167 l2vic_write32(base, L2VIC_INT_TYPEn, 0x20);
168 l2vic_set_vid_group(base, 5, 3);
169 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x20);
170 l2vic_write32(base, L2VIC_SOFT_INTn, 0x20);
171
172 val = l2vic_read32(base, L2VIC_INT_STATUSn);
173 g_assert_cmpuint(val & 0x20, ==, 0x20);
174 g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_3), ==, 5);
175
176 l2vic_write32(base, L2VIC_INT_CLEARn, 0x20);
177
178 /* Restore defaults; the block below reuses IRQ 3-5 without VID steering */
179 l2vic_write32(base, L2VIC_INT_GRPn_0, 0);
180 l2vic_write32(base, L2VIC_INT_TYPEn, 0);
181
182 /* Multiple pending: at most one active at a time */
183 l2vic_write32(base, L2VIC_INT_TYPEn, 0xF);
184 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0xF);
185 l2vic_write32(base, L2VIC_SOFT_INTn, 0xF);
186
187 val = l2vic_read32(base, L2VIC_INT_STATUSn);
188 g_assert_cmpuint(val & 0xF, !=, 0x0);
189
190 /*
191 * Only one irq becomes active per delivery; each clear unblocks the
192 * next pending one, so drain until all four have been delivered.
193 */
194 while ((val = l2vic_read32(base, L2VIC_INT_STATUSn)) & 0xF) {
195 l2vic_write32(base, L2VIC_INT_CLEARn, val & 0xF);
196 }
197
198 /* Level-triggered sources ignore soft interrupts */
199 l2vic_write32(base, L2VIC_INT_TYPEn, 0x0);
200 l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x20);
201 l2vic_write32(base, L2VIC_SOFT_INTn, 0x20);
202
203 val = l2vic_read32(base, L2VIC_INT_STATUSn);
204 g_assert_cmpuint(val & 0x20, ==, 0x0);
205
206 /* Same source, now edge-triggered, does fire */
207 l2vic_write32(base, L2VIC_INT_TYPEn, 0x20);
208 l2vic_write32(base, L2VIC_SOFT_INTn, 0x20);
209 val = l2vic_read32(base, L2VIC_INT_STATUSn);
210 g_assert_cmpuint(val & 0x20, ==, 0x20);
211
212 l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0xFFFFFFFF);
213 l2vic_write32(base, L2VIC_INT_CLEARn, 0xFFFFFFFF);
214 l2vic_write32(base, L2VIC_INT_GRPn_0, 0);
215 l2vic_write32(base, L2VIC_INT_GRPn_1, 0);
216 l2vic_write32(base, L2VIC_INT_GRPn_2, 0);
217 l2vic_write32(base, L2VIC_INT_GRPn_3, 0);
218 }
219
220 static void test_l2vic_on_machine(gconstpointer data)
221 {
222 const L2VICMachineCfg *mc = data;
223 g_autofree char *args = g_strdup_printf("-machine %s", mc->machine);
224 uint64_t base = mc->cfg->l2vic_base;
225
226 qtest_start(args);
227
228 test_l2vic_register_access(base);
229 test_l2vic_interrupt_enable(base);
230 test_l2vic_basic_functionality(base);
231 test_l2vic_irq_outputs(base);
232
233 qtest_end();
234 }
235
236 int main(int argc, char **argv)
237 {
238 size_t i;
239
240 g_test_init(&argc, &argv, NULL);
241
242 for (i = 0; i < ARRAY_SIZE(l2vic_machines); i++) {
243 g_autofree char *path = g_strdup_printf("/l2vic/%s/all-tests",
244 l2vic_machines[i].machine);
245 qtest_add_data_func(path, &l2vic_machines[i], test_l2vic_on_machine);
246 }
247
248 return g_test_run();
249 }