1 /*
2  * Copyright (c) 2022-2023, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /** ============================================================================
33  *  @file       UDMALPF3.h
34  *
35  *  @brief      UDMALPF3 driver implementation.
36  *
37  * # Driver include #
38  *  The UDMALPF3 header file should be included in an application as follows:
39  *  @code
40  *  #include <ti/drivers/dma/UDMALPF3.h>
41  *  @endcode
42  *
43  * # Overview #
44  * The UDMALPF3 driver currently only supports internal use by the drivers
45  * that use the uDMA peripheral (e.g., SPILPF3DMA).
46  * In other words, the application should never call any of the functions in this
47  * file.
48  *
49  * # General Behavior #
50  * This driver is used implicitly by other drivers (e.g., the SPILPF3DMA
51  * driver) so users should not have to interface to this driver from the
52  * application.
53  * The uDMA hardware makes use of a control table in RAM which must be 1024 bytes
54  * aligned. The default base address of this control table is 0x20000400, however
55  * this can be changed simply by defining UDMALPF3_CONFIG_BASE.
56  * The SPILPF3DMA.h supports SPI0, and uses both TX and RX DMA channels.
57  * Each control table entry is 16 bytes, so if an application uses SPI0
58  * the total RAM usage will be 2*16=32 bytes. Please see [Use cases] (@ref
59  * UDMA_23XX_USE_CASES) for example.
60  *
61  * # Error handling #
62  * Error handling is handled by the overlying driver which uses the DMA.
63  *
64  * # Power management #
65  * Power management is handled by the overlying driver which uses the DMA.
66  *
67  * # Supported functions #
68  * Note that these functions should never be called from the application, they
69  * are only called from other drivers. They are however included here for completeness:
70  *
71  * | API function             | Description                                    |
72  * |------------------------- |------------------------------------------------|
73  * | UDMALPF3_init()        | Initialize the uDMA HW.                        |
74  *
75  * @note These functions should not be called by code. These functions are called
76  *       by drivers using the DMA.
77  *
78  * # Unsupported Functionality #
79  * No known limitations
80  *
81  * # Use Cases @anchor UDMA_23XX_USE_CASES #
82  * In a system that has available SPI and UART peripherals, the following
83  * scenarios are possible:
84  * @code
85  * #define UDMALPF3_CONFIG_BASE 0x20000400
86  * @endcode
87  * - If only SPI0 is used (with TX mapped on channel 0 and RX mapped on channel
88  * 1), this will allocate 2*16=32 RAM bytes at address:\n
89  * [0x20000400-0x2000041F] = SPI0 RX/TX DMA channels
90  * - If only UART0 (with TX mapped on channel 2 and RX mapped on channel 3) is
91  * used, this will allocate 2*16=32 RAM bytes at address:\n
92  * [0x20000420-0x2000043F] = UART0 RX/TX DMA channels
93  * - If both SPI0 and UART0 are used, this will allocate 4*16=64 RAM bytes at addresses:\n
94  * [0x20000400-0x2000041F] = SPI0 RX/TX DMA channels\n
95  * [0x20000420-0x2000043F] = UART0 RX/TX DMA channels
96  *
97  * ============================================================================
98  */
99 
100 #ifndef ti_drivers_UDMALPF3__include
101 #define ti_drivers_UDMALPF3__include
102 
103 #include <stdint.h>
104 #include <stdbool.h>
105 
106 #include <ti/drivers/Power.h>
107 
108 #include <ti/devices/DeviceFamily.h>
109 #include DeviceFamily_constructPath(inc/hw_types.h)
110 #include DeviceFamily_constructPath(driverlib/udma.h)
111 
112 #ifdef __cplusplus
113 extern "C" {
114 #endif
115 
116 /*! Base address for the DMA control table, must be 1024 bytes aligned */
117 #if !defined(UDMALPF3_CONFIG_BASE)
118     #define UDMALPF3_CONFIG_BASE 0x20000400
119 #endif
120 
121 /*! Make sure DMA control table base address is 1024 bytes aligned */
122 #if (UDMALPF3_CONFIG_BASE & 0x3FF)
123     #error "Base address for DMA control table 'UDMALPF3_CONFIG_BASE' must be 1024 bytes aligned."
124 #endif
125 
126 /*! Compiler specific macros to allocate DMA control table entries */
127 #if defined(__IAR_SYSTEMS_ICC__)
128     #define ALLOCATE_CONTROL_TABLE_ENTRY(ENTRY_NAME, CHANNEL_INDEX)                               \
129         __no_init __root static volatile uDMAControlTableEntry ENTRY_NAME @UDMALPF3_CONFIG_BASE + \
130             (CHANNEL_INDEX) * sizeof(uDMAControlTableEntry)
131 #elif defined(__TI_COMPILER_VERSION__) || defined(__clang__)
132     #define ALLOCATE_CONTROL_TABLE_ENTRY(ENTRY_NAME, CHANNEL_INDEX) \
133         static volatile uDMAControlTableEntry ENTRY_NAME            \
134             __attribute__((retain,                                  \
135                            location((UDMALPF3_CONFIG_BASE) + (CHANNEL_INDEX) * sizeof(uDMAControlTableEntry))))
136 #elif defined(__GNUC__)
137     #define ALLOCATE_CONTROL_TABLE_ENTRY(ENTRY_NAME, CHANNEL_INDEX)                                          \
138         extern int UDMALPF3_##ENTRY_NAME##_is_placed;                                                        \
139         __attribute__((section("." #ENTRY_NAME), used)) static volatile uDMAControlTableEntry ENTRY_NAME = { \
140             &UDMALPF3_##ENTRY_NAME##_is_placed}
141 #else
142     #error "don't know how to define ALLOCATE_CONTROL_TABLE_ENTRY for this toolchain"
143 #endif
144 
145 /*! Sets the DMA transfer size in number of items */
146 #define UDMALPF3_SET_TRANSFER_SIZE(SIZE)    (((SIZE - 1) << UDMA_XFER_SIZE_S) & UDMA_XFER_SIZE_M)
147 /*! Gets the DMA transfer size in number of items*/
148 #define UDMALPF3_GET_TRANSFER_SIZE(CONTROL) (((CONTROL & UDMA_XFER_SIZE_M) >> UDMA_XFER_SIZE_S) + 1)
149 
150 /*!
151  *  @brief      UDMALPF3 Global configuration
152  */
153 typedef struct
154 {
155     uint32_t CtrlBaseAddr; /*!< Base address for UDMALPF3 control table */
156 } UDMALPF3_Config;
157 
158 /* Externs from ti_drivers_config.c */
159 extern const UDMALPF3_Config UDMALPF3_config;
160 
161 /*!
162  *  @brief  Function to initialize the LPF3 DMA driver and peripheral
163  *
164  *  The function will initialize the DMA peripheral and set the Control table
165  *  base address. The call powers up and clocks the DMA module only during
166  *  initialization. Each driver using DMA must set a power dependency
167  *  on the module before starting to use it (e.g. when opening the driver) and
168  *  release that dependency when DMA is no longer needed (e.g. when closing the
169  *  driver).
170  *
171  *  @pre    Calling context: Hwi, Swi, Task
172  *
173  *  @return none
174  *
175  *  @sa
176  */
177 extern void UDMALPF3_init(void);
178 
179 /*!
180  *  @internal
181  *  @brief  Function to enable the given DMA channel(s)
182  *
183  *  @pre    UDMALPF3_init() has to be called first.
184  *          Calling context: Hwi, Swi, Task
185  *
186  *  @param  channelBitMask  A bitmask of the channels to be enabled.
187  *
188  *  @sa     UDMALPF3_channelDisable
189  */
UDMALPF3_channelEnable(uint32_t channelBitMask)190 __STATIC_INLINE void UDMALPF3_channelEnable(uint32_t channelBitMask)
191 {
192     /* Enable DMA channel */
193     uDMAEnableChannel(channelBitMask);
194 }
195 
196 /*!
197  *  @internal
198  *  @brief  Function to check if a given DMA channel is done.
199  *
200  *  Will read the request done signal for the given channels
201  *  and return true if all channels are done, otherwise false.
202  *
203  *  @pre    UDMALPF3_init() has to be called first.
204  *          Calling context: Hwi, Swi, Task
205  *
206  *  @param  channelBitMask  A bitmask of the channels to be checked.
207  *
208  *  @return True if the channels are done, false otherwise.
209  *
210  *  @sa     UDMALPF3_channelDisable
211  */
UDMALPF3_channelDone(uint32_t channelBitMask)212 __STATIC_INLINE bool UDMALPF3_channelDone(uint32_t channelBitMask)
213 {
214     /* Check if REQDONE is set for the specified channels */
215     return (uDMAIntStatus() & channelBitMask) ? true : false;
216 }
217 
218 /*!
219  *  @internal
220  *  @brief  Function to clear a given DMA channel interrupt.
221  *
222  *  Will clear the DMA interrupt(s) for the given bitmask provided.
223  *
224  *  @pre    Calling context: Hwi, Swi, Task
225  *
226  *  @param  channelBitMask  A bitmask of the channels to clear interrupts for.
227  *
228  *  @return none
229  */
UDMALPF3_clearInterrupt(uint32_t channelBitMask)230 __STATIC_INLINE void UDMALPF3_clearInterrupt(uint32_t channelBitMask)
231 {
232     /* Clear UDMA done interrupt */
233     uDMAClearInt(channelBitMask);
234 }
235 
236 /*!
237  *  @internal
238  *  @brief  Function to disable one or more DMA channels.
239  *
240  *  Will disable the channel(s) for the given bitmask provided.
241  *
242  *  @pre    Calling context: Hwi, Swi, Task
243  *
244  *  @param  channelBitMask  A bitmask of the channels to be disabled.
245  *
246  *  @return none
247  *
248  *  @sa     UDMALPF3_channelEnable
249  */
UDMALPF3_channelDisable(uint32_t channelBitMask)250 __STATIC_INLINE void UDMALPF3_channelDisable(uint32_t channelBitMask)
251 {
252     /* Disable provided channels(s) */
253     uDMADisableChannel(channelBitMask);
254 }
255 
256 /*!
257  *  @internal
258  *  @brief  Function to disable a DMA channel's attributes.
259  *
260  *  Will disable a channel's attributes.
261  *
262  *  @pre    Calling context: Hwi, Swi, Task
263  *
264  *  @param  channelBitMask  A bitmask of the channels to configure.
265  *
266  *  @param  attr  Channel attribute to disable.
267  *
268  *
269  *  @return none
270  *
271  *  @sa     UDMALPF3_channelEnable
272  */
UDMALPF3_disableAttribute(uint32_t channelBitMask,uint32_t attr)273 __STATIC_INLINE void UDMALPF3_disableAttribute(uint32_t channelBitMask, uint32_t attr)
274 {
275     /* disable provided attribute for the given channel */
276     uDMADisableChannelAttribute(channelBitMask, attr);
277 }
278 
279 #ifdef __cplusplus
280 }
281 #endif
282 
283 #endif /* ti_drivers_UDMALPF3__include */
284