/* * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ // DO NOT USE THESE APIS IN ANY APPLICATIONS // DMA2D driver is not public for end users, but for ESP-IDF developers. #pragma once #include #include "esp_err.h" #include "hal/dma2d_types.h" #ifdef __cplusplus extern "C" { #endif /** * @brief Type of 2D-DMA pool handle */ typedef struct dma2d_group_t *dma2d_pool_handle_t; /** * @brief Type of 2D-DMA transaction context (queue element) */ typedef struct dma2d_trans_s dma2d_trans_t; /** * @brief Helper macro to get the size for struct `dma2d_trans_t` */ #define SIZEOF_DMA2D_TRANS_T dma2d_get_trans_elm_size() /** * @brief Get the size for struct `dma2d_trans_t` * * @return size_t Size of struct `dma2d_trans_t` */ size_t dma2d_get_trans_elm_size(void); /** * @brief A collection of configuration items that used for allocating a 2D-DMA pool */ typedef struct { uint32_t pool_id; /*!< The ID number of the 2D-DMA pool to allocate */ uint32_t intr_priority; /*!< 2D-DMA interrupt priority, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ } dma2d_pool_config_t; /** * @brief Acquire a 2D-DMA pool * * @param[in] config Pointer to a collection of configurations for the 2D-DMA pool * @param[out] ret_pool Returned pool handle * @return * - ESP_OK: Acquire the 2D-DMA pool successfully * - ESP_ERR_INVALID_ARG: Acquire the 2D-DMA pool failed because of invalid argument * - ESP_ERR_NO_MEM: Acquire the 2D-DMA pool failed because out of memory * - ESP_FAIL: Acquire the 2D-DMA pool failed because of other error */ esp_err_t dma2d_acquire_pool(const dma2d_pool_config_t *config, dma2d_pool_handle_t *ret_pool); /** * @brief Release a 2D-DMA pool * * @warning Upper driver should make sure there is no pending transaction (enqueued by the driver, but haven't be * processed) before calling this function. * * @param[in] dma2d_pool 2D-DMA pool handle, allocated by `dma2d_acquire_pool` * @return * - ESP_OK: Release the 2D-DMA pool successfully * - ESP_ERR_INVALID_ARG: Release the 2D-DMA pool failed because of invalid argument * - ESP_ERR_NOT_ALLOWED: Release the 2D-DMA pool failed because there is pending transactions in the pool, * pool can not be destroyed */ esp_err_t dma2d_release_pool(dma2d_pool_handle_t dma2d_pool); /** * @brief Type of 2D-DMA channel handle */ typedef struct dma2d_channel_t *dma2d_channel_handle_t; /** * @brief Struct to save the necessary information of a 2D-DMA channel for upper drivers to configure the channels */ typedef struct { dma2d_channel_direction_t dir; /*!< Direction of the DMA channel */ dma2d_channel_handle_t chan; /*!< Handle of the DMA channel */ } dma2d_trans_channel_info_t; /** * @brief Callback function to start a 2D-DMA transaction. This callback is being called when all necessary channels to * do the transaction have been acquired. * * Inside this function, usually configure the DMA channels, and then call `dma2d_start` to start the transaction. * * @note This function could run in current thread, or in other threads, or in ISR context (needs to follow ISR rules!) * * @param[in] num_chans Number of DMA channels acquired for the transaction * @param[in] dma2d_chans List of the channels acquired * @param[in] user_config User registered data (usually dma channel configurations) from `dma2d_trans_config_t::user_config` which is passed into `dma2d_enqueue` * * @return Whether a task switch is needed after the callback function returns, * this is usually due to the callback wakes up some high priority task. */ typedef bool (*dma2d_trans_on_picked_callback_t)(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); /** * @brief 2D-DMA channel special function flags * * These flags are supposed to be used to specify the 2D-DMA channel requirements for a transaction. */ #define DMA2D_CHANNEL_FUNCTION_FLAG_TX_REORDER (1 << 0) /*!< TX channel that has reorder functionality */ #define DMA2D_CHANNEL_FUNCTION_FLAG_RX_REORDER (1 << 1) /*!< RX channel that has reorder functionality */ #define DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC (1 << 2) /*!< TX channel that has color space conversion functionality */ #define DMA2D_CHANNEL_FUNCTION_FLAG_RX_CSC (1 << 3) /*!< RX channel that has color space conversion functionality */ #define DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING (1 << 4) /*!< TX and RX channel with same channel ID */ /** * @brief A collection of configuration items for a 2D-DMA transaction */ typedef struct { uint32_t tx_channel_num; /*!< Number of 2D-DMA TX channels required */ uint32_t rx_channel_num; /*!< Number of 2D-DMA RX channels required */ // Special function requirements for channels uint32_t channel_flags; /*!< Bitwise OR of `DMA2D_CHANNEL_FUNCTION_FLAG_*` flags indicating the required functions on the channels for the transaction */ // Specified to use reserved channels uint32_t specified_tx_channel_mask; /*!< Bit mask of the specific TX channels to be used, the specified TX channels should have been reserved */ uint32_t specified_rx_channel_mask; /*!< Bit mask of the specific RX channels to be used, the specified RX channels should have been reserved */ dma2d_trans_on_picked_callback_t on_job_picked; /*!< Callback function to be called when all necessary channels to do the transaction have been acquired */ void *user_config; /*!< User registered data to be passed into `on_job_picked` callback */ } dma2d_trans_config_t; /** * @brief Enqueue a 2D-DMA transaction to be picked up by a certain 2D-DMA pool * * @param[in] dma2d_pool 2D-DMA pool handle, allocated by `dma2d_acquire_pool` * @param[in] trans_desc Pointer to a collection of configurations for a transaction * The context must exist at least until `on_job_picked` callback function is called. * @param[in] trans_placeholder Address to the memory for storing this transaction context * Caller must malloc a placeholder for storing the 2D-DMA transaction, and pass it into the function. * Size of the placeholder can be get from `SIZEOF_DMA2D_TRANS_T` macro. * Freeing the 2D-DMA transaction placeholder should also be taken care by the upper driver. * It can be freed when `on_job_picked` callback function is called or anytime later. * @return * - ESP_OK: Enqueue the 2D-DMA transaction successfully * - ESP_ERR_INVALID_ARG: Enqueue the 2D-DMA transaction failed because of invalid argument */ esp_err_t dma2d_enqueue(dma2d_pool_handle_t dma2d_pool, const dma2d_trans_config_t *trans_desc, dma2d_trans_t *trans_placeholder); /** * @brief Dequeue a pending 2D-DMA transaction from a 2D-DMA pool * * Remove a transaction that was previously enqueued by `dma2d_enqueue` but has not yet been picked up for * processing (i.e. it is still waiting in the pool's pending queue). This is useful when the upper driver wants * to cancel a transaction that has not started yet. * * @note This API only operates on transactions that are still pending. To end a transaction that is already * in-flight (its channels have been acquired), use `dma2d_force_end` instead. * * @note After this function returns ESP_OK, the upper driver can safely free the transaction placeholder, as the * `on_job_picked` callback of the transaction will no longer be called. * * @param[in] dma2d_pool 2D-DMA pool handle, allocated by `dma2d_acquire_pool` * @param[in] trans Pointer to the 2D-DMA transaction context * @return * - ESP_OK: Dequeue the pending 2D-DMA transaction successfully * - ESP_ERR_INVALID_ARG: Dequeue failed because of invalid argument * - ESP_ERR_NOT_FOUND: The transaction is not in the pending queue, because it has already been picked up * for processing or it was never enqueued to this pool */ esp_err_t dma2d_dequeue(dma2d_pool_handle_t dma2d_pool, dma2d_trans_t *trans); /** * @brief Force end an in-flight 2D-DMA transaction * * This API is useful when the error was caused by the DMA consumer (such as JPEG). The error can only be detected * by the consumer module, and the error info will only be propagated to the consumer driver. The 2D-DMA channels being * involved to transfer the data has no way to be informed about the error at its upstream, it will keep waiting for * the data. * * Therefore, when the consumer driver is doing the error handling, it is required to call this API to end the on-going * transaction and release the taken TX and RX channels. It will stop and free the TX and RX channels that are bundled * together to process the transaction. * * @param[in] trans Pointer to the 2D-DMA transaction context * @param[out] need_yield Pointer to a status flag to record whether a task switch is needed if this API is being called in an ISR * @return * - ESP_OK: The transaction has been ended (either force-ended by this call, or it had already completed) * - ESP_ERR_INVALID_ARG: Force end failed because of invalid argument * - ESP_ERR_INVALID_STATE: Force end failed because the transaction is not yet in-flight */ esp_err_t dma2d_force_end(dma2d_trans_t *trans, bool *need_yield); /*********************************************** DMA CHANNEL OPERATIONS ***********************************************/ /** * @brief Type of 2D-DMA engine trigger */ typedef struct { dma2d_trigger_peripheral_t periph; /*!< Target peripheral which will trigger DMA operations */ int periph_sel_id; /*!< Peripheral selection ID. Supported IDs are listed in `soc/dma2d_channel.h` */ } dma2d_trigger_t; /** * @brief Connect 2D-DMA channel to trigger peripheral, and configure all other channel settings to a certain state (the channel will be reset first) * * Usually only to be called in `on_job_picked` callback, and is the first step to do inside the callback, since it resets other configurations to a default mode. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] trig_periph 2D-DMA trigger peripheral * @return * - ESP_OK: Connect 2D-DMA channel successfully * - ESP_ERR_INVALID_ARG: Connect 2D-DMA channel failed because of invalid argument */ esp_err_t dma2d_connect(dma2d_channel_handle_t dma2d_chan, const dma2d_trigger_t *trig_periph); /** * @brief A collection of strategy items that each 2D-DMA channel could apply */ typedef struct { bool owner_check; /*!< If set / clear, DMA channel enables / disables checking owner validity */ bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */ bool eof_till_data_popped; /*!< If set, EOF flag is generated until the data needs to read has been popped from the DMA FIFO (TX channel only) */ } dma2d_strategy_config_t; /** * @brief Apply channel strategy for 2D-DMA channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] config Configuration of 2D-DMA channel strategy * @return * - ESP_OK: Apply channel strategy successfully * - ESP_ERR_INVALID_ARG: Apply channel strategy failed because of invalid argument */ esp_err_t dma2d_apply_strategy(dma2d_channel_handle_t dma2d_chan, const dma2d_strategy_config_t *config); /** * @brief A collection of transfer ability items that each 2D-DMA channel could apply to improve transfer efficiency * * @note The 2D-DMA driver has no knowledge about the DMA buffer (address and size) used by upper layer. * So it's the responsibility of the **upper layer** to take care of the buffer address and size. * Usually RX buffer at least requires 4-byte alignment to avoid overwriting other data by DMA write PSRAM process * or its data being overwritten. */ typedef struct { bool desc_burst_en; /*!< If set / clear, DMA channel enables / disables burst reading descriptor link */ uint32_t data_burst_length; /*!< Configure the DMA channel burst reading data length */ bool access_ext_mem; /*!< Set this bit if the DMA transfer may access external memory */ dma2d_macro_block_size_t mb_size; /*!< Configure the DMA channel macro block size (only useful in DMA2D_DESCRIPTOR_BLOCK_RW_MODE_MULTIPLE mode) */ } dma2d_transfer_ability_t; /** * @brief Configure 2D-DMA channel transfer ability for transfer efficiency * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] ability Configuration of 2D-DMA channel transfer ability * @return * - ESP_OK: Set channel transfer ability successfully * - ESP_ERR_INVALID_ARG: Set channel transfer ability failed because of invalid argument */ esp_err_t dma2d_set_transfer_ability(dma2d_channel_handle_t dma2d_chan, const dma2d_transfer_ability_t *ability); /** * @brief A collection of color space conversion (CSC) items that each 2D-DMA channel could apply */ typedef struct { union { dma2d_csc_tx_option_t tx_csc_option; /*!< TX direction (into DMA) pixel format conversion option */ dma2d_csc_rx_option_t rx_csc_option; /*!< RX direction (out from DMA) pixel format conversion option */ }; dma2d_scramble_order_t pre_scramble; /*!< DMA channel data scramble order before color conversion */ dma2d_scramble_order_t post_scramble; /*!< DMA channel data scramble order after color conversion (only available for RX channels) */ } dma2d_csc_config_t; /** * @brief Configure color space conversion setting for 2D-DMA channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] config Configuration of 2D-DMA channel color space conversion * @return * - ESP_OK: Configure DMA color space conversion successfully * - ESP_ERR_INVALID_ARG: Configure DMA color space conversion failed because of invalid argument */ esp_err_t dma2d_configure_color_space_conversion(dma2d_channel_handle_t dma2d_chan, const dma2d_csc_config_t *config); /** * @brief A collection of configurations apply to 2D-DMA channel DSCR-PORT mode */ typedef struct { uint32_t block_h; /*!< Horizontal width of the block in dscr-port mode (unit: pixel) */ uint32_t block_v; /*!< Vertical height of the block in dscr-port mode (unit: pixel) */ } dma2d_dscr_port_mode_config_t; /** * @brief Configure 2D-DMA channel DSCR-PORT mode * * @note This API only targets PPA SRM, which uses 2D-DMA DSCR-PORT mode. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] config Configuration of 2D-DMA channel DSCR-PORT mode * @return * - ESP_OK: Configure 2D-DMA dscr-port mode successfully * - ESP_ERR_INVALID_ARG: Configure 2D-DMA dscr-port mode failed because of invalid argument */ esp_err_t dma2d_configure_dscr_port_mode(dma2d_channel_handle_t dma2d_chan, const dma2d_dscr_port_mode_config_t *config); /** * @brief Type of 2D-DMA event data */ typedef struct { union { intptr_t rx_eof_desc_addr; /*!< EOF descriptor address of RX channel */ intptr_t tx_eof_desc_addr; /*!< EOF descriptor address of TX channel */ }; dma2d_trans_t *transaction; /*!< Pointer to the transaction context processed */ } dma2d_event_data_t; /** * @brief Type of 2D-DMA event callback * * @param dma2d_chan 2D-DMA channel handle. Depends on the callback events, sometimes will pass NULL to this parameter. * @param event_data 2D-DMA event data * @param user_data User registered data from `dma2d_register_tx/rx_event_callbacks` * * @return Whether a task switch is needed after the callback function returns, * this is usually due to the callback wakes up some high priority task. */ typedef bool (*dma2d_event_callback_t)(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data); /** * @brief Group of supported 2D-DMA TX callbacks * @note The callbacks are all running under ISR environment */ typedef struct { dma2d_event_callback_t on_desc_done; /*!< Invoked when TX engine completes processing all data in a descriptor. When TX_DONE interrupt gets triggered but not EOF, it is considered to be still in the middle of a complete transaction (partially done), you are allowed to configure 2D-DMA channel hardware/descriptor in this callback, and let the channels start running again */ } dma2d_tx_event_callbacks_t; /** * @brief Group of supported 2D-DMA RX callbacks * @note The callbacks are all running under ISR environment * * Users should be clear on the unique responsibility of each callback when writing the callback functions, such as * where to free the transaction memory. */ typedef struct { dma2d_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor. Note that in this callback, RX channel handle will not be given. This is because at the moment of `on_recv_eof` callback is called, the channels are returned to the pool and may have already been used to start another new transaction */ dma2d_event_callback_t on_desc_done; /*!< Invoked when RX engine completes processing all data in a descriptor. When RX_DONE interrupt gets triggered but not EOF, it is considered to be still in the middle of a complete transaction (partially done), you are allowed to configure 2D-DMA channel hardware/descriptor in this callback, and let the channels start running again */ dma2d_event_callback_t on_desc_empty; /*!< Invoked when the buffer size pointed to by the received linked list descriptor is less than the length of the data to be received */ } dma2d_rx_event_callbacks_t; /** * @brief Set 2D-DMA event callbacks for TX channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA TX channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly * @return * - ESP_OK: Set event callbacks successfully * - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument */ esp_err_t dma2d_register_tx_event_callbacks(dma2d_channel_handle_t dma2d_chan, dma2d_tx_event_callbacks_t *cbs, void *user_data); /** * @brief Set 2D-DMA event callbacks for RX channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA RX channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly * @return * - ESP_OK: Set event callbacks successfully * - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument */ esp_err_t dma2d_register_rx_event_callbacks(dma2d_channel_handle_t dma2d_chan, dma2d_rx_event_callbacks_t *cbs, void *user_data); /** * @brief Set descriptor address for 2D-DMA channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @param[in] desc_base_addr Base address of descriptors * @return * - ESP_OK: Set 2D-DMA descriptor addr successfully * - ESP_ERR_INVALID_ARG: Set 2D-DMA descriptor addr failed because of invalid argument */ esp_err_t dma2d_set_desc_addr(dma2d_channel_handle_t dma2d_chan, intptr_t desc_base_addr); /** * @brief Start engine for 2D-DMA channel * * Usually only to be called in `on_job_picked` callback. * * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` * @return * - ESP_OK: Start 2D-DMA engine successfully * - ESP_ERR_INVALID_ARG: Start 2D-DMA engine failed because of invalid argument */ esp_err_t dma2d_start(dma2d_channel_handle_t dma2d_chan); /** * @brief Stop engine for 2D-DMA channel * * Usually to be called in ISR context. * * @param[in] dma2d_chan 2D-DMA channel handle * @return * - ESP_OK: Stop 2D-DMA engine successfully * - ESP_ERR_INVALID_ARG: Stop 2D-DMA engine failed because of invalid argument */ esp_err_t dma2d_stop(dma2d_channel_handle_t dma2d_chan); /** * @brief Make the appended descriptors be aware to the 2D-DMA engine * * Usually to be called in ISR context. * * @param[in] dma2d_chan 2D-DMA channel handle * @return * - ESP_OK: Send append command to 2D-DMA engine successfully * - ESP_ERR_INVALID_ARG: Send append command to 2D-DMA engine failed because of invalid argument */ esp_err_t dma2d_append(dma2d_channel_handle_t dma2d_chan); /** * @brief Reset engine for 2D-DMA channel * * Usually to be called in ISR context. * * @param[in] dma2d_chan 2D-DMA channel handle * @return * - ESP_OK: Reset 2D-DMA engine successfully * - ESP_ERR_INVALID_ARG: Reset 2D-DMA engine failed because of invalid argument */ esp_err_t dma2d_reset(dma2d_channel_handle_t dma2d_chan); #ifdef __cplusplus } #endif