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