1 /******************************************************************************
2 * Filename: udma.c
3 *
4 * Description: Driver for the uDMA controller
5 *
6 * Copyright (c) 2015 - 2022, Texas Instruments Incorporated
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * 1) Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2) Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36
37 #include "udma.h"
38
39 //*****************************************************************************
40 //
41 // Handle support for DriverLib in ROM:
42 // This section will undo prototype renaming made in the header file
43 //
44 //*****************************************************************************
45 #if !defined(DOXYGEN)
46 #undef uDMAChannelAttributeEnable
47 #define uDMAChannelAttributeEnable NOROM_uDMAChannelAttributeEnable
48 #undef uDMAChannelAttributeDisable
49 #define uDMAChannelAttributeDisable NOROM_uDMAChannelAttributeDisable
50 #undef uDMAChannelAttributeGet
51 #define uDMAChannelAttributeGet NOROM_uDMAChannelAttributeGet
52 #undef uDMAChannelControlSet
53 #define uDMAChannelControlSet NOROM_uDMAChannelControlSet
54 #undef uDMAChannelTransferSet
55 #define uDMAChannelTransferSet NOROM_uDMAChannelTransferSet
56 #undef uDMAChannelScatterGatherSet
57 #define uDMAChannelScatterGatherSet NOROM_uDMAChannelScatterGatherSet
58 #undef uDMAChannelSizeGet
59 #define uDMAChannelSizeGet NOROM_uDMAChannelSizeGet
60 #undef uDMAChannelModeGet
61 #define uDMAChannelModeGet NOROM_uDMAChannelModeGet
62 #endif
63
64 //*****************************************************************************
65 //
66 // Enables attributes of a uDMA channel
67 //
68 //*****************************************************************************
69 void
uDMAChannelAttributeEnable(uint32_t ui32Base,uint32_t ui32ChannelNum,uint32_t ui32Attr)70 uDMAChannelAttributeEnable(uint32_t ui32Base, uint32_t ui32ChannelNum,
71 uint32_t ui32Attr)
72 {
73 // Check the arguments.
74 ASSERT(uDMABaseValid(ui32Base));
75 ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
76 ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
77 UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
78
79 // Set the useburst bit for this channel if set in ui32Attr.
80 if(ui32Attr & UDMA_ATTR_USEBURST)
81 {
82 HWREG(ui32Base + UDMA_O_SETBURST) = 1 << ui32ChannelNum;
83 }
84
85 // Set the alternate control select bit for this channel,
86 // if set in ui32Attr.
87 if(ui32Attr & UDMA_ATTR_ALTSELECT)
88 {
89 HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) = 1 << ui32ChannelNum;
90 }
91
92 // Set the high priority bit for this channel, if set in ui32Attr.
93 if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
94 {
95 HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) = 1 << ui32ChannelNum;
96 }
97
98 // Set the request mask bit for this channel, if set in ui32Attr.
99 if(ui32Attr & UDMA_ATTR_REQMASK)
100 {
101 HWREG(ui32Base + UDMA_O_SETREQMASK) = 1 << ui32ChannelNum;
102 }
103 }
104
105 //*****************************************************************************
106 //
107 // Disables attributes of an uDMA channel
108 //
109 //*****************************************************************************
110 void
uDMAChannelAttributeDisable(uint32_t ui32Base,uint32_t ui32ChannelNum,uint32_t ui32Attr)111 uDMAChannelAttributeDisable(uint32_t ui32Base, uint32_t ui32ChannelNum,
112 uint32_t ui32Attr)
113 {
114 // Check the arguments.
115 ASSERT(uDMABaseValid(ui32Base));
116 ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
117 ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
118 UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
119
120 // Clear the useburst bit for this channel if set in ui32Attr.
121 if(ui32Attr & UDMA_ATTR_USEBURST)
122 {
123 HWREG(ui32Base + UDMA_O_CLEARBURST) = 1 << ui32ChannelNum;
124 }
125
126 // Clear the alternate control select bit for this channel, if set in
127 // ululAttr.
128 if(ui32Attr & UDMA_ATTR_ALTSELECT)
129 {
130 HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
131 }
132
133 // Clear the high priority bit for this channel, if set in ui32Attr.
134 if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
135 {
136 HWREG(ui32Base + UDMA_O_CLEARCHNLPRIORITY) = 1 << ui32ChannelNum;
137 }
138
139 // Clear the request mask bit for this channel, if set in ui32Attr.
140 if(ui32Attr & UDMA_ATTR_REQMASK)
141 {
142 HWREG(ui32Base + UDMA_O_CLEARREQMASK) = 1 << ui32ChannelNum;
143 }
144 }
145
146 //*****************************************************************************
147 //
148 // Gets the enabled attributes of a uDMA channel
149 //
150 //*****************************************************************************
151 uint32_t
uDMAChannelAttributeGet(uint32_t ui32Base,uint32_t ui32ChannelNum)152 uDMAChannelAttributeGet(uint32_t ui32Base, uint32_t ui32ChannelNum)
153 {
154 uint32_t ui32Attr = 0;
155
156 // Check the arguments.
157 ASSERT(uDMABaseValid(ui32Base));
158 ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
159
160 // Check to see if useburst bit is set for this channel.
161 if(HWREG(ui32Base + UDMA_O_SETBURST) & (1 << ui32ChannelNum))
162 {
163 ui32Attr |= UDMA_ATTR_USEBURST;
164 }
165
166 // Check to see if the alternate control bit is set for this channel.
167 if(HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) & (1 << ui32ChannelNum))
168 {
169 ui32Attr |= UDMA_ATTR_ALTSELECT;
170 }
171
172 // Check to see if the high priority bit is set for this channel.
173 if(HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) & (1 << ui32ChannelNum))
174 {
175 ui32Attr |= UDMA_ATTR_HIGH_PRIORITY;
176 }
177
178 // Check to see if the request mask bit is set for this channel.
179 if(HWREG(ui32Base + UDMA_O_SETREQMASK) & (1 << ui32ChannelNum))
180 {
181 ui32Attr |= UDMA_ATTR_REQMASK;
182 }
183
184 // Return the configuration flags.
185 return(ui32Attr);
186 }
187
188 //*****************************************************************************
189 //
190 // Sets the control parameters for a uDMA channel control structure
191 //
192 //*****************************************************************************
193 void
uDMAChannelControlSet(uint32_t ui32Base,uint32_t ui32ChannelStructIndex,uint32_t ui32Control)194 uDMAChannelControlSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex,
195 uint32_t ui32Control)
196 {
197 tDMAControlTable *pControlTable;
198
199 // Check the arguments.
200 ASSERT(uDMABaseValid(ui32Base));
201 ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
202 ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
203
204 // Get the base address of the control table.
205 pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
206
207 // Get the current control word value and mask off the fields to be
208 // changed, then OR in the new settings.
209 pControlTable[ui32ChannelStructIndex].ui32Control =
210 ((pControlTable[ui32ChannelStructIndex].ui32Control &
211 ~(UDMA_DST_INC_M |
212 UDMA_SRC_INC_M |
213 UDMA_SIZE_M |
214 UDMA_ARB_M |
215 UDMA_NEXT_USEBURST)) |
216 ui32Control);
217 }
218
219 //*****************************************************************************
220 //
221 // Sets the transfer parameters for a uDMA channel control structure
222 //
223 //*****************************************************************************
224 void
uDMAChannelTransferSet(uint32_t ui32Base,uint32_t ui32ChannelStructIndex,uint32_t ui32Mode,void * pvSrcAddr,void * pvDstAddr,uint32_t ui32TransferSize)225 uDMAChannelTransferSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex,
226 uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr,
227 uint32_t ui32TransferSize)
228 {
229 tDMAControlTable *pControlTable;
230 uint32_t ui32Control;
231 uint32_t ui32Inc;
232 uint32_t ui32BufferBytes;
233
234 // Check the arguments.
235 ASSERT(uDMABaseValid(ui32Base));
236 ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
237 ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
238 ASSERT(ui32Mode <= UDMA_MODE_PER_SCATTER_GATHER);
239 ASSERT((uint32_t)pvSrcAddr >= SRAM_BASE);
240 ASSERT((uint32_t)pvDstAddr >= SRAM_BASE);
241 ASSERT((ui32TransferSize != 0) && (ui32TransferSize <= UDMA_XFER_SIZE_MAX));
242
243 // Get the base address of the control table.
244 pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
245
246 // Get the current control word value and mask off the mode and size
247 // fields.
248 ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
249 ~(UDMA_XFER_SIZE_M | UDMA_MODE_M));
250
251 // Adjust the mode if the alt control structure is selected.
252 if(ui32ChannelStructIndex & UDMA_ALT_SELECT)
253 {
254 if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
255 (ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
256 {
257 ui32Mode |= UDMA_MODE_ALT_SELECT;
258 }
259 }
260
261 // Set the transfer size and mode in the control word (but don't write the
262 // control word yet as it could kick off a transfer).
263 ui32Control |= ui32Mode | ((ui32TransferSize - 1) << UDMA_XFER_SIZE_S);
264
265 // Get the address increment value for the source, from the control word.
266 ui32Inc = (ui32Control & UDMA_SRC_INC_M);
267
268 // Compute the ending source address of the transfer. If the source
269 // increment is set to none, then the ending address is the same as the
270 // beginning.
271 if(ui32Inc != UDMA_SRC_INC_NONE)
272 {
273 ui32Inc = ui32Inc >> UDMA_SRC_INC_S;
274 ui32BufferBytes = ui32TransferSize << ui32Inc;
275 pvSrcAddr = (void *)((uint32_t)pvSrcAddr + ui32BufferBytes - (1 << ui32Inc));
276 }
277
278 // Load the source ending address into the control block.
279 pControlTable[ui32ChannelStructIndex].pvSrcEndAddr = pvSrcAddr;
280
281 // Get the address increment value for the destination, from the control
282 // word.
283 ui32Inc = ui32Control & UDMA_DST_INC_M;
284
285 // Compute the ending destination address of the transfer. If the
286 // destination increment is set to none, then the ending address is the
287 // same as the beginning.
288 if(ui32Inc != UDMA_DST_INC_NONE)
289 {
290 // There is a special case if this is setting up a scatter-gather
291 // transfer. The destination pointer needs to point to the end of
292 // the alternate structure for this channel instead of calculating
293 // the end of the buffer in the normal way.
294 if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
295 (ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
296 {
297 pvDstAddr =
298 (void *)&pControlTable[ui32ChannelStructIndex |
299 UDMA_ALT_SELECT].ui32Spare;
300 }
301 // Not a scatter-gather transfer, calculate end pointer normally.
302 else
303 {
304 ui32Inc = ui32Inc >> UDMA_DST_INC_S;
305 ui32BufferBytes = ui32TransferSize << ui32Inc;
306 pvDstAddr = (void *)((uint32_t)pvDstAddr + ui32BufferBytes - 1);
307 }
308 }
309
310 // Load the destination ending address into the control block.
311 pControlTable[ui32ChannelStructIndex].pvDstEndAddr = pvDstAddr;
312
313 // Write the new control word value.
314 pControlTable[ui32ChannelStructIndex].ui32Control = ui32Control;
315 }
316
317 //*****************************************************************************
318 //
319 // Configures a uDMA channel for scatter-gather mode
320 //
321 //*****************************************************************************
322 void
uDMAChannelScatterGatherSet(uint32_t ui32Base,uint32_t ui32ChannelNum,uint32_t ui32TaskCount,void * pvTaskList,uint32_t ui32IsPeriphSG)323 uDMAChannelScatterGatherSet(uint32_t ui32Base, uint32_t ui32ChannelNum,
324 uint32_t ui32TaskCount, void *pvTaskList,
325 uint32_t ui32IsPeriphSG)
326 {
327 tDMAControlTable *pControlTable;
328 tDMAControlTable *pTaskTable;
329
330 // Check the parameters.
331 ASSERT(uDMABaseValid(ui32Base));
332 ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
333 ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
334 ASSERT(pvTaskList != 0);
335 ASSERT(ui32TaskCount <= UDMA_XFER_SIZE_MAX);
336 ASSERT(ui32TaskCount != 0);
337
338 // Get the base address of the control table.
339 pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
340
341 // Get a handy pointer to the task list.
342 pTaskTable = (tDMAControlTable *)pvTaskList;
343
344 // Compute the ending address for the source pointer. This will be the
345 // last element of the last task in the task table.
346 pControlTable[ui32ChannelNum].pvSrcEndAddr =
347 &pTaskTable[ui32TaskCount - 1].ui32Spare;
348
349 // Compute the ending address for the destination pointer. This will be
350 // the end of the alternate structure for this channel.
351 pControlTable[ui32ChannelNum].pvDstEndAddr =
352 &pControlTable[ui32ChannelNum | UDMA_ALT_SELECT].ui32Spare;
353
354 // Compute the control word. Most configurable items are fixed for
355 // scatter-gather. Item and increment sizes are all 32-bit and arb
356 // size must be 4. The count is the number of items in the task list
357 // times 4 (4 words per task).
358 pControlTable[ui32ChannelNum].ui32Control =
359 (UDMA_DST_INC_32 | UDMA_SRC_INC_32 |
360 UDMA_SIZE_32 | UDMA_ARB_4 |
361 (((ui32TaskCount * 4) - 1) << UDMA_XFER_SIZE_S) |
362 (ui32IsPeriphSG ? UDMA_MODE_PER_SCATTER_GATHER :
363 UDMA_MODE_MEM_SCATTER_GATHER));
364
365 // Scatter-gather operations can leave the alt bit set. So if doing
366 // back to back scatter-gather transfers, the second attempt may not
367 // work correctly because the alt bit is set. Therefore, clear the
368 // alt bit here to ensure that it is always cleared before a new SG
369 // transfer is started.
370 HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
371
372 }
373
374 //*****************************************************************************
375 //
376 // Gets the current transfer size for a uDMA channel control structure
377 //
378 //*****************************************************************************
379 uint32_t
uDMAChannelSizeGet(uint32_t ui32Base,uint32_t ui32ChannelStructIndex)380 uDMAChannelSizeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex)
381 {
382 tDMAControlTable *pControlTable;
383 uint32_t ui32Control;
384
385 // Check the arguments.
386 ASSERT(uDMABaseValid(ui32Base));
387 ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
388 ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
389
390 // Get the base address of the control table.
391 pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
392
393 // Get the current control word value and mask off all but the size field
394 // and the mode field.
395 ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
396 (UDMA_XFER_SIZE_M | UDMA_MODE_M));
397
398 // If the size field and mode field are 0 then the transfer is finished
399 // and there are no more items to transfer.
400 if(ui32Control == 0)
401 {
402 return(0);
403 }
404
405 // Otherwise, if either the size field or more field is non-zero, then
406 // not all the items have been transferred.
407 else
408 {
409 // Shift the size field and add one, then return to user.
410 return((ui32Control >> UDMA_XFER_SIZE_S) + 1);
411 }
412 }
413
414 //*****************************************************************************
415 //
416 // Gets the transfer mode for a uDMA channel control structure
417 //
418 //*****************************************************************************
419 uint32_t
uDMAChannelModeGet(uint32_t ui32Base,uint32_t ui32ChannelStructIndex)420 uDMAChannelModeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex)
421 {
422 tDMAControlTable *pControlTable;
423 uint32_t ui32Control;
424
425 // Check the arguments.
426 ASSERT(uDMABaseValid(ui32Base));
427 ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
428 ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
429
430 // Get the base address of the control table.
431 pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
432
433 // Get the current control word value and mask off all but the mode field.
434 ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
435 UDMA_MODE_M);
436
437 // Check if scatter/gather mode, and if so, mask off the alt bit.
438 if(((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_MEM_SCATTER_GATHER) ||
439 ((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_PER_SCATTER_GATHER))
440 {
441 ui32Control &= ~UDMA_MODE_ALT_SELECT;
442 }
443
444 // Return the mode to the caller.
445 return(ui32Control);
446 }
447