xref: /openbmc/qemu/tests/qtest/xlnx-canfd-test.c (revision 8a64609e)
1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * QTests for the Xilinx Versal CANFD controller.
5  *
6  * Copyright (c) 2022 AMD Inc.
7  *
8  * Written-by: Vikram Garhwal<vikram.garhwal@amd.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include "qemu/osdep.h"
30 #include "libqtest.h"
31 
32 /* Base address. */
33 #define CANFD0_BASE_ADDR                0xff060000
34 #define CANFD1_BASE_ADDR                0xff070000
35 
36 /* Register addresses. */
37 #define R_SRR_OFFSET                    0x00
38 #define R_MSR_OFFSET                    0x04
39 #define R_FILTER_CONTROL_REGISTER       0xe0
40 #define R_SR_OFFSET                     0x18
41 #define R_ISR_OFFSET                    0x1c
42 #define R_IER_OFFSET                    0x20
43 #define R_ICR_OFFSET                    0x24
44 #define R_TX_READY_REQ_REGISTER         0x90
45 #define RX_FIFO_STATUS_REGISTER         0xe8
46 #define R_TXID_OFFSET                   0x100
47 #define R_TXDLC_OFFSET                  0x104
48 #define R_TXDATA1_OFFSET                0x108
49 #define R_TXDATA2_OFFSET                0x10c
50 #define R_AFMR_REGISTER0                0xa00
51 #define R_AFIR_REGISTER0                0xa04
52 #define R_RX0_ID_OFFSET                 0x2100
53 #define R_RX0_DLC_OFFSET                0x2104
54 #define R_RX0_DATA1_OFFSET              0x2108
55 #define R_RX0_DATA2_OFFSET              0x210c
56 
57 /* CANFD modes. */
58 #define SRR_CONFIG_MODE                 0x00
59 #define MSR_NORMAL_MODE                 0x00
60 #define MSR_LOOPBACK_MODE               (1 << 1)
61 #define ENABLE_CANFD                    (1 << 1)
62 
63 /* CANFD status. */
64 #define STATUS_CONFIG_MODE              (1 << 0)
65 #define STATUS_NORMAL_MODE              (1 << 3)
66 #define STATUS_LOOPBACK_MODE            (1 << 1)
67 #define ISR_TXOK                        (1 << 1)
68 #define ISR_RXOK                        (1 << 4)
69 
70 #define ENABLE_ALL_FILTERS              0xffffffff
71 #define ENABLE_ALL_INTERRUPTS           0xffffffff
72 
73 /* We are sending one canfd message. */
74 #define TX_READY_REG_VAL                0x1
75 
76 #define FIRST_RX_STORE_INDEX            0x1
77 #define STATUS_REG_MASK                 0xf
78 #define DLC_FD_BIT_SHIFT                0x1b
79 #define DLC_FD_BIT_MASK                 0xf8000000
80 #define FIFO_STATUS_READ_INDEX_MASK     0x3f
81 #define FIFO_STATUS_FILL_LEVEL_MASK     0x7f00
82 #define FILL_LEVEL_SHIFT                0x8
83 
84 /* CANFD frame size ID, DLC and 16 DATA word. */
85 #define CANFD_FRAME_SIZE        18
86 /* CAN frame size ID, DLC and 2 DATA word. */
87 #define CAN_FRAME_SIZE          4
88 
89 /* Set the filters for CANFD controller. */
90 static void enable_filters(QTestState *qts)
91 {
92      const uint32_t arr_afmr[32] = { 0xb423deaa, 0xa2a40bdc, 0x1b64f486,
93                                      0x95c0d4ee, 0xe0c44528, 0x4b407904,
94                                      0xd2673f46, 0x9fc638d6, 0x8844f3d8,
95                                      0xa607d1e8, 0x67871bf4, 0xc2557dc,
96                                      0x9ea5b53e, 0x3643c0cc, 0x5a05ea8e,
97                                      0x83a46d84, 0x4a25c2b8, 0x93a66008,
98                                      0x2e467470, 0xedc66118, 0x9086f9f2,
99                                      0xfa23dd36, 0xb6654b90, 0xb221b8ca,
100                                      0x3467d1e2, 0xa3a55542, 0x5b26a012,
101                                      0x2281ea7e, 0xcea0ece8, 0xdc61e588,
102                                      0x2e5676a,  0x16821320 };
103 
104     const uint32_t arr_afir[32] = { 0xa833dfa1, 0x255a477e, 0x3a4bb1c5,
105                                     0x8f560a6c, 0x27f38903, 0x2fecec4d,
106                                     0xa014c66d, 0xec289b8,  0x7e52dead,
107                                     0x82e94f3c, 0xcf3e3c5c, 0x66059871,
108                                     0x3f213df4, 0x25ac3959, 0xa12e9bef,
109                                     0xa3ad3af,  0xbafd7fe,  0xb3cb40fd,
110                                     0x5d9caa81, 0x2ed61902, 0x7cd64a0,
111                                     0x4b1fa538, 0x9b5ced8c, 0x150de059,
112                                     0xd2794227, 0x635e820a, 0xbb6b02cf,
113                                     0xbb58176,  0x570025bb, 0xa78d9658,
114                                     0x49d735df, 0xe5399d2f };
115 
116     /* Passing the respective array values to all the AFMR and AFIR pairs. */
117     for (int i = 0; i < 32; i++) {
118         /* For CANFD0. */
119        qtest_writel(qts, CANFD0_BASE_ADDR + R_AFMR_REGISTER0 + 8 * i,
120                     arr_afmr[i]);
121        qtest_writel(qts, CANFD0_BASE_ADDR + R_AFIR_REGISTER0 + 8 * i,
122                     arr_afir[i]);
123 
124         /* For CANFD1. */
125        qtest_writel(qts, CANFD1_BASE_ADDR + R_AFMR_REGISTER0 + 8 * i,
126                     arr_afmr[i]);
127        qtest_writel(qts, CANFD1_BASE_ADDR + R_AFIR_REGISTER0 + 8 * i,
128                     arr_afir[i]);
129     }
130 
131     /* Enable all the pairs from AFR register. */
132     qtest_writel(qts, CANFD0_BASE_ADDR + R_FILTER_CONTROL_REGISTER,
133                  ENABLE_ALL_FILTERS);
134     qtest_writel(qts, CANFD1_BASE_ADDR + R_FILTER_CONTROL_REGISTER,
135                  ENABLE_ALL_FILTERS);
136 }
137 
138 static void configure_canfd(QTestState *qts, uint8_t mode)
139 {
140     uint32_t status = 0;
141 
142     /* Put CANFD0 and CANFD1 in config mode. */
143     qtest_writel(qts, CANFD0_BASE_ADDR + R_SRR_OFFSET, SRR_CONFIG_MODE);
144     qtest_writel(qts, CANFD1_BASE_ADDR + R_SRR_OFFSET, SRR_CONFIG_MODE);
145 
146     /* Write mode of operation in Mode select register. */
147     qtest_writel(qts, CANFD0_BASE_ADDR + R_MSR_OFFSET, mode);
148     qtest_writel(qts, CANFD1_BASE_ADDR + R_MSR_OFFSET, mode);
149 
150     enable_filters(qts);
151 
152     /* Check here if CANFD0 and CANFD1 are in config mode. */
153     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
154     status = status & STATUS_REG_MASK;
155     g_assert_cmpint(status, ==, STATUS_CONFIG_MODE);
156 
157     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
158     status = status & STATUS_REG_MASK;
159     g_assert_cmpint(status, ==, STATUS_CONFIG_MODE);
160 
161     qtest_writel(qts, CANFD1_BASE_ADDR + R_IER_OFFSET, ENABLE_ALL_INTERRUPTS);
162     qtest_writel(qts, CANFD1_BASE_ADDR + R_IER_OFFSET, ENABLE_ALL_INTERRUPTS);
163 
164     qtest_writel(qts, CANFD0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CANFD);
165     qtest_writel(qts, CANFD1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CANFD);
166 }
167 
168 static void generate_random_data(uint32_t *buf_tx, bool is_canfd_frame)
169 {
170     /* Generate random TX data for CANFD frame. */
171     if (is_canfd_frame) {
172         for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
173             buf_tx[2 + i] = g_random_int();
174         }
175     } else {
176         /* Generate random TX data for CAN frame. */
177         for (int i = 0; i < CAN_FRAME_SIZE - 2; i++) {
178             buf_tx[2 + i] = g_random_int();
179         }
180     }
181 }
182 
183 static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx,
184                       uint32_t frame_size)
185 {
186     uint32_t int_status;
187     uint32_t fifo_status_reg_value;
188     /* At which RX FIFO the received data is stored. */
189     uint8_t store_ind = 0;
190 
191     /* Read the interrupt on CANFD rx. */
192     int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK;
193 
194     g_assert_cmpint(int_status, ==, ISR_RXOK);
195 
196     /* Find the fill level and read index. */
197     fifo_status_reg_value = qtest_readl(qts, can_base_addr +
198                                         RX_FIFO_STATUS_REGISTER);
199 
200     store_ind = (fifo_status_reg_value & FIFO_STATUS_READ_INDEX_MASK) +
201                 ((fifo_status_reg_value & FIFO_STATUS_FILL_LEVEL_MASK) >>
202                   FILL_LEVEL_SHIFT);
203 
204     g_assert_cmpint(store_ind, ==, FIRST_RX_STORE_INDEX);
205 
206     /* Read the RX register data for CANFD. */
207     buf_rx[0] = qtest_readl(qts, can_base_addr + R_RX0_ID_OFFSET);
208     buf_rx[1] = qtest_readl(qts, can_base_addr + R_RX0_DLC_OFFSET);
209 
210     for (int i = 0; i < frame_size - 2; i++) {
211         buf_rx[i + 2] = qtest_readl(qts,
212                                 can_base_addr + R_RX0_DATA1_OFFSET + 4 * i);
213     }
214 
215     /* Clear the RX interrupt. */
216     qtest_writel(qts, CANFD1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK);
217 }
218 
219 static void write_data(QTestState *qts, uint64_t can_base_addr,
220                        const uint32_t *buf_tx, bool is_canfd_frame)
221 {
222     /* Write the TX register data for CANFD. */
223     qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]);
224     qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]);
225 
226     if (is_canfd_frame) {
227         for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
228             qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET + 4 * i,
229                          buf_tx[2 + i]);
230         }
231     } else {
232         qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]);
233         qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]);
234     }
235 }
236 
237 static void send_data(QTestState *qts, uint64_t can_base_addr)
238 {
239     uint32_t int_status;
240 
241     qtest_writel(qts, can_base_addr + R_TX_READY_REQ_REGISTER,
242                  TX_READY_REG_VAL);
243 
244     /* Read the interrupt on CANFD for tx. */
245     int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK;
246 
247     g_assert_cmpint(int_status, ==, ISR_TXOK);
248 
249     /* Clear the interrupt for tx. */
250     qtest_writel(qts, CANFD0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK);
251 }
252 
253 static void match_rx_tx_data(const uint32_t *buf_tx, const uint32_t *buf_rx,
254                              bool is_canfd_frame)
255 {
256     uint16_t size = 0;
257     uint8_t len = CAN_FRAME_SIZE;
258 
259     if (is_canfd_frame) {
260         len = CANFD_FRAME_SIZE;
261     }
262 
263     while (size < len) {
264         if (R_RX0_ID_OFFSET + 4 * size == R_RX0_DLC_OFFSET)  {
265             g_assert_cmpint((buf_rx[size] & DLC_FD_BIT_MASK), ==,
266                             (buf_tx[size] & DLC_FD_BIT_MASK));
267         } else {
268             g_assert_cmpint(buf_rx[size], ==, buf_tx[size]);
269         }
270 
271         size++;
272     }
273 }
274 /*
275  * Xilinx CANFD supports both CAN and CANFD frames. This test will be
276  * transferring CAN frame i.e. 8 bytes of data from CANFD0 and CANFD1 through
277  * canbus. CANFD0 initiate the data transfer to can-bus, CANFD1 receives the
278  * data. Test compares the can frame data sent from CANFD0 and received on
279  * CANFD1.
280  */
281 static void test_can_data_transfer(void)
282 {
283     uint32_t buf_tx[CAN_FRAME_SIZE] = { 0x5a5bb9a4, 0x80000000,
284                                         0x12345678, 0x87654321 };
285     uint32_t buf_rx[CAN_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
286     uint32_t status = 0;
287 
288     generate_random_data(buf_tx, false);
289 
290     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
291                 " -object can-bus,id=canbus"
292                 " -machine canbus0=canbus"
293                 " -machine canbus1=canbus"
294                 );
295 
296     configure_canfd(qts, MSR_NORMAL_MODE);
297 
298     /* Check if CANFD0 and CANFD1 are in Normal mode. */
299     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
300     status = status & STATUS_REG_MASK;
301     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
302 
303     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
304     status = status & STATUS_REG_MASK;
305     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
306 
307     write_data(qts, CANFD0_BASE_ADDR, buf_tx, false);
308 
309     send_data(qts, CANFD0_BASE_ADDR);
310     read_data(qts, CANFD1_BASE_ADDR, buf_rx, CAN_FRAME_SIZE);
311     match_rx_tx_data(buf_tx, buf_rx, false);
312 
313     qtest_quit(qts);
314 }
315 
316 /*
317  * This test will be transferring CANFD frame i.e. 64 bytes of data from CANFD0
318  * and CANFD1 through canbus. CANFD0 initiate the data transfer to can-bus,
319  * CANFD1 receives the data. Test compares the CANFD frame data sent from CANFD0
320  * with received on CANFD1.
321  */
322 static void test_canfd_data_transfer(void)
323 {
324     uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
325     uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
326     uint32_t status = 0;
327 
328     generate_random_data(buf_tx, true);
329 
330     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
331                 " -object can-bus,id=canbus"
332                 " -machine canbus0=canbus"
333                 " -machine canbus1=canbus"
334                 );
335 
336     configure_canfd(qts, MSR_NORMAL_MODE);
337 
338     /* Check if CANFD0 and CANFD1 are in Normal mode. */
339     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
340     status = status & STATUS_REG_MASK;
341     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
342 
343     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
344     status = status & STATUS_REG_MASK;
345     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
346 
347     write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
348 
349     send_data(qts, CANFD0_BASE_ADDR);
350     read_data(qts, CANFD1_BASE_ADDR, buf_rx, CANFD_FRAME_SIZE);
351     match_rx_tx_data(buf_tx, buf_rx, true);
352 
353     qtest_quit(qts);
354 }
355 
356 /*
357  * This test is performing loopback mode on CANFD0 and CANFD1. Data sent from
358  * TX of each CANFD0 and CANFD1 are compared with RX register data for
359  * respective CANFD Controller.
360  */
361 static void test_can_loopback(void)
362 {
363     uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
364     uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
365     uint32_t status = 0;
366 
367     generate_random_data(buf_tx, true);
368 
369     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
370                 " -object can-bus,id=canbus"
371                 " -machine canbus0=canbus"
372                 " -machine canbus1=canbus"
373                 );
374 
375     configure_canfd(qts, MSR_LOOPBACK_MODE);
376 
377     /* Check if CANFD0 and CANFD1 are set in correct loopback mode. */
378     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
379     status = status & STATUS_REG_MASK;
380     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
381 
382     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
383     status = status & STATUS_REG_MASK;
384     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
385 
386     write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
387 
388     send_data(qts, CANFD0_BASE_ADDR);
389     read_data(qts, CANFD0_BASE_ADDR, buf_rx, CANFD_FRAME_SIZE);
390     match_rx_tx_data(buf_tx, buf_rx, true);
391 
392     generate_random_data(buf_tx, true);
393 
394     write_data(qts, CANFD1_BASE_ADDR, buf_tx, true);
395 
396     send_data(qts, CANFD1_BASE_ADDR);
397     read_data(qts, CANFD1_BASE_ADDR, buf_rx, CANFD_FRAME_SIZE);
398     match_rx_tx_data(buf_tx, buf_rx, true);
399 
400     qtest_quit(qts);
401 }
402 
403 int main(int argc, char **argv)
404 {
405     g_test_init(&argc, &argv, NULL);
406 
407     qtest_add_func("/net/canfd/can_data_transfer", test_can_data_transfer);
408     qtest_add_func("/net/canfd/canfd_data_transfer", test_canfd_data_transfer);
409     qtest_add_func("/net/canfd/can_loopback", test_can_loopback);
410 
411     return g_test_run();
412 }
413