xlnx-can-test.c (12963B)
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 72static 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 89static 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 108static 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 */ 133static 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 */ 171static 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 */ 218static 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. */ 266static 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. */ 312static 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 349int 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}