1 /* 2 * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // DO NOT USE THESE APIS IN ANY APPLICATIONS 8 // GDMA driver is not public for end users, but for ESP-IDF developers. 9 10 #pragma once 11 12 #include <stdbool.h> 13 #include "esp_etm.h" 14 #include "soc/gdma_channel.h" 15 #include "hal/gdma_types.h" 16 #include "esp_err.h" 17 18 #ifdef __cplusplus 19 extern "C" { 20 #endif 21 22 /** 23 * @brief Type of GDMA channel handle 24 * 25 */ 26 typedef struct gdma_channel_t *gdma_channel_handle_t; 27 28 /** 29 * @brief Collection of configuration items that used for allocating GDMA channel 30 * 31 */ 32 typedef struct { 33 gdma_channel_handle_t sibling_chan; /*!< DMA sibling channel handle (NULL means having sibling is not necessary) */ 34 gdma_channel_direction_t direction; /*!< DMA channel direction */ 35 struct { 36 int reserve_sibling: 1; /*!< If set, DMA channel allocator would prefer to allocate new channel in a new pair, and reserve sibling channel for future use */ 37 } flags; 38 } gdma_channel_alloc_config_t; 39 40 /** 41 * @brief GDMA transfer ability 42 * 43 * @note The alignment set in this structure is **not** a guarantee that gdma driver will take care of the nonalignment cases. 44 * Actually the GDMA driver has no knowledge about the DMA buffer (address and size) used by upper layer. 45 * So it's the responsibility of the **upper layer** to take care of the buffer address and size. 46 * 47 */ 48 typedef struct { 49 size_t sram_trans_align; /*!< DMA transfer alignment for memory in SRAM, in bytes. The driver enables/disables burst mode based on this value. 0 means no alignment is required */ 50 size_t psram_trans_align; /*!< DMA transfer alignment for memory in PSRAM, in bytes. The driver sets proper burst block size based on the alignment value. 0 means no alignment is required */ 51 } gdma_transfer_ability_t; 52 53 /** 54 * @brief Type of GDMA event data 55 * 56 */ 57 typedef struct { 58 union { 59 intptr_t rx_eof_desc_addr; /*!< EOF descriptor address of RX channel */ 60 intptr_t tx_eof_desc_addr; /*!< EOF descriptor address of TX channel */ 61 }; 62 } gdma_event_data_t; 63 64 /** 65 * @brief Type of GDMA event callback 66 * @param dma_chan GDMA channel handle, created from `gdma_new_channel` 67 * @param event_data GDMA event data 68 * @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks` 69 * 70 * @return Whether a task switch is needed after the callback function returns, 71 * this is usually due to the callback wakes up some high priority task. 72 * 73 */ 74 typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); 75 76 /** 77 * @brief Group of supported GDMA TX callbacks 78 * @note The callbacks are all running under ISR environment 79 * 80 */ 81 typedef struct { 82 gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */ 83 } gdma_tx_event_callbacks_t; 84 85 /** 86 * @brief Group of supported GDMA RX callbacks 87 * @note The callbacks are all running under ISR environment 88 * 89 */ 90 typedef struct { 91 gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */ 92 } gdma_rx_event_callbacks_t; 93 94 /** 95 * @brief Type of GDMA engine trigger 96 * @note It's recommended to initialize this structure with `GDMA_MAKE_TRIGGER`. 97 * 98 */ 99 typedef struct { 100 gdma_trigger_peripheral_t periph; /*!< Target peripheral which will trigger DMA operations */ 101 int instance_id; /*!< Peripheral instance ID. Supported IDs are listed in `soc/gdma_channel.h`, e.g. SOC_GDMA_TRIG_PERIPH_UHCI0 */ 102 } gdma_trigger_t; 103 104 /** 105 * @brief Helper macro to initialize GDMA trigger 106 * @note value of `peri` must be selected from `gdma_trigger_peripheral_t` enum. 107 * e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I2S,0) 108 * 109 */ 110 #define GDMA_MAKE_TRIGGER(peri, id) \ 111 (gdma_trigger_t) { .periph = peri, .instance_id = SOC_##peri##id } 112 113 /** 114 * @brief A collection of strategy item that each GDMA channel could apply 115 * 116 */ 117 typedef struct { 118 bool owner_check; /*!< If set / clear, DMA channel enables / disables checking owner validity */ 119 bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */ 120 } gdma_strategy_config_t; 121 122 /** 123 * @brief Create GDMA channel 124 * @note This API won't install interrupt service for the allocated channel. 125 * If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`. 126 * 127 * @param[in] config Pointer to a collection of configurations for allocating GDMA channel 128 * @param[out] ret_chan Returnned channel handle 129 * @return 130 * - ESP_OK: Create DMA channel successfully 131 * - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument 132 * - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory 133 * - ESP_FAIL: Create DMA channel failed because of other error 134 */ 135 esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan); 136 137 /** 138 * @brief Connect GDMA channel to trigger peripheral 139 * 140 * @note Suggest to use helper macro `GDMA_MAKE_TRIGGER` to construct parameter `trig_periph`. e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA,0) 141 * @note Connecting to a peripheral will also reset the DMA FIFO and FSM automatically 142 * 143 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 144 * @param[in] trig_periph GDMA trigger peripheral 145 * @return 146 * - ESP_OK: Connect GDMA channel successfully 147 * - ESP_ERR_INVALID_ARG: Connect GDMA channel failed because of invalid argument 148 * - ESP_ERR_INVALID_STATE: Connect GDMA channel failed because DMA channel is working with another peripheral 149 * - ESP_FAIL: Connect GDMA channel failed because of other error 150 */ 151 esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_periph); 152 153 /** 154 * @brief Disconnect GMA channel from peripheral 155 * 156 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 157 * @return 158 * - ESP_OK: Disconnect GDMA channel successfully 159 * - ESP_ERR_INVALID_ARG: Disconnect GDMA channel failed because of invalid argument 160 * - ESP_ERR_INVALID_STATE: Disconnect GDMA channel failed because DMA channel is not connected to any peripheral 161 * - ESP_FAIL: Disconnect DMA channel failed because of other error 162 */ 163 esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan); 164 165 /** 166 * @brief Set DMA channel transfer ability 167 * 168 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 169 * @param[in] ability Transfer ability, e.g. alignment 170 * @return 171 * - ESP_OK: Set DMA channel transfer ability successfully 172 * - ESP_ERR_INVALID_ARG: Set DMA channel transfer ability failed because of invalid argument 173 * - ESP_FAIL: Set DMA channel transfer ability failed because of other error 174 */ 175 esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability); 176 177 /** 178 * @brief Apply channel strategy for GDMA channel 179 * 180 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 181 * @param[in] config Configuration of GDMA channel strategy 182 * - ESP_OK: Apply channel strategy successfully 183 * - ESP_ERR_INVALID_ARG: Apply channel strategy failed because of invalid argument 184 * - ESP_FAIL: Apply channel strategy failed because of other error 185 */ 186 esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config); 187 188 /** 189 * @brief Set GDMA channel priority 190 * 191 * @note By default, all GDMA channels are with the same priority: 0. Channels with the same priority are served in round-robin manner. 192 * 193 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 194 * @param[in] priority Priority of GDMA channel, higher value means higher priority 195 * @return 196 * - ESP_OK: Set GDMA channel priority successfully 197 * - ESP_ERR_INVALID_ARG: Set GDMA channel priority failed because of invalid argument, e.g. priority out of range [0,GDMA_LL_CHANNEL_MAX_PRIORITY] 198 * - ESP_FAIL: Set GDMA channel priority failed because of other error 199 */ 200 esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority); 201 202 /** 203 * @brief Delete GDMA channel 204 * @note If you call `gdma_new_channel` several times for a same peripheral, make sure you call this API the same times. 205 * 206 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 207 * @return 208 * - ESP_OK: Delete GDMA channel successfully 209 * - ESP_ERR_INVALID_ARG: Delete GDMA channel failed because of invalid argument 210 * - ESP_FAIL: Delete GDMA channel failed because of other error 211 */ 212 esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan); 213 214 /** 215 * @brief Get the channel ID 216 * 217 * @note This API breaks the encapsulation of GDMA Channel Object. 218 * With the returned channel ID, you can even bypass all other GDMA driver API and access Low Level API directly. 219 * 220 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 221 * @param[out] channel_id Returned channel ID 222 * @return 223 * - ESP_OK: Get GDMA channel ID successfully 224 * - ESP_ERR_INVALID_ARG: Get GDMA channel ID failed because of invalid argument 225 * - ESP_FAIL: Get GDMA channel ID failed because of other error 226 */ 227 esp_err_t gdma_get_channel_id(gdma_channel_handle_t dma_chan, int *channel_id); 228 229 /** 230 * @brief Set GDMA event callbacks for TX channel 231 * @note This API will install GDMA interrupt service for the channel internally 232 * 233 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 234 * @param[in] cbs Group of callback functions 235 * @param[in] user_data User data, which will be passed to callback functions directly 236 * @return 237 * - ESP_OK: Set event callbacks successfully 238 * - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument 239 * - ESP_FAIL: Set event callbacks failed because of other error 240 */ 241 esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data); 242 243 /** 244 * @brief Set GDMA event callbacks for RX channel 245 * @note This API will install GDMA interrupt service for the channel internally 246 * 247 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 248 * @param[in] cbs Group of callback functions 249 * @param[in] user_data User data, which will be passed to callback functions directly 250 * @return 251 * - ESP_OK: Set event callbacks successfully 252 * - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument 253 * - ESP_FAIL: Set event callbacks failed because of other error 254 */ 255 esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_rx_event_callbacks_t *cbs, void *user_data); 256 257 /** 258 * @brief Set DMA descriptor address and start engine 259 * 260 * @note This function is allowed to run within ISR context 261 * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled 262 * 263 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 264 * @param[in] desc_base_addr Base address of descriptors (usually the descriptors are chained into a link or ring) 265 * @return 266 * - ESP_OK: Start DMA engine successfully 267 * - ESP_ERR_INVALID_ARG: Start DMA engine failed because of invalid argument 268 * - ESP_ERR_INVALID_STATE: Start DMA engine failed because of invalid state, e.g. the channel is controlled by ETM, so can't start it manually 269 * - ESP_FAIL: Start DMA engine failed because of other error 270 */ 271 esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr); 272 273 /** 274 * @brief Stop DMA engine 275 * 276 * @note This function is allowed to run within ISR context 277 * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled 278 * 279 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 280 * @return 281 * - ESP_OK: Stop DMA engine successfully 282 * - ESP_ERR_INVALID_ARG: Stop DMA engine failed because of invalid argument 283 * - ESP_ERR_INVALID_STATE: Stop DMA engine failed because of invalid state, e.g. the channel is controlled by ETM, so can't stop it manually 284 * - ESP_FAIL: Stop DMA engine failed because of other error 285 */ 286 esp_err_t gdma_stop(gdma_channel_handle_t dma_chan); 287 288 /** 289 * @brief Make the appended descriptors be aware to the DMA engine 290 * 291 * @note This function is allowed to run within ISR context 292 * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled 293 * @note This API could also resume a paused DMA engine, make sure new descriptors have been appended to the descriptor chain before calling it. 294 * 295 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 296 * @return 297 * - ESP_OK: Send append command to DMA engine successfully 298 * - ESP_ERR_INVALID_ARG: Send append command to DMA engine failed because of invalid argument 299 * - ESP_FAIL: Send append command to DMA engine failed because of other error 300 */ 301 esp_err_t gdma_append(gdma_channel_handle_t dma_chan); 302 303 /** 304 * @brief Reset DMA channel FIFO and internal finite state machine 305 * 306 * @note This function is allowed to run within ISR context 307 * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled 308 * @note Resetting a DMA channel won't break the connection with the target peripheral 309 * 310 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 311 * @return 312 * - ESP_OK: DMA channel reset successfully 313 * - ESP_ERR_INVALID_ARG: DMA channel reset failed due to invalid arguments 314 * - ESP_FAIL: DMA channel reset failed due to other errors 315 */ 316 esp_err_t gdma_reset(gdma_channel_handle_t dma_chan); 317 318 /** 319 * @brief GDMA ETM event configuration 320 */ 321 typedef struct { 322 gdma_etm_event_type_t event_type; /*!< GDMA ETM event type */ 323 } gdma_etm_event_config_t; 324 325 /** 326 * @brief Get the ETM event for GDMA channel 327 * 328 * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` 329 * 330 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 331 * @param[in] config GDMA ETM event configuration 332 * @param[out] out_event Returned ETM event handle 333 * @return 334 * - ESP_OK: Get ETM event successfully 335 * - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument 336 * - ESP_ERR_NOT_SUPPORTED: Get ETM event failed because the GDMA hardware doesn't support ETM event 337 * - ESP_FAIL: Get ETM event failed because of other error 338 */ 339 esp_err_t gdma_new_etm_event(gdma_channel_handle_t dma_chan, const gdma_etm_event_config_t *config, esp_etm_event_handle_t *out_event); 340 341 /** 342 * @brief GDMA ETM task configuration 343 */ 344 typedef struct { 345 gdma_etm_task_type_t task_type; /*!< GDMA ETM task type */ 346 } gdma_etm_task_config_t; 347 348 /** 349 * @brief Get the ETM task for GDMA channel 350 * 351 * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` 352 * @note If the GDMA task (e.g. start/stop) is controlled by ETM, then you can't use `gdma_start`/`gdma_stop` to control it. 353 * 354 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 355 * @param[in] config GDMA ETM task configuration 356 * @param[out] out_task Returned ETM task handle 357 * @return 358 * - ESP_OK: Get ETM task successfully 359 * - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument 360 * - ESP_ERR_NOT_SUPPORTED: Get ETM task failed because the gdma hardware doesn't support ETM task 361 * - ESP_FAIL: Get ETM task failed because of other error 362 */ 363 esp_err_t gdma_new_etm_task(gdma_channel_handle_t dma_chan, const gdma_etm_task_config_t *config, esp_etm_task_handle_t *out_task); 364 365 /** 366 * @brief Get the mask of free M2M trigger IDs 367 * 368 * @note On some ESP targets (e.g. ESP32C3/S3), DMA trigger used for memory copy can be any of valid peripheral's trigger ID, 369 * which can bring conflict if the peripheral is also using the same trigger ID. This function can return the free IDs 370 * for memory copy, at the runtime. 371 * 372 * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` 373 * @param[out] mask Returned mask of free M2M trigger IDs 374 * @return 375 * - ESP_OK: Get free M2M trigger IDs successfully 376 * - ESP_ERR_INVALID_ARG: Get free M2M trigger IDs failed because of invalid argument 377 * - ESP_FAIL: Get free M2M trigger IDs failed because of other error 378 */ 379 esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_t *mask); 380 381 #ifdef __cplusplus 382 } 383 #endif 384