xref: /openbmc/qemu/tests/qtest/xlnx-canfd-test.c (revision 8d7f954a)
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] = rand();
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] = rand();
179         }
180     }
181 }
182 
183 static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx)
184 {
185     uint32_t int_status;
186     uint32_t fifo_status_reg_value;
187     /* At which RX FIFO the received data is stored. */
188     uint8_t store_ind = 0;
189     bool is_canfd_frame = false;
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     is_canfd_frame = (buf_rx[1] >> DLC_FD_BIT_SHIFT) & 1;
211 
212     if (is_canfd_frame) {
213         for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
214             buf_rx[i + 2] = qtest_readl(qts,
215                                     can_base_addr + R_RX0_DATA1_OFFSET + 4 * i);
216         }
217     } else {
218         buf_rx[2] = qtest_readl(qts, can_base_addr + R_RX0_DATA1_OFFSET);
219         buf_rx[3] = qtest_readl(qts, can_base_addr + R_RX0_DATA2_OFFSET);
220     }
221 
222     /* Clear the RX interrupt. */
223     qtest_writel(qts, CANFD1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK);
224 }
225 
226 static void write_data(QTestState *qts, uint64_t can_base_addr,
227                        const uint32_t *buf_tx, bool is_canfd_frame)
228 {
229     /* Write the TX register data for CANFD. */
230     qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]);
231     qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]);
232 
233     if (is_canfd_frame) {
234         for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
235             qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET + 4 * i,
236                          buf_tx[2 + i]);
237         }
238     } else {
239         qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]);
240         qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]);
241     }
242 }
243 
244 static void send_data(QTestState *qts, uint64_t can_base_addr)
245 {
246     uint32_t int_status;
247 
248     qtest_writel(qts, can_base_addr + R_TX_READY_REQ_REGISTER,
249                  TX_READY_REG_VAL);
250 
251     /* Read the interrupt on CANFD for tx. */
252     int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK;
253 
254     g_assert_cmpint(int_status, ==, ISR_TXOK);
255 
256     /* Clear the interrupt for tx. */
257     qtest_writel(qts, CANFD0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK);
258 }
259 
260 static void match_rx_tx_data(const uint32_t *buf_tx, const uint32_t *buf_rx,
261                              bool is_canfd_frame)
262 {
263     uint16_t size = 0;
264     uint8_t len = CAN_FRAME_SIZE;
265 
266     if (is_canfd_frame) {
267         len = CANFD_FRAME_SIZE;
268     }
269 
270     while (size < len) {
271         if (R_RX0_ID_OFFSET + 4 * size == R_RX0_DLC_OFFSET)  {
272             g_assert_cmpint((buf_rx[size] & DLC_FD_BIT_MASK), ==,
273                             (buf_tx[size] & DLC_FD_BIT_MASK));
274         } else {
275             if (!is_canfd_frame && size == 4) {
276                 break;
277             }
278 
279             g_assert_cmpint(buf_rx[size], ==, buf_tx[size]);
280         }
281 
282         size++;
283     }
284 }
285 /*
286  * Xilinx CANFD supports both CAN and CANFD frames. This test will be
287  * transferring CAN frame i.e. 8 bytes of data from CANFD0 and CANFD1 through
288  * canbus. CANFD0 initiate the data transfer to can-bus, CANFD1 receives the
289  * data. Test compares the can frame data sent from CANFD0 and received on
290  * CANFD1.
291  */
292 static void test_can_data_transfer(void)
293 {
294     uint32_t buf_tx[CAN_FRAME_SIZE] = { 0x5a5bb9a4, 0x80000000,
295                                         0x12345678, 0x87654321 };
296     uint32_t buf_rx[CAN_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
297     uint32_t status = 0;
298 
299     generate_random_data(buf_tx, false);
300 
301     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
302                 " -object can-bus,id=canbus"
303                 " -machine canbus0=canbus"
304                 " -machine canbus1=canbus"
305                 );
306 
307     configure_canfd(qts, MSR_NORMAL_MODE);
308 
309     /* Check if CANFD0 and CANFD1 are in Normal mode. */
310     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
311     status = status & STATUS_REG_MASK;
312     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
313 
314     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
315     status = status & STATUS_REG_MASK;
316     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
317 
318     write_data(qts, CANFD0_BASE_ADDR, buf_tx, false);
319 
320     send_data(qts, CANFD0_BASE_ADDR);
321     read_data(qts, CANFD1_BASE_ADDR, buf_rx);
322     match_rx_tx_data(buf_tx, buf_rx, false);
323 
324     qtest_quit(qts);
325 }
326 
327 /*
328  * This test will be transferring CANFD frame i.e. 64 bytes of data from CANFD0
329  * and CANFD1 through canbus. CANFD0 initiate the data transfer to can-bus,
330  * CANFD1 receives the data. Test compares the CANFD frame data sent from CANFD0
331  * with received on CANFD1.
332  */
333 static void test_canfd_data_transfer(void)
334 {
335     uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
336     uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
337     uint32_t status = 0;
338 
339     generate_random_data(buf_tx, true);
340 
341     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
342                 " -object can-bus,id=canbus"
343                 " -machine canbus0=canbus"
344                 " -machine canbus1=canbus"
345                 );
346 
347     configure_canfd(qts, MSR_NORMAL_MODE);
348 
349     /* Check if CANFD0 and CANFD1 are in Normal mode. */
350     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
351     status = status & STATUS_REG_MASK;
352     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
353 
354     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
355     status = status & STATUS_REG_MASK;
356     g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
357 
358     write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
359 
360     send_data(qts, CANFD0_BASE_ADDR);
361     read_data(qts, CANFD1_BASE_ADDR, buf_rx);
362     match_rx_tx_data(buf_tx, buf_rx, true);
363 
364     qtest_quit(qts);
365 }
366 
367 /*
368  * This test is performing loopback mode on CANFD0 and CANFD1. Data sent from
369  * TX of each CANFD0 and CANFD1 are compared with RX register data for
370  * respective CANFD Controller.
371  */
372 static void test_can_loopback(void)
373 {
374     uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
375     uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
376     uint32_t status = 0;
377 
378     generate_random_data(buf_tx, true);
379 
380     QTestState *qts = qtest_init("-machine xlnx-versal-virt"
381                 " -object can-bus,id=canbus"
382                 " -machine canbus0=canbus"
383                 " -machine canbus1=canbus"
384                 );
385 
386     configure_canfd(qts, MSR_LOOPBACK_MODE);
387 
388     /* Check if CANFD0 and CANFD1 are set in correct loopback mode. */
389     status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
390     status = status & STATUS_REG_MASK;
391     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
392 
393     status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
394     status = status & STATUS_REG_MASK;
395     g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
396 
397     write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
398 
399     send_data(qts, CANFD0_BASE_ADDR);
400     read_data(qts, CANFD0_BASE_ADDR, buf_rx);
401     match_rx_tx_data(buf_tx, buf_rx, true);
402 
403     generate_random_data(buf_tx, true);
404 
405     write_data(qts, CANFD1_BASE_ADDR, buf_tx, true);
406 
407     send_data(qts, CANFD1_BASE_ADDR);
408     read_data(qts, CANFD1_BASE_ADDR, buf_rx);
409     match_rx_tx_data(buf_tx, buf_rx, true);
410 
411     qtest_quit(qts);
412 }
413 
414 int main(int argc, char **argv)
415 {
416     g_test_init(&argc, &argv, NULL);
417 
418     qtest_add_func("/net/canfd/can_data_transfer", test_can_data_transfer);
419     qtest_add_func("/net/canfd/canfd_data_transfer", test_canfd_data_transfer);
420     qtest_add_func("/net/canfd/can_loopback", test_can_loopback);
421 
422     return g_test_run();
423 }
424