1 /*
2 * Copyright (c) 2020 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Verify zephyr dma link transfer
10 * @details
11 * - Test Steps
12 * -# Set dma channel configuration including source/dest addr, burstlen
13 * -# Set direction memory-to-memory
14 * -# Start transfer tx -> rx
15 * -# after a major/minor loop trigger another channel to transfer, rx -> rx2
16 * - Expected Results
17 * -# Data is transferred correctly from src to dest
18 */
19
20 #include <zephyr/kernel.h>
21 #include <zephyr/drivers/dma.h>
22 #include <zephyr/ztest.h>
23
24 #define TEST_DMA_CHANNEL_0 (0)
25 #define TEST_DMA_CHANNEL_1 (1)
26 #define RX_BUFF_SIZE (48)
27
28 #ifdef CONFIG_NOCACHE_MEMORY
29 static __aligned(32) char tx_data[RX_BUFF_SIZE] __used
30 __attribute__((__section__(".nocache")));
31 static const char TX_DATA[] = "It is harder to be kind than to be wise........";
32 static __aligned(32) char rx_data[RX_BUFF_SIZE] __used
33 __attribute__((__section__(".nocache.dma")));
34 static __aligned(32) char rx_data2[RX_BUFF_SIZE] __used
35 __attribute__((__section__(".nocache.dma")));
36 #else
37 static const char tx_data[] = "It is harder to be kind than to be wise........";
38 static char rx_data[RX_BUFF_SIZE] = { 0 };
39 static char rx_data2[RX_BUFF_SIZE] = { 0 };
40 #endif
41
test_done(const struct device * dma_dev,void * arg,uint32_t id,int status)42 static void test_done(const struct device *dma_dev, void *arg, uint32_t id,
43 int status)
44 {
45 if (status >= 0) {
46 TC_PRINT("DMA transfer done ch %d\n", id);
47 } else {
48 TC_PRINT("DMA transfer met an error\n");
49 }
50 }
51
test_task(int minor,int major)52 static int test_task(int minor, int major)
53 {
54 struct dma_config dma_cfg = { 0 };
55 struct dma_block_config dma_block_cfg = { 0 };
56 const struct device *const dma = DEVICE_DT_GET(DT_NODELABEL(dma0));
57
58 if (!device_is_ready(dma)) {
59 TC_PRINT("dma controller device is not ready\n");
60 return TC_FAIL;
61 }
62
63 #ifdef CONFIG_NOCACHE_MEMORY
64 memcpy(tx_data, TX_DATA, sizeof(TX_DATA));
65 #endif
66
67 dma_cfg.channel_direction = MEMORY_TO_MEMORY;
68 dma_cfg.source_data_size = 1U;
69 dma_cfg.dest_data_size = 1U;
70 dma_cfg.source_burst_length = 16;
71 dma_cfg.dest_burst_length = 16;
72 dma_cfg.dma_callback = test_done;
73 dma_cfg.complete_callback_en = 0U;
74 dma_cfg.error_callback_dis = 0U;
75 dma_cfg.block_count = 1U;
76 dma_cfg.head_block = &dma_block_cfg;
77 #ifdef CONFIG_DMA_MCUX_TEST_SLOT_START
78 dma_cfg.dma_slot = CONFIG_DMA_MCUX_TEST_SLOT_START;
79 #endif
80
81 TC_PRINT("Preparing DMA Controller: Chan_ID=%u, BURST_LEN=%u\n",
82 TEST_DMA_CHANNEL_1, 8 >> 3);
83
84 TC_PRINT("Starting the transfer\n");
85 (void)memset(rx_data, 0, sizeof(rx_data));
86 (void)memset(rx_data2, 0, sizeof(rx_data2));
87
88 dma_block_cfg.block_size = sizeof(tx_data);
89 #ifdef CONFIG_DMA_64BIT
90 dma_block_cfg.source_address = (uint64_t)tx_data;
91 dma_block_cfg.dest_address = (uint64_t)rx_data2;
92 #else
93 dma_block_cfg.source_address = (uint32_t)tx_data;
94 dma_block_cfg.dest_address = (uint32_t)rx_data2;
95 #endif
96
97 if (dma_config(dma, TEST_DMA_CHANNEL_1, &dma_cfg)) {
98 TC_PRINT("ERROR: transfer\n");
99 return TC_FAIL;
100 }
101
102 #ifdef CONFIG_DMA_MCUX_TEST_SLOT_START
103 dma_cfg.dma_slot = CONFIG_DMA_MCUX_TEST_SLOT_START + 1;
104 #endif
105
106 dma_cfg.source_chaining_en = minor;
107 dma_cfg.dest_chaining_en = major;
108 dma_cfg.linked_channel = TEST_DMA_CHANNEL_1;
109
110 dma_block_cfg.block_size = sizeof(tx_data);
111 #ifdef CONFIG_DMA_64BIT
112 dma_block_cfg.source_address = (uint64_t)tx_data;
113 dma_block_cfg.dest_address = (uint64_t)rx_data;
114 #else
115 dma_block_cfg.source_address = (uint32_t)tx_data;
116 dma_block_cfg.dest_address = (uint32_t)rx_data;
117 #endif
118
119 if (dma_config(dma, TEST_DMA_CHANNEL_0, &dma_cfg)) {
120 TC_PRINT("ERROR: transfer\n");
121 return TC_FAIL;
122 }
123
124 if (dma_start(dma, TEST_DMA_CHANNEL_0)) {
125 TC_PRINT("ERROR: transfer\n");
126 return TC_FAIL;
127 }
128 k_sleep(K_MSEC(2000));
129 TC_PRINT("%s\n", rx_data);
130 TC_PRINT("%s\n", rx_data2);
131 if (minor == 0 && major == 1) {
132 /* major link only trigger lined channel minor loop once */
133 if (strncmp(tx_data, rx_data2, dma_cfg.source_burst_length) != 0) {
134 return TC_FAIL;
135 }
136 } else if (minor == 1 && major == 0) {
137 /* minor link trigger linked channel except the last one*/
138 if (strncmp(tx_data, rx_data2,
139 dma_block_cfg.block_size - dma_cfg.source_burst_length) != 0) {
140 return TC_FAIL;
141 }
142 } else if (minor == 1 && major == 1) {
143 if (strcmp(tx_data, rx_data2) != 0) {
144 return TC_FAIL;
145 }
146 }
147
148 return TC_PASS;
149 }
150
151 /* export test cases */
ZTEST(dma_m2m_link,test_dma_m2m_chan0_1_major_link)152 ZTEST(dma_m2m_link, test_dma_m2m_chan0_1_major_link)
153 {
154 zassert_true((test_task(0, 1) == TC_PASS));
155 }
156
ZTEST(dma_m2m_link,test_dma_m2m_chan0_1_minor_link)157 ZTEST(dma_m2m_link, test_dma_m2m_chan0_1_minor_link)
158 {
159 zassert_true((test_task(1, 0) == TC_PASS));
160 }
161
ZTEST(dma_m2m_link,test_dma_m2m_chan0_1_minor_major_link)162 ZTEST(dma_m2m_link, test_dma_m2m_chan0_1_minor_major_link)
163 {
164 zassert_true((test_task(1, 1) == TC_PASS));
165 }
166