qemu/tests/qtest/xlnx-can-test.c
<<
>>
Prefs
   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 "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}
 361