qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xlnx-can-test.c (12956B)


      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 
     72 static 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 
     89 static 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 
    108 static 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  */
    133 static 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  */
    171 static 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  */
    218 static 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. */
    266 static 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. */
    312 static 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 
    349 int 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 }