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. */
enable_filters(QTestState * qts)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
configure_canfd(QTestState * qts,uint8_t mode)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
generate_random_data(uint32_t * buf_tx,bool is_canfd_frame)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
read_data(QTestState * qts,uint64_t can_base_addr,uint32_t * buf_rx,uint32_t frame_size)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
write_data(QTestState * qts,uint64_t can_base_addr,const uint32_t * buf_tx,bool is_canfd_frame)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
send_data(QTestState * qts,uint64_t can_base_addr)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
match_rx_tx_data(const uint32_t * buf_tx,const uint32_t * buf_rx,bool is_canfd_frame)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 */
test_can_data_transfer(void)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 */
test_canfd_data_transfer(void)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 */
test_can_loopback(void)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
main(int argc,char ** argv)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