Files

443 lines
21 KiB
C

/*
* SPDX-FileCopyrightText: 2023-2024 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 <stdbool.h>
#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 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: Force end an in-flight transaction successfully
* - 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