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