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