forked from OpenDGPS/zynq-axi-dma-sg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zynq-axi-dma-sg.c
279 lines (220 loc) · 15.7 KB
/
zynq-axi-dma-sg.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*********************************************************************/
/* TRANSFER MEMORY TO ZYNQ PL (MM2S) */
/* AND FROM ZYNQ PL TO MEMORY (S2MM) */
/* */
/* THIS C-CODE IS AUTOGENERATED BY gen-c.xslt */
/* COMPILE: gcc -Wall -o zynq-axi-dma-sg zynq-axi-dma-sg.c */
/* RUN as sudo: taskset -1 ./zynq-axi-dma-sg */
/*********************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
/*
from AXI DMA v7.1 - LogiCORE IP Product Guide http://www.xilinx.com/support/documentation/ip_documentation/axi_dma/v7_1/pg021_axi_dma.pdf
1. Write the address of the starting descriptor to the Current Descriptor register. If AXI DMA is configured for an address space greater than 32, then also program the MSB 32 bits of the current descriptor.
2. Start the MM2S channel running by setting the run/stop bit to 1 (MM2S_DMACR.RS =1). The Halted bit (DMASR.Halted) should deassert indicating the MM2S channel is running.
3. If desired, enable interrupts by writing a 1 to MM2S_DMACR.IOC_IrqEn and MM2S_DMACR.Err_IrqEn.
4. Write a valid address to the Tail Descriptor register. If AXI DMA is configured for an address space greater than 32, then also program the MSB 32 bits of the tail descriptor.
5. Writing to the Tail Descriptor register triggers the DMA to start fetching the descriptors from the memory. In case of multichannel configuration, the fetching of descriptors starts when the packet arrives on the S2MM channel.
6. The fetched descriptors are processed, Data is read from the memory and then output to the MM2S streaming channel.
*/
/*********************************************************************/
/* define mmap locations */
/* consult the README for the exact memory layout */
/*********************************************************************/
#define AXI_DMA_REGISTER_LOCATION 0x40400000 //AXI DMA Register Address Map
#define DESCRIPTOR_REGISTERS_SIZE 0xFFFF
#define SG_DMA_DESCRIPTORS_WIDTH 0xFFFF
#define MEMBLOCK_WIDTH 0x3FFFFFF //size of mem used by s2mm and mm2s
#define BUFFER_BLOCK_WIDTH 0x7D0000 //size of memory block per descriptor in bytes
#define NUM_OF_DESCRIPTORS 0x7 //number of descriptors for each direction
#define HP0_DMA_BUFFER_MEM_ADDRESS 0x20000000
#define HP0_MM2S_DMA_BASE_MEM_ADDRESS (HP0_DMA_BUFFER_MEM_ADDRESS)
#define HP0_S2MM_DMA_BASE_MEM_ADDRESS (HP0_DMA_BUFFER_MEM_ADDRESS + MEMBLOCK_WIDTH + 1)
#define HP0_MM2S_DMA_DESCRIPTORS_ADDRESS (HP0_MM2S_DMA_BASE_MEM_ADDRESS)
#define HP0_S2MM_DMA_DESCRIPTORS_ADDRESS (HP0_S2MM_DMA_BASE_MEM_ADDRESS)
#define HP0_MM2S_SOURCE_MEM_ADDRESS (HP0_MM2S_DMA_BASE_MEM_ADDRESS + SG_DMA_DESCRIPTORS_WIDTH + 1)
#define HP0_S2MM_TARGET_MEM_ADDRESS (HP0_S2MM_DMA_BASE_MEM_ADDRESS + SG_DMA_DESCRIPTORS_WIDTH + 1)
/*********************************************************************/
/* define all register locations */
/* based on "LogiCORE IP Product Guide" */
/*********************************************************************/
// MM2S CONTROL
#define MM2S_CONTROL_REGISTER 0x00 // MM2S_DMACR
#define MM2S_STATUS_REGISTER 0x04 // MM2S_DMASR
#define MM2S_CURDESC 0x08 // must align 0x40 addresses
#define MM2S_CURDESC_MSB 0x0C // unused with 32bit addresses
#define MM2S_TAILDESC 0x10 // must align 0x40 addresses
#define MM2S_TAILDESC_MSB 0x14 // unused with 32bit addresses
#define SG_CTL 0x2C // CACHE CONTROL
// S2MM CONTROL
#define S2MM_CONTROL_REGISTER 0x30 // S2MM_DMACR
#define S2MM_STATUS_REGISTER 0x34 // S2MM_DMASR
#define S2MM_CURDESC 0x38 // must align 0x40 addresses
#define S2MM_CURDESC_MSB 0x3C // unused with 32bit addresses
#define S2MM_TAILDESC 0x40 // must align 0x40 addresses
#define S2MM_TAILDESC_MSB 0x44 // unused with 32bit addresses
int main() {
unsigned int* axi_dma_register_mmap;
unsigned int* mm2s_descriptor_register_mmap;
unsigned int* s2mm_descriptor_register_mmap;
unsigned int* source_mem_map;
unsigned int* dest_mem_map;
int controlregister_ok = 0,mm2s_status,s2mm_status;
uint32_t mm2s_current_descriptor_address;
uint32_t s2mm_current_descriptor_address;
uint32_t mm2s_tail_descriptor_address;
uint32_t s2mm_tail_descriptor_address;
/*********************************************************************/
/* mmap the AXI DMA Register Address Map */
/* the base address is defined in vivado */
/* by editing the offset address in */
/* address editor tab ("open block diagramm") */
/*********************************************************************/
int dh = open("/dev/mem", O_RDWR | O_SYNC);
axi_dma_register_mmap = mmap(NULL, DESCRIPTOR_REGISTERS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, AXI_DMA_REGISTER_LOCATION);
mm2s_descriptor_register_mmap = mmap(NULL, DESCRIPTOR_REGISTERS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, HP0_MM2S_DMA_DESCRIPTORS_ADDRESS);
s2mm_descriptor_register_mmap = mmap(NULL, DESCRIPTOR_REGISTERS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, HP0_S2MM_DMA_DESCRIPTORS_ADDRESS);
source_mem_map = mmap(NULL, BUFFER_BLOCK_WIDTH * NUM_OF_DESCRIPTORS, PROT_READ | PROT_WRITE, MAP_SHARED, dh, (off_t)(HP0_MM2S_SOURCE_MEM_ADDRESS));
dest_mem_map = mmap(NULL, BUFFER_BLOCK_WIDTH * NUM_OF_DESCRIPTORS, PROT_READ | PROT_WRITE, MAP_SHARED, dh, (off_t)(HP0_S2MM_TARGET_MEM_ADDRESS));
int i;
// fill mm2s-register memory with zeros
for (i = 0; i < DESCRIPTOR_REGISTERS_SIZE; i++) {
char *p = (char *)mm2s_descriptor_register_mmap;
p[i] = 0x00000000;
}
// fill s2mm-register memory with zeros
for (i = 0; i < DESCRIPTOR_REGISTERS_SIZE; i++) {
char *p = (char *)s2mm_descriptor_register_mmap;
p[i] = 0x00000000;
}
// fill source memory with a counter value
for (i = 0; i < (BUFFER_BLOCK_WIDTH / 4) * NUM_OF_DESCRIPTORS; i++) {
unsigned int *p = source_mem_map;
p[i] = 0x00000000 + i;
}
// fill target memory with zeros
for (i = 0; i < (BUFFER_BLOCK_WIDTH / 4) * NUM_OF_DESCRIPTORS; i++) {
unsigned int *p = dest_mem_map;
p[i] = 0xffffffff;
}
/*********************************************************************/
/* reset and halt all dma operations */
/*********************************************************************/
axi_dma_register_mmap[MM2S_CONTROL_REGISTER >> 2] = 0x4;
axi_dma_register_mmap[S2MM_CONTROL_REGISTER >> 2] = 0x4;
axi_dma_register_mmap[MM2S_CONTROL_REGISTER >> 2] = 0x0;
axi_dma_register_mmap[S2MM_CONTROL_REGISTER >> 2] = 0x0;
/*********************************************************************/
/* build mm2s and s2mm stream and control stream */
/* chains will be filled with next desc, buffer width and registers */
/* [0]: next descr */
/* [1]: reserved */
/* [2]: buffer addr */
/*********************************************************************/
mm2s_current_descriptor_address = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS; // save current descriptor address
mm2s_descriptor_register_mmap[0x0 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x40; // set next descriptor address
mm2s_descriptor_register_mmap[0x8 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x0; // set target buffer address
mm2s_descriptor_register_mmap[0x18 >> 2] = 0x87D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0x40 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x80; // set next descriptor address
mm2s_descriptor_register_mmap[0x48 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x7D0000; // set target buffer address
mm2s_descriptor_register_mmap[0x58 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0x80 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0xC0; // set next descriptor address
mm2s_descriptor_register_mmap[0x88 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0xFA0000; // set target buffer address
mm2s_descriptor_register_mmap[0x98 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0xC0 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x100; // set next descriptor address
mm2s_descriptor_register_mmap[0xC8 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x1770000; // set target buffer address
mm2s_descriptor_register_mmap[0xD8 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0x100 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x140; // set next descriptor address
mm2s_descriptor_register_mmap[0x108 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x1F40000; // set target buffer address
mm2s_descriptor_register_mmap[0x118 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0x140 >> 2] = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x180; // set next descriptor address
mm2s_descriptor_register_mmap[0x148 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x2710000; // set target buffer address
mm2s_descriptor_register_mmap[0x158 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
mm2s_descriptor_register_mmap[0x180 >> 2] = 0x00; // set next descriptor address (unused?)
mm2s_descriptor_register_mmap[0x188 >> 2] = HP0_MM2S_SOURCE_MEM_ADDRESS + 0x2EE0000; // set target buffer address
mm2s_descriptor_register_mmap[0x198 >> 2] = 0x47D0000; // set mm2s/s2mm buffer length to control register
mm2s_tail_descriptor_address = HP0_MM2S_DMA_DESCRIPTORS_ADDRESS + 0x180 ; // save tail descriptor address
s2mm_current_descriptor_address = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS; // save current descriptor address
s2mm_descriptor_register_mmap[0x0 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x40; // set next descriptor address
s2mm_descriptor_register_mmap[0x8 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x0; // set target buffer address
s2mm_descriptor_register_mmap[0x18 >> 2] = 0x87D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0x40 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x80; // set next descriptor address
s2mm_descriptor_register_mmap[0x48 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x7D0000; // set target buffer address
s2mm_descriptor_register_mmap[0x58 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0x80 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0xC0; // set next descriptor address
s2mm_descriptor_register_mmap[0x88 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0xFA0000; // set target buffer address
s2mm_descriptor_register_mmap[0x98 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0xC0 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x100; // set next descriptor address
s2mm_descriptor_register_mmap[0xC8 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x1770000; // set target buffer address
s2mm_descriptor_register_mmap[0xD8 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0x100 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x140; // set next descriptor address
s2mm_descriptor_register_mmap[0x108 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x1F40000; // set target buffer address
s2mm_descriptor_register_mmap[0x118 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0x140 >> 2] = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x180; // set next descriptor address
s2mm_descriptor_register_mmap[0x148 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x2710000; // set target buffer address
s2mm_descriptor_register_mmap[0x158 >> 2] = 0x7D0000; // set mm2s/s2mm buffer length to control register
s2mm_descriptor_register_mmap[0x180 >> 2] = 0x00; // set next descriptor address (unused?)
s2mm_descriptor_register_mmap[0x188 >> 2] = HP0_S2MM_TARGET_MEM_ADDRESS + 0x2EE0000; // set target buffer address
s2mm_descriptor_register_mmap[0x198 >> 2] = 0x47D0000; // set mm2s/s2mm buffer length to control register
s2mm_tail_descriptor_address = HP0_S2MM_DMA_DESCRIPTORS_ADDRESS + 0x180 ; // save tail descriptor address
/*********************************************************************/
/* set current descriptor addresses */
/* and start dma operations (S2MM_DMACR.RS = 1) */
/*********************************************************************/
axi_dma_register_mmap[MM2S_CURDESC>>2] = mm2s_current_descriptor_address;
axi_dma_register_mmap[S2MM_CURDESC>>2] = s2mm_current_descriptor_address;
axi_dma_register_mmap[MM2S_CONTROL_REGISTER >> 2] = 0x1;
axi_dma_register_mmap[S2MM_CONTROL_REGISTER >> 2] = 0x1;
/*********************************************************************/
/* start transfer */
/* (by setting the taildescriptors) */
/*********************************************************************/
axi_dma_register_mmap[MM2S_TAILDESC>>2] = mm2s_tail_descriptor_address;
axi_dma_register_mmap[S2MM_TAILDESC>>2] = s2mm_tail_descriptor_address;
/*********************************************************************/
/* wait until all transfers finished */
/*********************************************************************/
while (!controlregister_ok)
{
mm2s_status = axi_dma_register_mmap[MM2S_STATUS_REGISTER >> 2];
s2mm_status = axi_dma_register_mmap[S2MM_STATUS_REGISTER >> 2];
controlregister_ok = ((mm2s_status & 0x00001000) && (s2mm_status & 0x00001000));
printf("Memory-mapped to stream status (0x%08x@0x%02x):\n", mm2s_status, MM2S_STATUS_REGISTER);
printf("MM2S_STATUS_REGISTER status register values:\n");
if (mm2s_status & 0x00000001) printf(" halted"); else printf(" running");
if (mm2s_status & 0x00000002) printf(" idle");
if (mm2s_status & 0x00000008) printf(" SGIncld");
if (mm2s_status & 0x00000010) printf(" DMAIntErr");
if (mm2s_status & 0x00000020) printf(" DMASlvErr");
if (mm2s_status & 0x00000040) printf(" DMADecErr");
if (mm2s_status & 0x00000100) printf(" SGIntErr");
if (mm2s_status & 0x00000200) printf(" SGSlvErr");
if (mm2s_status & 0x00000400) printf(" SGDecErr");
if (mm2s_status & 0x00001000) printf(" IOC_Irq");
if (mm2s_status & 0x00002000) printf(" Dly_Irq");
if (mm2s_status & 0x00004000) printf(" Err_Irq");
printf("\n");
printf("Stream to memory-mapped status (0x%08x@0x%02x):\n", s2mm_status, S2MM_STATUS_REGISTER);
printf("S2MM_STATUS_REGISTER status register values:\n");
if (s2mm_status & 0x00000001) printf(" halted"); else printf(" running");
if (s2mm_status & 0x00000002) printf(" idle");
if (s2mm_status & 0x00000008) printf(" SGIncld");
if (s2mm_status & 0x00000010) printf(" DMAIntErr");
if (s2mm_status & 0x00000020) printf(" DMASlvErr");
if (s2mm_status & 0x00000040) printf(" DMADecErr");
if (s2mm_status & 0x00000100) printf(" SGIntErr");
if (s2mm_status & 0x00000200) printf(" SGSlvErr");
if (s2mm_status & 0x00000400) printf(" SGDecErr");
if (s2mm_status & 0x00001000) printf(" IOC_Irq");
if (s2mm_status & 0x00002000) printf(" Dly_Irq");
if (s2mm_status & 0x00004000) printf(" Err_Irq");
printf("\n");
}
return 0;
}