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