xref: /openbmc/qemu/tests/qtest/xlnx-can-test.c (revision 4c386f80)
1 /*
2  * QTests for the Xilinx ZynqMP CAN controller.
3  *
4  * Copyright (c) 2020 Xilinx Inc.
5  *
6  * Written-by: Vikram Garhwal<fnu.vikram@xilinx.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include "qemu/osdep.h"
28 #include "libqos/libqtest.h"
29 
30 /* Base address. */
31 #define CAN0_BASE_ADDR          0xFF060000
32 #define CAN1_BASE_ADDR          0xFF070000
33 
34 /* Register addresses. */
35 #define R_SRR_OFFSET            0x00
36 #define R_MSR_OFFSET            0x04
37 #define R_SR_OFFSET             0x18
38 #define R_ISR_OFFSET            0x1C
39 #define R_ICR_OFFSET            0x24
40 #define R_TXID_OFFSET           0x30
41 #define R_TXDLC_OFFSET          0x34
42 #define R_TXDATA1_OFFSET        0x38
43 #define R_TXDATA2_OFFSET        0x3C
44 #define R_RXID_OFFSET           0x50
45 #define R_RXDLC_OFFSET          0x54
46 #define R_RXDATA1_OFFSET        0x58
47 #define R_RXDATA2_OFFSET        0x5C
48 #define R_AFR                   0x60
49 #define R_AFMR1                 0x64
50 #define R_AFIR1                 0x68
51 #define R_AFMR2                 0x6C
52 #define R_AFIR2                 0x70
53 #define R_AFMR3                 0x74
54 #define R_AFIR3                 0x78
55 #define R_AFMR4                 0x7C
56 #define R_AFIR4                 0x80
57 
58 /* CAN modes. */
59 #define CONFIG_MODE             0x00
60 #define NORMAL_MODE             0x00
61 #define LOOPBACK_MODE           0x02
62 #define SNOOP_MODE              0x04
63 #define SLEEP_MODE              0x01
64 #define ENABLE_CAN              (1 << 1)
65 #define STATUS_NORMAL_MODE      (1 << 3)
66 #define STATUS_LOOPBACK_MODE    (1 << 1)
67 #define STATUS_SNOOP_MODE       (1 << 12)
68 #define STATUS_SLEEP_MODE       (1 << 2)
69 #define ISR_TXOK                (1 << 1)
70 #define ISR_RXOK                (1 << 4)
71 
72 static void match_rx_tx_data(const uint32_t *buf_tx, const uint32_t *buf_rx,
73                              uint8_t can_timestamp)
74 {
75     uint16_t size = 0;
76     uint8_t len = 4;
77 
78     while (size < len) {
79         if (R_RXID_OFFSET + 4 * size == R_RXDLC_OFFSET)  {
80             g_assert_cmpint(buf_rx[size], ==, buf_tx[size] + can_timestamp);
81         } else {
82             g_assert_cmpint(buf_rx[size], ==, buf_tx[size]);
83         }
84 
85         size++;
86     }
87 }
88 
89 static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx)
90 {
91     uint32_t int_status;
92 
93     /* Read the interrupt on CAN rx. */
94     int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK;
95 
96     g_assert_cmpint(int_status, ==, ISR_RXOK);
97 
98     /* Read the RX register data for CAN. */
99     buf_rx[0] = qtest_readl(qts, can_base_addr + R_RXID_OFFSET);
100     buf_rx[1] = qtest_readl(qts, can_base_addr + R_RXDLC_OFFSET);
101     buf_rx[2] = qtest_readl(qts, can_base_addr + R_RXDATA1_OFFSET);
102     buf_rx[3] = qtest_readl(qts, can_base_addr + R_RXDATA2_OFFSET);
103 
104     /* Clear the RX interrupt. */
105     qtest_writel(qts, CAN1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK);
106 }
107 
108 static void send_data(QTestState *qts, uint64_t can_base_addr,
109                       const uint32_t *buf_tx)
110 {
111     uint32_t int_status;
112 
113     /* Write the TX register data for CAN. */
114     qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]);
115     qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]);
116     qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]);
117     qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]);
118 
119     /* Read the interrupt on CAN for tx. */
120     int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK;
121 
122     g_assert_cmpint(int_status, ==, ISR_TXOK);
123 
124     /* Clear the interrupt for tx. */
125     qtest_writel(qts, CAN0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK);
126 }
127 
128 /*
129  * This test will be transferring data from CAN0 and CAN1 through canbus. CAN0
130  * initiate the data transfer to can-bus, CAN1 receives the data. Test compares
131  * the data sent from CAN0 with received on CAN1.
132  */
133 static void test_can_bus(void)
134 {
135     const uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 };
136     uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 };
137     uint32_t status = 0;
138     uint8_t can_timestamp = 1;
139 
140     QTestState *qts = qtest_init("-machine xlnx-zcu102"
141                 " -object can-bus,id=canbus"
142                 " -machine canbus0=canbus"
143                 " -machine canbus1=canbus"
144                 );
145 
146     /* Configure the CAN0 and CAN1. */
147     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
148     qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
149     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
150     qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
151 
152     /* Check here if CAN0 and CAN1 are in normal mode. */
153     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
154     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
155 
156     status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET);
157     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
158 
159     send_data(qts, CAN0_BASE_ADDR, buf_tx);
160 
161     read_data(qts, CAN1_BASE_ADDR, buf_rx);
162     match_rx_tx_data(buf_tx, buf_rx, can_timestamp);
163 
164     qtest_quit(qts);
165 }
166 
167 /*
168  * This test is performing loopback mode on CAN0 and CAN1. Data sent from TX of
169  * each CAN0 and CAN1 are compared with RX register data for respective CAN.
170  */
171 static void test_can_loopback(void)
172 {
173     uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 };
174     uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 };
175     uint32_t status = 0;
176 
177     QTestState *qts = qtest_init("-machine xlnx-zcu102"
178                 " -object can-bus,id=canbus"
179                 " -machine canbus0=canbus"
180                 " -machine canbus1=canbus"
181                 );
182 
183     /* Configure the CAN0 in loopback mode. */
184     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE);
185     qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE);
186     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
187 
188     /* Check here if CAN0 is set in loopback mode. */
189     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
190 
191     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
192 
193     send_data(qts, CAN0_BASE_ADDR, buf_tx);
194     read_data(qts, CAN0_BASE_ADDR, buf_rx);
195     match_rx_tx_data(buf_tx, buf_rx, 0);
196 
197     /* Configure the CAN1 in loopback mode. */
198     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE);
199     qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE);
200     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
201 
202     /* Check here if CAN1 is set in loopback mode. */
203     status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET);
204 
205     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
206 
207     send_data(qts, CAN1_BASE_ADDR, buf_tx);
208     read_data(qts, CAN1_BASE_ADDR, buf_rx);
209     match_rx_tx_data(buf_tx, buf_rx, 0);
210 
211     qtest_quit(qts);
212 }
213 
214 /*
215  * Enable filters for CAN1. This will filter incoming messages with ID. In this
216  * test message will pass through filter 2.
217  */
218 static void test_can_filter(void)
219 {
220     uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 };
221     uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 };
222     uint32_t status = 0;
223     uint8_t can_timestamp = 1;
224 
225     QTestState *qts = qtest_init("-machine xlnx-zcu102"
226                 " -object can-bus,id=canbus"
227                 " -machine canbus0=canbus"
228                 " -machine canbus1=canbus"
229                 );
230 
231     /* Configure the CAN0 and CAN1. */
232     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
233     qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
234     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
235     qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
236 
237     /* Check here if CAN0 and CAN1 are in normal mode. */
238     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
239     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
240 
241     status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET);
242     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
243 
244     /* Set filter for CAN1 for incoming messages. */
245     qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0x0);
246     qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR1, 0xF7);
247     qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR1, 0x121F);
248     qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR2, 0x5431);
249     qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR2, 0x14);
250     qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR3, 0x1234);
251     qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR3, 0x5431);
252     qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR4, 0xFFF);
253     qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR4, 0x1234);
254 
255     qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0xF);
256 
257     send_data(qts, CAN0_BASE_ADDR, buf_tx);
258 
259     read_data(qts, CAN1_BASE_ADDR, buf_rx);
260     match_rx_tx_data(buf_tx, buf_rx, can_timestamp);
261 
262     qtest_quit(qts);
263 }
264 
265 /* Testing sleep mode on CAN0 while CAN1 is in normal mode. */
266 static void test_can_sleepmode(void)
267 {
268     uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 };
269     uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 };
270     uint32_t status = 0;
271     uint8_t can_timestamp = 1;
272 
273     QTestState *qts = qtest_init("-machine xlnx-zcu102"
274                 " -object can-bus,id=canbus"
275                 " -machine canbus0=canbus"
276                 " -machine canbus1=canbus"
277                 );
278 
279     /* Configure the CAN0. */
280     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE);
281     qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SLEEP_MODE);
282     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
283 
284     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
285     qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
286 
287     /* Check here if CAN0 is in SLEEP mode and CAN1 in normal mode. */
288     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
289     g_assert_cmpint(status, ==, STATUS_SLEEP_MODE);
290 
291     status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET);
292     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
293 
294     send_data(qts, CAN1_BASE_ADDR, buf_tx);
295 
296     /*
297      * Once CAN1 sends data on can-bus. CAN0 should exit sleep mode.
298      * Check the CAN0 status now. It should exit the sleep mode and receive the
299      * incoming data.
300      */
301     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
302     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
303 
304     read_data(qts, CAN0_BASE_ADDR, buf_rx);
305 
306     match_rx_tx_data(buf_tx, buf_rx, can_timestamp);
307 
308     qtest_quit(qts);
309 }
310 
311 /* Testing Snoop mode on CAN0 while CAN1 is in normal mode. */
312 static void test_can_snoopmode(void)
313 {
314     uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 };
315     uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 };
316     uint32_t status = 0;
317     uint8_t can_timestamp = 1;
318 
319     QTestState *qts = qtest_init("-machine xlnx-zcu102"
320                 " -object can-bus,id=canbus"
321                 " -machine canbus0=canbus"
322                 " -machine canbus1=canbus"
323                 );
324 
325     /* Configure the CAN0. */
326     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE);
327     qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SNOOP_MODE);
328     qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
329 
330     qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN);
331     qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE);
332 
333     /* Check here if CAN0 is in SNOOP mode and CAN1 in normal mode. */
334     status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET);
335     g_assert_cmpint(status, ==, STATUS_SNOOP_MODE);
336 
337     status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET);
338     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
339 
340     send_data(qts, CAN1_BASE_ADDR, buf_tx);
341 
342     read_data(qts, CAN0_BASE_ADDR, buf_rx);
343 
344     match_rx_tx_data(buf_tx, buf_rx, can_timestamp);
345 
346     qtest_quit(qts);
347 }
348 
349 int main(int argc, char **argv)
350 {
351     g_test_init(&argc, &argv, NULL);
352 
353     qtest_add_func("/net/can/can_bus", test_can_bus);
354     qtest_add_func("/net/can/can_loopback", test_can_loopback);
355     qtest_add_func("/net/can/can_filter", test_can_filter);
356     qtest_add_func("/net/can/can_test_snoopmode", test_can_snoopmode);
357     qtest_add_func("/net/can/can_test_sleepmode", test_can_sleepmode);
358 
359     return g_test_run();
360 }
361