mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
Merge branch 'refactor/gdma_channel_allocator_both_direction_v6.0' into 'release/v6.0'
refactor(gdma): channel allocation can return both direction within the same call && Support ESP32-P4 ECO6 (v6.0) See merge request espressif/esp-idf!44870
This commit is contained in:
@@ -437,18 +437,9 @@ static void hci_driver_uart_dma_install(void)
|
||||
periph_module_enable(PERIPH_UHCI0_MODULE);
|
||||
periph_module_reset(PERIPH_UHCI0_MODULE);
|
||||
// install DMA driver
|
||||
gdma_channel_alloc_config_t tx_channel_config = {
|
||||
.flags.reserve_sibling = 1,
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
gdma_channel_alloc_config_t channel_config = {0};
|
||||
|
||||
ESP_ERROR_CHECK(gdma_new_ahb_channel(&tx_channel_config, &s_tx_channel));
|
||||
gdma_channel_alloc_config_t rx_channel_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = s_tx_channel,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(gdma_new_ahb_channel(&rx_channel_config, &s_rx_channel));
|
||||
ESP_ERROR_CHECK(gdma_new_ahb_channel(&channel_config, &s_tx_channel, &s_rx_channel));
|
||||
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
|
||||
gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
|
||||
gdma_strategy_config_t strategy_config = {
|
||||
|
||||
@@ -29,12 +29,11 @@ esp_err_t adc_dma_init(adc_dma_t *adc_dma)
|
||||
esp_err_t ret = ESP_OK;
|
||||
//alloc rx gdma channel
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ret = gdma_new_ahb_channel(&rx_alloc_config, &(adc_dma->gdma_chan));
|
||||
ret = gdma_new_ahb_channel(&rx_alloc_config, NULL, &(adc_dma->gdma_chan));
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -41,19 +41,19 @@ _Static_assert(offsetof(bitscrambler_loopback_t, bs) == 0, "bs needs to be 1st m
|
||||
static void bitscrambler_loopback_free(bitscrambler_loopback_t *bsl);
|
||||
static esp_err_t bitscrambler_loopback_cleanup(bitscrambler_handle_t bs, void* user_ctx);
|
||||
|
||||
static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *handle, int bus)
|
||||
static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *tx_handle, gdma_channel_handle_t *rx_handle, int bus)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
//Note that there are chips that do not have SOC_GDMA_BUS_* defined, but those chips also do
|
||||
//not have a BitScrambler.
|
||||
#ifdef SOC_GDMA_BUS_AHB
|
||||
if (bus == SOC_GDMA_BUS_AHB || bus == SOC_GDMA_BUS_ANY) {
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(cfg, handle), TAG, "alloc AHB DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(cfg, tx_handle, rx_handle), TAG, "alloc AHB DMA channel failed");
|
||||
}
|
||||
#endif
|
||||
#ifdef SOC_GDMA_BUS_AXI
|
||||
if (bus == SOC_GDMA_BUS_AXI) {
|
||||
ESP_RETURN_ON_ERROR(gdma_new_axi_channel(cfg, handle), TAG, "alloc AXI DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_axi_channel(cfg, tx_handle, rx_handle), TAG, "alloc AXI DMA channel failed");
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
@@ -115,16 +115,8 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach
|
||||
ESP_GOTO_ON_ERROR(gdma_new_link_list(&dma_link_cfg, &bs->rx_link_list), err, TAG, "failed to create RX link list");
|
||||
|
||||
// create TX channel and RX channel, they should reside in the same DMA pair
|
||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = 1,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(new_dma_channel(&tx_alloc_config, &bs->tx_channel, bus), err, TAG, "failed to create GDMA TX channel");
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = bs->tx_channel,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(new_dma_channel(&rx_alloc_config, &bs->rx_channel, bus), err, TAG, "failed to create GDMA RX channel");
|
||||
gdma_channel_alloc_config_t alloc_config = {0};
|
||||
ESP_GOTO_ON_ERROR(new_dma_channel(&alloc_config, &bs->tx_channel, &bs->rx_channel, bus), err, TAG, "failed to create GDMA channels");
|
||||
|
||||
gdma_connect(bs->rx_channel, g_bitscrambler_periph_desc[attach_to].dma_trigger);
|
||||
gdma_connect(bs->tx_channel, g_bitscrambler_periph_desc[attach_to].dma_trigger);
|
||||
|
||||
@@ -81,7 +81,6 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
|
||||
size_t alignment_size;
|
||||
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
#if CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
@@ -89,7 +88,7 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_GDMA_DESC_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment");
|
||||
|
||||
ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed");
|
||||
ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, NULL, &dma->dma_chan), TAG, "new channel failed");
|
||||
|
||||
ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed");
|
||||
|
||||
|
||||
@@ -821,17 +821,15 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
|
||||
#endif
|
||||
};
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
/* Register a new GDMA tx channel */
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register tx dma channel error");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan, NULL), TAG, "Register tx dma channel error");
|
||||
ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect tx dma channel error");
|
||||
gdma_tx_event_callbacks_t cb = {.on_trans_eof = i2s_dma_tx_callback};
|
||||
/* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */
|
||||
ESP_GOTO_ON_ERROR(gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register tx callback failed");
|
||||
} else {
|
||||
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
/* Register a new GDMA rx channel */
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register rx dma channel error");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, NULL, &handle->dma.dma_chan), TAG, "Register rx dma channel error");
|
||||
ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect rx dma channel error");
|
||||
gdma_rx_event_callbacks_t cb = {.on_recv_eof = i2s_dma_rx_callback};
|
||||
/* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */
|
||||
|
||||
@@ -293,8 +293,7 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_tx_chan), TAG, "DMA tx channel alloc failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_tx_chan, NULL), TAG, "DMA tx channel alloc failed");
|
||||
gdma_connect(i3c_master_handle->dma_tx_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I3C, 0));
|
||||
|
||||
gdma_transfer_config_t transfer_cfg = {
|
||||
@@ -316,8 +315,7 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const
|
||||
ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &i3c_master_handle->tx_dma_link), TAG, "DMA tx link list alloc failed");
|
||||
|
||||
// Initialize DMA RX channel
|
||||
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_rx_chan), TAG, "DMA rx channel alloc failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, NULL, &i3c_master_handle->dma_rx_chan), TAG, "DMA rx channel alloc failed");
|
||||
gdma_connect(i3c_master_handle->dma_rx_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I3C, 0));
|
||||
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(i3c_master_handle->dma_rx_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed");
|
||||
|
||||
@@ -444,12 +444,11 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t
|
||||
{
|
||||
/* Allocate and connect the GDMA channel */
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
#if CONFIG_PARLIO_RX_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, NULL, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed");
|
||||
gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0));
|
||||
|
||||
/* Set GDMA strategy */
|
||||
|
||||
@@ -138,12 +138,11 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
|
||||
static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio_tx_unit_config_t *config)
|
||||
{
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
#if CONFIG_PARLIO_TX_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &tx_unit->dma_chan), TAG, "allocate TX DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &tx_unit->dma_chan, NULL), TAG, "allocate TX DMA channel failed");
|
||||
gdma_connect(tx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0));
|
||||
gdma_strategy_config_t gdma_strategy_conf = {
|
||||
.auto_update_desc = false, // for loop transmission, we have no chance to change the owner
|
||||
|
||||
@@ -43,12 +43,11 @@ static inline void rmt_rx_mount_dma_buffer(rmt_rx_channel_t *rx_chan, const void
|
||||
static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx_channel_config_t *config)
|
||||
{
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
#if CONFIG_RMT_RX_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, NULL, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed");
|
||||
gdma_transfer_config_t transfer_cfg = {
|
||||
.access_ext_mem = true, // support receive buffer to PSRAM
|
||||
.max_data_burst_size = 32,
|
||||
|
||||
@@ -32,12 +32,11 @@ static bool rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t
|
||||
static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx_channel_config_t *config)
|
||||
{
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
#if CONFIG_RMT_TX_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan), TAG, "allocate TX DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan, NULL), TAG, "allocate TX DMA channel failed");
|
||||
gdma_strategy_config_t gdma_strategy_conf = {
|
||||
.auto_update_desc = true,
|
||||
.owner_check = true,
|
||||
|
||||
@@ -265,23 +265,14 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (dma_chan == SPI_DMA_CH_AUTO) {
|
||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||
.flags.reserve_sibling = 1,
|
||||
#if CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&tx_alloc_config, &dma_ctx->tx_dma_chan), SPI_TAG, "alloc gdma tx failed");
|
||||
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = dma_ctx->tx_dma_chan,
|
||||
gdma_channel_alloc_config_t alloc_config = {
|
||||
#if CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma_ctx->rx_dma_chan), SPI_TAG, "alloc gdma rx failed");
|
||||
// Allocate TX and RX channels separately (they don't need to be in the same pair)
|
||||
ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&alloc_config, &dma_ctx->tx_dma_chan, NULL), SPI_TAG, "alloc gdma tx channel failed");
|
||||
ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&alloc_config, NULL, &dma_ctx->rx_dma_chan), SPI_TAG, "alloc gdma rx channel failed");
|
||||
|
||||
if (host_id == SPI2_HOST) {
|
||||
gdma_connect(dma_ctx->tx_dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
|
||||
|
||||
@@ -173,12 +173,11 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
|
||||
{
|
||||
// Initialize DMA TX channel
|
||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
#if CONFIG_UHCI_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&tx_alloc_config, &uhci_ctrl->tx_dir.dma_chan), TAG, "DMA tx channel alloc failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&tx_alloc_config, &uhci_ctrl->tx_dir.dma_chan, NULL), TAG, "DMA tx channel alloc failed");
|
||||
gdma_connect(uhci_ctrl->tx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
|
||||
|
||||
gdma_transfer_config_t transfer_cfg = {
|
||||
@@ -207,12 +206,11 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
|
||||
|
||||
// Initialize DMA RX channel
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
#if CONFIG_UHCI_ISR_CACHE_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&rx_alloc_config, &uhci_ctrl->rx_dir.dma_chan), TAG, "DMA rx channel alloc failed");
|
||||
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&rx_alloc_config, NULL, &uhci_ctrl->rx_dir.dma_chan), TAG, "DMA rx channel alloc failed");
|
||||
gdma_connect(uhci_ctrl->rx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->rx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed");
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 1 // Number of GDMA pairs in each AHB group
|
||||
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x01 // pair 0 is M2M capable
|
||||
|
||||
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
|
||||
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
|
||||
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \
|
||||
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \
|
||||
|
||||
@@ -52,6 +52,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 2 // Number of GDMA pairs in each AHB group
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x03 // pair 0,1 are M2M capable
|
||||
|
||||
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
|
||||
(uint32_t[1][2][GDMA_ETM_EVENT_MAX]){{{ \
|
||||
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \
|
||||
|
||||
@@ -52,6 +52,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
|
||||
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \
|
||||
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \
|
||||
|
||||
@@ -48,6 +48,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
|
||||
#define GDMA_LL_AHB_PAIRS_PER_GROUP 5 // Number of GDMA pairs in each AHB group
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x1F // pair 0,1,2,3,4 are M2M capable
|
||||
|
||||
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
|
||||
(uint32_t[1][5][GDMA_ETM_EVENT_MAX]){{{ \
|
||||
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \
|
||||
|
||||
@@ -63,6 +63,14 @@
|
||||
#define GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE 1 // AHB GDMA supports adjustable burst size
|
||||
#endif
|
||||
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x06 // only pair 1,2 are M2M capable
|
||||
#else
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
#endif
|
||||
|
||||
#define GDMA_LL_AXI_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable
|
||||
|
||||
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
|
||||
(uint32_t[2][GDMA_ETM_EVENT_MAX]){ \
|
||||
{ \
|
||||
|
||||
@@ -73,6 +73,8 @@ extern "C" {
|
||||
#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1
|
||||
#define GDMA_LL_MAX_BURST_SIZE_PSRAM 64 // PSRAM controller doesn't support burst access with size > 64 bytes
|
||||
|
||||
#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x1F // pair 0,1,2,3,4 are M2M capable
|
||||
|
||||
///////////////////////////////////// Common /////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,7 +103,7 @@ static esp_err_t mcp_gdma_destroy(async_memcpy_gdma_context_t *mcp_gdma)
|
||||
}
|
||||
|
||||
static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp,
|
||||
esp_err_t (*new_channel_func)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *),
|
||||
esp_err_t (*new_channel_func)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *, gdma_channel_handle_t *),
|
||||
int gdma_bus_id)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
@@ -118,17 +118,9 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi
|
||||
mcp_gdma->transaction_pool = heap_caps_calloc(trans_queue_len, sizeof(async_memcpy_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(mcp_gdma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool");
|
||||
|
||||
// create TX channel and RX channel, they should reside in the same DMA pair
|
||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||
.flags.reserve_sibling = 1,
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(new_channel_func(&tx_alloc_config, &mcp_gdma->tx_channel), err, TAG, "failed to alloc GDMA TX channel");
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = mcp_gdma->tx_channel,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(new_channel_func(&rx_alloc_config, &mcp_gdma->rx_channel), err, TAG, "failed to alloc GDMA RX channel");
|
||||
// create TX and RX channels in the same pair with a single call
|
||||
gdma_channel_alloc_config_t channel_config = {0};
|
||||
ESP_GOTO_ON_ERROR(new_channel_func(&channel_config, &mcp_gdma->tx_channel, &mcp_gdma->rx_channel), err, TAG, "failed to alloc GDMA channels");
|
||||
|
||||
// get a free DMA trigger ID for memory copy
|
||||
gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0);
|
||||
@@ -147,7 +139,7 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi
|
||||
gdma_apply_strategy(mcp_gdma->rx_channel, &strategy_cfg);
|
||||
|
||||
#if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
if(config->weight){
|
||||
if (config->weight) {
|
||||
ESP_GOTO_ON_ERROR(gdma_set_weight(mcp_gdma->rx_channel, config->weight), err, TAG, "Set GDMA rx channel weight failed");
|
||||
ESP_GOTO_ON_ERROR(gdma_set_weight(mcp_gdma->tx_channel, config->weight), err, TAG, "Set GDMA tx channel weight failed");
|
||||
}
|
||||
|
||||
@@ -35,15 +35,14 @@
|
||||
#define SEARCH_REQUEST_TX_CHANNEL (1 << 1)
|
||||
|
||||
typedef struct gdma_platform_t {
|
||||
portMUX_TYPE spinlock; // platform level spinlock, protect the group handle slots and reference count of each group.
|
||||
portMUX_TYPE spinlock; // platform level spinlock, protect the group handle slots
|
||||
gdma_group_t *groups[GDMA_LL_GET(INST_NUM)]; // array of GDMA group instances
|
||||
int group_ref_counts[GDMA_LL_GET(INST_NUM)]; // reference count used to protect group install/uninstall
|
||||
} gdma_platform_t;
|
||||
|
||||
static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config));
|
||||
static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id);
|
||||
static void gdma_release_group_handle(gdma_group_t *group);
|
||||
static void gdma_release_pair_handle(gdma_pair_t *pair);
|
||||
static gdma_group_t *gdma_try_alloc_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config));
|
||||
static gdma_pair_t *gdma_try_alloc_pair_handle(gdma_group_t *group, int pair_id);
|
||||
static void gdma_try_free_group_handle(gdma_group_t *group);
|
||||
static void gdma_try_free_pair_handle(gdma_pair_t *pair);
|
||||
static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel);
|
||||
static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel);
|
||||
static esp_err_t gdma_install_rx_interrupt(gdma_rx_channel_t *rx_chan);
|
||||
@@ -59,29 +58,28 @@ typedef struct {
|
||||
int start_group_id;
|
||||
int end_group_id;
|
||||
int pairs_per_group;
|
||||
uint32_t m2m_capable_mask;
|
||||
void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config);
|
||||
} gdma_channel_search_info_t;
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "gdma");
|
||||
|
||||
static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *search_info, const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan)
|
||||
static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *search_info, const gdma_channel_alloc_config_t *config,
|
||||
gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
gdma_tx_channel_t *alloc_tx_channel = NULL;
|
||||
gdma_rx_channel_t *alloc_rx_channel = NULL;
|
||||
int search_code = 0;
|
||||
bool found_pair = false;
|
||||
gdma_pair_t *pair = NULL;
|
||||
gdma_group_t *group = NULL;
|
||||
|
||||
// Validate input parameters
|
||||
ESP_RETURN_ON_FALSE(search_info && config && ret_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(search_info && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(ret_tx_chan || ret_rx_chan, ESP_ERR_INVALID_ARG, TAG, "both channel pointers are NULL");
|
||||
ESP_RETURN_ON_FALSE(search_info->start_group_id < search_info->end_group_id, ESP_ERR_INVALID_ARG, TAG, "invalid group range");
|
||||
ESP_RETURN_ON_FALSE(search_info->pairs_per_group > 0, ESP_ERR_INVALID_ARG, TAG, "invalid pairs_per_group");
|
||||
if (config->sibling_chan) {
|
||||
ESP_RETURN_ON_FALSE(config->sibling_chan->direction != config->direction, ESP_ERR_INVALID_ARG, TAG,
|
||||
"sibling channel should have a different direction");
|
||||
ESP_RETURN_ON_FALSE(config->sibling_chan->pair, ESP_ERR_INVALID_ARG, TAG, "invalid sibling channel");
|
||||
}
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
// retention module is per GDMA pair, before we allocate the pair object, some common registers are already configured in "hal_init"
|
||||
@@ -90,71 +88,64 @@ static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *sear
|
||||
sleep_retention_power_lock_acquire();
|
||||
#endif
|
||||
|
||||
if (config->flags.reserve_sibling) {
|
||||
search_code = SEARCH_REQUEST_RX_CHANNEL | SEARCH_REQUEST_TX_CHANNEL; // search for a pair of channels
|
||||
}
|
||||
if (config->direction == GDMA_CHANNEL_DIRECTION_TX) {
|
||||
search_code |= SEARCH_REQUEST_TX_CHANNEL; // search TX only
|
||||
// Determine search code based on which channels are requested
|
||||
if (ret_tx_chan) {
|
||||
search_code |= SEARCH_REQUEST_TX_CHANNEL;
|
||||
alloc_tx_channel = heap_caps_calloc(1, sizeof(gdma_tx_channel_t), GDMA_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(alloc_tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for gdma tx channel");
|
||||
} else if (config->direction == GDMA_CHANNEL_DIRECTION_RX) {
|
||||
search_code |= SEARCH_REQUEST_RX_CHANNEL; // search RX only
|
||||
}
|
||||
if (ret_rx_chan) {
|
||||
search_code |= SEARCH_REQUEST_RX_CHANNEL;
|
||||
alloc_rx_channel = heap_caps_calloc(1, sizeof(gdma_rx_channel_t), GDMA_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(alloc_rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for gdma rx channel");
|
||||
}
|
||||
|
||||
if (config->sibling_chan) {
|
||||
pair = config->sibling_chan->pair;
|
||||
group = pair->group;
|
||||
// Acquire reference early, before any additional error checks
|
||||
esp_os_enter_critical(&group->spinlock);
|
||||
group->pair_ref_counts[pair->pair_id]++; // channel obtains a reference to pair
|
||||
esp_os_exit_critical(&group->spinlock);
|
||||
// skip the search path below if user has specify a sibling channel
|
||||
goto search_done;
|
||||
}
|
||||
// If both channels are requested, they must be in the same pair
|
||||
// The search_code will have both bits set, ensuring we find a pair with both channels available
|
||||
|
||||
int start_group_id = search_info->start_group_id;
|
||||
int end_group_id = search_info->end_group_id;
|
||||
int pairs_per_group = search_info->pairs_per_group;
|
||||
|
||||
for (int i = start_group_id; i < end_group_id && search_code; i++) { // loop to search group
|
||||
group = gdma_acquire_group_handle(i, search_info->hal_init);
|
||||
// loop to search group
|
||||
for (int i = start_group_id; i < end_group_id && !found_pair; i++) {
|
||||
group = gdma_try_alloc_group_handle(i, search_info->hal_init);
|
||||
ESP_GOTO_ON_FALSE(group, ESP_ERR_NO_MEM, err, TAG, "no mem for group(%d)", i);
|
||||
group->bus_id = search_info->bus_id;
|
||||
for (int j = 0; j < pairs_per_group && search_code; j++) { // loop to search pair
|
||||
pair = gdma_acquire_pair_handle(group, j);
|
||||
|
||||
// loop to search pair
|
||||
for (int j = 0; j < pairs_per_group && !found_pair; j++) {
|
||||
// Check M2M capability BEFORE acquiring pair to avoid unnecessary allocation
|
||||
if (ret_tx_chan && ret_rx_chan) { // Both channels requested (implicit M2M usage)
|
||||
if (!((1 << j) & search_info->m2m_capable_mask)) {
|
||||
ESP_LOGV(TAG, "pair(%d,%d) not M2M capable, skip", i, j);
|
||||
continue; // Skip pairs that don't support M2M
|
||||
}
|
||||
}
|
||||
|
||||
pair = gdma_try_alloc_pair_handle(group, j);
|
||||
ESP_GOTO_ON_FALSE(pair, ESP_ERR_NO_MEM, err, TAG, "no mem for pair(%d,%d)", i, j);
|
||||
|
||||
// Check if channels are available
|
||||
esp_os_enter_critical(&pair->spinlock);
|
||||
if (!(search_code & pair->occupy_code)) { // pair has suitable position for acquired channel(s)
|
||||
pair->occupy_code |= search_code;
|
||||
search_code = 0; // exit search loop
|
||||
found_pair = true;
|
||||
}
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
// found a pair that satisfies the search condition
|
||||
if (search_code == 0) {
|
||||
// gdma_acquire_pair_handle already increased pair ref count, no need to do it again
|
||||
// pair is ready to use, don't release it
|
||||
// however, we need to release the group reference acquired by gdma_acquire_group_handle
|
||||
// because gdma_acquire_pair_handle already added its own group reference
|
||||
gdma_release_group_handle(group);
|
||||
break; // exit inner loop, will also exit outer loop due to search_code == 0
|
||||
} else {
|
||||
// not suitable pair, release it
|
||||
gdma_release_pair_handle(pair);
|
||||
pair = NULL;
|
||||
}
|
||||
} // loop used to search pair
|
||||
// Only release group if we didn't find a suitable pair in this group
|
||||
if (search_code != 0) {
|
||||
gdma_release_group_handle(group);
|
||||
|
||||
// If no suitable pair found in this group, release the group before trying next group
|
||||
if (!found_pair) {
|
||||
gdma_try_free_group_handle(group);
|
||||
group = NULL;
|
||||
}
|
||||
} // loop used to search group
|
||||
ESP_GOTO_ON_FALSE(search_code == 0, ESP_ERR_NOT_FOUND, err, TAG, "no free gdma channel, search code=%d", search_code);
|
||||
assert(pair && group); // pair and group handle shouldn't be NULL
|
||||
search_done:
|
||||
// register TX channel
|
||||
ESP_GOTO_ON_FALSE(found_pair, ESP_ERR_NOT_FOUND, err, TAG, "no free gdma channel, search code=%d", search_code);
|
||||
|
||||
// Note: No lock protection is needed here because pair->occupy_code was already set atomically
|
||||
// in the critical section above. Once the occupy_code bit is set, this is the only thread that
|
||||
// can write to pair->tx_chan, so there's no race condition.
|
||||
if (alloc_tx_channel) {
|
||||
pair->tx_chan = alloc_tx_channel;
|
||||
alloc_tx_channel->base.pair = pair;
|
||||
@@ -162,10 +153,15 @@ search_done:
|
||||
alloc_tx_channel->base.periph_id = GDMA_INVALID_PERIPH_TRIG;
|
||||
alloc_tx_channel->base.flags.isr_cache_safe = config->flags.isr_cache_safe;
|
||||
alloc_tx_channel->base.del = gdma_del_tx_channel; // set channel deletion function
|
||||
*ret_chan = &alloc_tx_channel->base; // return the installed channel
|
||||
alloc_tx_channel->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
*ret_tx_chan = &alloc_tx_channel->base; // return the installed channel
|
||||
#if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
// set 1 as default weight, can be overwritten by user
|
||||
gdma_set_weight(&alloc_tx_channel->base, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// register RX channel
|
||||
// Note: Same as TX channel - no lock needed due to occupy_code protection
|
||||
if (alloc_rx_channel) {
|
||||
pair->rx_chan = alloc_rx_channel;
|
||||
alloc_rx_channel->base.pair = pair;
|
||||
@@ -173,40 +169,66 @@ search_done:
|
||||
alloc_rx_channel->base.periph_id = GDMA_INVALID_PERIPH_TRIG;
|
||||
alloc_rx_channel->base.flags.isr_cache_safe = config->flags.isr_cache_safe;
|
||||
alloc_rx_channel->base.del = gdma_del_rx_channel; // set channel deletion function
|
||||
*ret_chan = &alloc_rx_channel->base; // return the installed channel
|
||||
}
|
||||
alloc_rx_channel->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
*ret_rx_chan = &alloc_rx_channel->base; // return the installed channel
|
||||
#if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
// set 1 as default weight, can be overwritten by user
|
||||
gdma_set_weight(*ret_chan, 1);
|
||||
// set 1 as default weight, can be overwritten by user
|
||||
gdma_set_weight(&alloc_rx_channel->base, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
// set up the sleep retention link for the pair
|
||||
gdma_acquire_sleep_retention(pair);
|
||||
// Each channel holds a reference to the sleep retention, so we need to acquire it for each channel
|
||||
if (alloc_tx_channel) {
|
||||
gdma_acquire_sleep_retention(pair);
|
||||
}
|
||||
if (alloc_rx_channel) {
|
||||
gdma_acquire_sleep_retention(pair);
|
||||
}
|
||||
// release the helper power lock because we have finished setting up the sleep retention link
|
||||
sleep_retention_power_lock_release();
|
||||
#endif
|
||||
(*ret_chan)->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
ESP_LOGD(TAG, "new %s channel (%d,%d) at %p", (config->direction == GDMA_CHANNEL_DIRECTION_TX) ? "tx" : "rx",
|
||||
group->group_id, pair->pair_id, *ret_chan);
|
||||
ESP_LOGV(TAG, "new channel(s) in (%d,%d)%s%s", group->group_id, pair->pair_id,
|
||||
alloc_tx_channel ? " tx" : "", alloc_rx_channel ? " rx" : "");
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (pair) {
|
||||
// If we successfully set occupy_code and/or channel pointers but failed later,
|
||||
// we need to restore the pair state before releasing it
|
||||
if (found_pair) {
|
||||
esp_os_enter_critical(&pair->spinlock);
|
||||
// Clear the occupy_code bits we set
|
||||
pair->occupy_code &= ~search_code;
|
||||
// NULL out any channel pointers we may have set to avoid dangling pointers
|
||||
// The channel memory will be freed below
|
||||
if (alloc_tx_channel && pair->tx_chan == alloc_tx_channel) {
|
||||
pair->tx_chan = NULL;
|
||||
}
|
||||
if (alloc_rx_channel && pair->rx_chan == alloc_rx_channel) {
|
||||
pair->rx_chan = NULL;
|
||||
}
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
}
|
||||
// If we successfully acquired a pair but failed later, release it
|
||||
// The pair release will also check and free the group if all pairs are gone
|
||||
gdma_try_free_pair_handle(pair);
|
||||
} else if (group) {
|
||||
// If we acquired a group but failed to get a pair, try to release the group
|
||||
// This handles the case where we created an empty group that never got any pairs
|
||||
// Note: gdma_try_free_group_handle is state-based and idempotent, so calling it
|
||||
// even when pair was released is safe (though the second call would be redundant)
|
||||
gdma_try_free_group_handle(group);
|
||||
}
|
||||
// Free the channel structures after clearing the pair pointers
|
||||
if (alloc_tx_channel) {
|
||||
free(alloc_tx_channel);
|
||||
}
|
||||
if (alloc_rx_channel) {
|
||||
free(alloc_rx_channel);
|
||||
}
|
||||
// coverity[dead_error_condition] - defensive check for code maintainability
|
||||
if (pair) {
|
||||
gdma_release_pair_handle(pair);
|
||||
// pair release will also release group if it's the last reference
|
||||
// so we don't need to release group separately to avoid double-release
|
||||
} else if (group) {
|
||||
// only release group if pair wasn't allocated/released
|
||||
gdma_release_group_handle(group);
|
||||
}
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
sleep_retention_power_lock_release();
|
||||
#endif
|
||||
@@ -214,36 +236,40 @@ err:
|
||||
}
|
||||
|
||||
#if SOC_HAS(AHB_GDMA)
|
||||
esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan)
|
||||
esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan)
|
||||
{
|
||||
gdma_channel_search_info_t search_info = {
|
||||
.bus_id = SOC_GDMA_BUS_AHB,
|
||||
.start_group_id = GDMA_LL_AHB_GROUP_START_ID,
|
||||
.end_group_id = GDMA_LL_AHB_GROUP_START_ID + GDMA_LL_AHB_NUM_GROUPS,
|
||||
.pairs_per_group = GDMA_LL_AHB_PAIRS_PER_GROUP,
|
||||
.m2m_capable_mask = GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK,
|
||||
.hal_init = gdma_ahb_hal_init,
|
||||
};
|
||||
return do_allocate_gdma_channel(&search_info, config, ret_chan);
|
||||
return do_allocate_gdma_channel(&search_info, config, ret_tx_chan, ret_rx_chan);
|
||||
}
|
||||
#endif // SOC_HAS(AHB_GDMA)
|
||||
|
||||
#if SOC_HAS(AXI_GDMA)
|
||||
esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan)
|
||||
esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan)
|
||||
{
|
||||
gdma_channel_search_info_t search_info = {
|
||||
.bus_id = SOC_GDMA_BUS_AXI,
|
||||
.start_group_id = GDMA_LL_AXI_GROUP_START_ID,
|
||||
.end_group_id = GDMA_LL_AXI_GROUP_START_ID + GDMA_LL_AXI_NUM_GROUPS,
|
||||
.pairs_per_group = GDMA_LL_AXI_PAIRS_PER_GROUP,
|
||||
.m2m_capable_mask = GDMA_LL_AXI_M2M_CAPABLE_PAIR_MASK,
|
||||
.hal_init = gdma_axi_hal_init,
|
||||
};
|
||||
return do_allocate_gdma_channel(&search_info, config, ret_chan);
|
||||
return do_allocate_gdma_channel(&search_info, config, ret_tx_chan, ret_rx_chan);
|
||||
}
|
||||
#endif // SOC_HAS(AXI_GDMA)
|
||||
|
||||
esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -257,18 +283,17 @@ esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan)
|
||||
|
||||
esp_err_t gdma_get_group_channel_id(gdma_channel_handle_t dma_chan, int *group_id, int *channel_id)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
gdma_pair_t *pair = NULL;
|
||||
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
pair = dma_chan->pair;
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
if (group_id != NULL) {
|
||||
*group_id = pair->group->group_id;
|
||||
}
|
||||
if (channel_id != NULL) {
|
||||
*channel_id = pair->pair_id;
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_periph)
|
||||
@@ -345,7 +370,9 @@ esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan)
|
||||
|
||||
esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_t *mask)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan || !mask) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
uint32_t free_mask = group->hal.priv_data->m2m_free_periph_mask;
|
||||
@@ -361,7 +388,9 @@ esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_
|
||||
|
||||
esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan || !config) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint32_t max_data_burst_size = config->max_data_burst_size;
|
||||
if (max_data_burst_size) {
|
||||
// burst size must be power of 2
|
||||
@@ -424,7 +453,9 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
|
||||
|
||||
esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (int_mem_alignment) {
|
||||
*int_mem_alignment = dma_chan->int_mem_alignment;
|
||||
}
|
||||
@@ -436,7 +467,9 @@ esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t
|
||||
|
||||
esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan || !config) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -448,7 +481,9 @@ esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strateg
|
||||
|
||||
esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && priority <= GDMA_LL_CHANNEL_MAX_PRIORITY, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan || priority > GDMA_LL_CHANNEL_MAX_PRIORITY) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -461,7 +496,9 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority)
|
||||
#if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION
|
||||
esp_err_t gdma_set_weight(gdma_channel_handle_t dma_chan, uint32_t weight)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(dma_chan && weight <= GDMA_LL_CHANNEL_MAX_WEIGHT, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan || weight > GDMA_LL_CHANNEL_MAX_WEIGHT) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -559,8 +596,12 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
|
||||
|
||||
esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan->flags.start_stop_by_etm == false, ESP_ERR_INVALID_STATE, TAG, "channel is controlled by ETM");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (dma_chan->flags.start_stop_by_etm) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -574,8 +615,12 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr)
|
||||
|
||||
esp_err_t gdma_stop(gdma_channel_handle_t dma_chan)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan->flags.start_stop_by_etm == false, ESP_ERR_INVALID_STATE, TAG, "channel is controlled by ETM");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (dma_chan->flags.start_stop_by_etm) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -589,7 +634,9 @@ esp_err_t gdma_stop(gdma_channel_handle_t dma_chan)
|
||||
|
||||
esp_err_t gdma_append(gdma_channel_handle_t dma_chan)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -603,7 +650,9 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan)
|
||||
|
||||
esp_err_t gdma_reset(gdma_channel_handle_t dma_chan)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
if (!dma_chan) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
gdma_pair_t *pair = dma_chan->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_hal_context_t *hal = &group->hal;
|
||||
@@ -615,14 +664,21 @@ esp_err_t gdma_reset(gdma_channel_handle_t dma_chan)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void gdma_release_group_handle(gdma_group_t *group)
|
||||
static void gdma_try_free_group_handle(gdma_group_t *group)
|
||||
{
|
||||
int group_id = group->group_id;
|
||||
bool do_deinitialize = false;
|
||||
|
||||
esp_os_enter_critical(&s_platform.spinlock);
|
||||
s_platform.group_ref_counts[group_id]--;
|
||||
if (s_platform.group_ref_counts[group_id] == 0) {
|
||||
// Check if all pairs are gone - if so, free the group
|
||||
bool all_pairs_gone = true;
|
||||
for (int i = 0; i < GDMA_LL_GET(PAIRS_PER_INST); i++) {
|
||||
if (group->pairs[i] != NULL) {
|
||||
all_pairs_gone = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_pairs_gone) {
|
||||
assert(s_platform.groups[group_id]);
|
||||
do_deinitialize = true;
|
||||
// deregister from the platform
|
||||
@@ -636,11 +692,11 @@ static void gdma_release_group_handle(gdma_group_t *group)
|
||||
|
||||
if (do_deinitialize) {
|
||||
free(group);
|
||||
ESP_LOGD(TAG, "del group %d", group_id);
|
||||
ESP_LOGV(TAG, "del group %d", group_id);
|
||||
}
|
||||
}
|
||||
|
||||
static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config))
|
||||
static gdma_group_t *gdma_try_alloc_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config))
|
||||
{
|
||||
bool new_group = false;
|
||||
gdma_group_t *group = NULL;
|
||||
@@ -672,12 +728,10 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gd
|
||||
} else {
|
||||
group = s_platform.groups[group_id];
|
||||
}
|
||||
// someone acquired the group handle means we have a new object that refer to this group
|
||||
s_platform.group_ref_counts[group_id]++;
|
||||
esp_os_exit_critical(&s_platform.spinlock);
|
||||
|
||||
if (new_group) {
|
||||
ESP_LOGD(TAG, "new group (%d) at %p", group_id, group);
|
||||
ESP_LOGV(TAG, "new group (%d) at %p", group_id, group);
|
||||
} else {
|
||||
free(pre_alloc_group);
|
||||
}
|
||||
@@ -685,29 +739,42 @@ out:
|
||||
return group;
|
||||
}
|
||||
|
||||
static void gdma_release_pair_handle(gdma_pair_t *pair)
|
||||
static void gdma_try_free_pair_handle(gdma_pair_t *pair)
|
||||
{
|
||||
gdma_group_t *group = pair->group;
|
||||
int pair_id = pair->pair_id;
|
||||
bool do_deinitialize = false;
|
||||
|
||||
esp_os_enter_critical(&group->spinlock);
|
||||
group->pair_ref_counts[pair_id]--;
|
||||
if (group->pair_ref_counts[pair_id] == 0) {
|
||||
assert(group->pairs[pair_id]);
|
||||
// Use pair->spinlock to check channel pointers since that's the lock protecting them
|
||||
esp_os_enter_critical(&pair->spinlock);
|
||||
// Only free the pair if nothing is using or reserving it
|
||||
if (pair->tx_chan == NULL && pair->rx_chan == NULL && pair->occupy_code == 0) {
|
||||
// Mark for deinitialization, but need to update group->pairs under group lock
|
||||
do_deinitialize = true;
|
||||
group->pairs[pair_id] = NULL; // deregister from pair
|
||||
}
|
||||
esp_os_exit_critical(&group->spinlock);
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
|
||||
if (do_deinitialize) {
|
||||
// Now safely update the group's pair pointer under group lock
|
||||
esp_os_enter_critical(&group->spinlock);
|
||||
// Double-check in case another thread beat us to it
|
||||
if (group->pairs[pair_id] != NULL) {
|
||||
group->pairs[pair_id] = NULL; // deregister from group
|
||||
} else {
|
||||
// Another thread already freed this pair, abort
|
||||
do_deinitialize = false;
|
||||
}
|
||||
esp_os_exit_critical(&group->spinlock);
|
||||
}
|
||||
|
||||
if (do_deinitialize) {
|
||||
free(pair);
|
||||
ESP_LOGD(TAG, "del pair (%d,%d)", group->group_id, pair_id);
|
||||
gdma_release_group_handle(group);
|
||||
ESP_LOGV(TAG, "del pair (%d,%d)", group->group_id, pair_id);
|
||||
gdma_try_free_group_handle(group);
|
||||
}
|
||||
}
|
||||
|
||||
static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id)
|
||||
static gdma_pair_t *gdma_try_alloc_pair_handle(gdma_group_t *group, int pair_id)
|
||||
{
|
||||
bool new_pair = false;
|
||||
gdma_pair_t *pair = NULL;
|
||||
@@ -729,18 +796,11 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id)
|
||||
} else {
|
||||
pair = group->pairs[pair_id];
|
||||
}
|
||||
// someone acquired the pair handle means we have a new object that refer to this pair
|
||||
group->pair_ref_counts[pair_id]++;
|
||||
esp_os_exit_critical(&group->spinlock);
|
||||
|
||||
// Update group reference count outside of group->spinlock to avoid deadlock
|
||||
// This must be done after pair registration to ensure group remains valid
|
||||
// Log new pair creation
|
||||
if (new_pair) {
|
||||
esp_os_enter_critical(&s_platform.spinlock);
|
||||
s_platform.group_ref_counts[group->group_id]++;
|
||||
esp_os_exit_critical(&s_platform.spinlock);
|
||||
|
||||
ESP_LOGD(TAG, "new pair (%d,%d) at %p", group->group_id, pair_id, pair);
|
||||
ESP_LOGV(TAG, "new pair (%d,%d) at %p", group->group_id, pair_id, pair);
|
||||
} else {
|
||||
free(pre_alloc_pair);
|
||||
}
|
||||
@@ -769,18 +829,18 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel)
|
||||
gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX, false); // disable all interrupt events
|
||||
gdma_hal_clear_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX); // clear all pending events
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
ESP_LOGD(TAG, "uninstall interrupt service for tx channel (%d,%d)", group_id, pair_id);
|
||||
ESP_LOGV(TAG, "uninstall interrupt service for tx channel (%d,%d)", group_id, pair_id);
|
||||
}
|
||||
|
||||
free(tx_chan);
|
||||
ESP_LOGD(TAG, "del tx channel (%d,%d)", group_id, pair_id);
|
||||
ESP_LOGV(TAG, "del tx channel (%d,%d)", group_id, pair_id);
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
// release sleep retention lock
|
||||
gdma_release_sleep_retention(pair);
|
||||
#endif
|
||||
// channel has a reference on pair, release it now
|
||||
gdma_release_pair_handle(pair);
|
||||
// release pair handle (will free pair if both channels are deleted)
|
||||
gdma_try_free_pair_handle(pair);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -804,18 +864,18 @@ static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel)
|
||||
gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX, false); // disable all interrupt events
|
||||
gdma_hal_clear_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX); // clear all pending events
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
ESP_LOGD(TAG, "uninstall interrupt service for rx channel (%d,%d)", group_id, pair_id);
|
||||
ESP_LOGV(TAG, "uninstall interrupt service for rx channel (%d,%d)", group_id, pair_id);
|
||||
}
|
||||
|
||||
free(rx_chan);
|
||||
ESP_LOGD(TAG, "del rx channel (%d,%d)", group_id, pair_id);
|
||||
ESP_LOGV(TAG, "del rx channel (%d,%d)", group_id, pair_id);
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
// release sleep retention lock
|
||||
gdma_release_sleep_retention(pair);
|
||||
#endif
|
||||
// channel has a reference on pair, release it now
|
||||
gdma_release_pair_handle(pair);
|
||||
// release pair handle (will free pair if both channels are deleted)
|
||||
gdma_try_free_pair_handle(pair);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -926,7 +986,7 @@ static esp_err_t gdma_install_rx_interrupt(gdma_rx_channel_t *rx_chan)
|
||||
gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX, false); // disable all interrupt events
|
||||
gdma_hal_clear_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX); // clear all pending events
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
ESP_LOGD(TAG, "install interrupt service for rx channel (%d,%d)", group->group_id, pair_id);
|
||||
ESP_LOGV(TAG, "install interrupt service for rx channel (%d,%d)", group->group_id, pair_id);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
@@ -958,7 +1018,7 @@ static esp_err_t gdma_install_tx_interrupt(gdma_tx_channel_t *tx_chan)
|
||||
gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX, false); // disable all interrupt events
|
||||
gdma_hal_clear_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX); // clear all pending events
|
||||
esp_os_exit_critical(&pair->spinlock);
|
||||
ESP_LOGD(TAG, "install interrupt service for tx channel (%d,%d)", group->group_id, pair_id);
|
||||
ESP_LOGV(TAG, "install interrupt service for tx channel (%d,%d)", group->group_id, pair_id);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
|
||||
@@ -61,7 +61,6 @@ typedef struct gdma_group_t {
|
||||
uint32_t tx_periph_in_use_mask; // each bit indicates which peripheral (TX direction) has been occupied
|
||||
uint32_t rx_periph_in_use_mask; // each bit indicates which peripheral (RX direction) has been occupied
|
||||
gdma_pair_t *pairs[GDMA_LL_GET(PAIRS_PER_INST)]; // handles of GDMA pairs
|
||||
int pair_ref_counts[GDMA_LL_GET(PAIRS_PER_INST)]; // reference count used to protect pair install/uninstall
|
||||
} gdma_group_t;
|
||||
|
||||
struct gdma_pair_t {
|
||||
|
||||
@@ -26,10 +26,7 @@ typedef struct gdma_channel_t *gdma_channel_handle_t;
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
gdma_channel_handle_t sibling_chan; /*!< DMA sibling channel handle (NULL means having sibling is not necessary) */
|
||||
gdma_channel_direction_t direction; /*!< DMA channel direction */
|
||||
struct {
|
||||
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 */
|
||||
int isr_cache_safe: 1; /*!< If set, DMA channel allocator would allocate interrupt in cache-safe region, and ISR is serviceable when cache is disabled */
|
||||
} flags;
|
||||
} gdma_channel_alloc_config_t;
|
||||
@@ -110,34 +107,44 @@ typedef struct {
|
||||
} gdma_strategy_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create AHB-GDMA channel
|
||||
* @brief Create AHB-GDMA channel(s)
|
||||
* @note This API won't install interrupt service for the allocated channel.
|
||||
* If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`.
|
||||
* @note To allocate both TX and RX channels in a pair, pass non-NULL pointers for both ret_tx_chan and ret_rx_chan.
|
||||
* To allocate only one direction, pass NULL for the unwanted direction.
|
||||
* @note Allocation is atomic: if any channel fails to allocate, all partially allocated resources are cleaned up automatically.
|
||||
* Either all requested channels are successfully allocated, or the function fails with no channels allocated.
|
||||
*
|
||||
* @param[in] config Pointer to a collection of configurations for allocating GDMA channel
|
||||
* @param[out] ret_chan Returned channel handle
|
||||
* @param[out] ret_tx_chan Returned TX channel handle. Pass NULL if TX channel is not needed. Must not be NULL if ret_rx_chan is also NULL.
|
||||
* @param[out] ret_rx_chan Returned RX channel handle. Pass NULL if RX channel is not needed. Must not be NULL if ret_tx_chan is also NULL.
|
||||
* @return
|
||||
* - ESP_OK: Create DMA channel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument
|
||||
* - ESP_OK: Create DMA channel(s) successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because both ret_tx_chan and ret_rx_chan are NULL
|
||||
* - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory
|
||||
* - ESP_FAIL: Create DMA channel failed because of other error
|
||||
*/
|
||||
esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan);
|
||||
esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan);
|
||||
|
||||
/**
|
||||
* @brief Create AXI-GDMA channel
|
||||
* @brief Create AXI-GDMA channel(s)
|
||||
* @note This API won't install interrupt service for the allocated channel.
|
||||
* If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`.
|
||||
* @note To allocate both TX and RX channels in a pair, pass non-NULL pointers for both ret_tx_chan and ret_rx_chan.
|
||||
* To allocate only one direction, pass NULL for the unwanted direction.
|
||||
* @note Allocation is atomic: if any channel fails to allocate, all partially allocated resources are cleaned up automatically.
|
||||
* Either all requested channels are successfully allocated, or the function fails with no channels allocated.
|
||||
*
|
||||
* @param[in] config Pointer to a collection of configurations for allocating GDMA channel
|
||||
* @param[out] ret_chan Returned channel handle
|
||||
* @param[out] ret_tx_chan Returned TX channel handle. Pass NULL if TX channel is not needed. Must not be NULL if ret_rx_chan is also NULL.
|
||||
* @param[out] ret_rx_chan Returned RX channel handle. Pass NULL if RX channel is not needed. Must not be NULL if ret_tx_chan is also NULL.
|
||||
* @return
|
||||
* - ESP_OK: Create DMA channel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument
|
||||
* - ESP_OK: Create DMA channel(s) successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because both ret_tx_chan and ret_rx_chan are NULL
|
||||
* - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory
|
||||
* - ESP_FAIL: Create DMA channel failed because of other error
|
||||
*/
|
||||
esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan);
|
||||
esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan);
|
||||
|
||||
/**
|
||||
* @brief Connect GDMA channel to trigger peripheral
|
||||
|
||||
@@ -32,14 +32,13 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
gdma_channel_alloc_config_t channel_config = {};
|
||||
gdma_channel_handle_t tx_channels[GDMA_LL_GET(PAIRS_PER_INST)] = {};
|
||||
gdma_channel_handle_t rx_channels[GDMA_LL_GET(PAIRS_PER_INST)] = {};
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
|
||||
#if SOC_HAS(AHB_GDMA)
|
||||
// install TX channels
|
||||
for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[i]));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[i], NULL));
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &tx_channels[0]));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &tx_channels[0], NULL));
|
||||
|
||||
// Free interrupts before installing RX interrupts to ensure enough free interrupts
|
||||
for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) {
|
||||
@@ -47,11 +46,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
}
|
||||
|
||||
// install RX channels
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[i]));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[i]));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &rx_channels[0]));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[0]));
|
||||
|
||||
for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_del_channel(rx_channels[i]));
|
||||
@@ -61,20 +59,12 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
// install single and paired TX/RX channels
|
||||
#if GDMA_LL_AHB_PAIRS_PER_GROUP >= 2
|
||||
// single tx channel
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[0]));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[0], NULL));
|
||||
|
||||
// create tx channel and reserve sibling
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
channel_config.flags.reserve_sibling = 1;
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[1]));
|
||||
// create rx channel and specify sibling channel
|
||||
channel_config.flags.reserve_sibling = 0;
|
||||
channel_config.sibling_chan = tx_channels[1]; // specify sibling channel
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[1]));
|
||||
channel_config.sibling_chan = NULL;
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[0]));
|
||||
// create tx and rx channel pair
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[1], &rx_channels[1]));
|
||||
// create single rx channel
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[0]));
|
||||
|
||||
gdma_trigger_t fake_ahb_trigger1 = {
|
||||
.periph = 1,
|
||||
@@ -104,11 +94,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
|
||||
#if SOC_HAS(AXI_GDMA)
|
||||
// install TX channels
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[i]));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[i], NULL));
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &tx_channels[0]));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &tx_channels[0], NULL));
|
||||
|
||||
// Free interrupts before installing RX interrupts to ensure enough free interrupts
|
||||
for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) {
|
||||
@@ -116,11 +105,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
}
|
||||
|
||||
// install RX channels
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[i]));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, NULL, &rx_channels[i]));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &rx_channels[0]));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, NULL, &rx_channels[0]));
|
||||
|
||||
for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(gdma_del_channel(rx_channels[i]));
|
||||
@@ -130,20 +118,12 @@ TEST_CASE("GDMA channel allocation", "[GDMA]")
|
||||
// install single and paired TX/RX channels
|
||||
#if GDMA_LL_AXI_PAIRS_PER_GROUP >= 2
|
||||
// single tx channel
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[0]));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[0], NULL));
|
||||
|
||||
// create tx channel and reserve sibling
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_TX;
|
||||
channel_config.flags.reserve_sibling = 1;
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[1]));
|
||||
// create rx channel and specify sibling channel
|
||||
channel_config.flags.reserve_sibling = 0;
|
||||
channel_config.sibling_chan = tx_channels[1]; // specify sibling channel
|
||||
channel_config.direction = GDMA_CHANNEL_DIRECTION_RX;
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[1]));
|
||||
channel_config.sibling_chan = NULL;
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[0]));
|
||||
// create tx and rx channel pair
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[1], &rx_channels[1]));
|
||||
// create single rx channel
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&channel_config, NULL, &rx_channels[0]));
|
||||
|
||||
gdma_trigger_t fake_axi_trigger1 = {
|
||||
.periph = 1,
|
||||
@@ -344,20 +324,10 @@ static void test_gdma_m2m_mode(bool trig_retention_backup)
|
||||
{
|
||||
gdma_channel_handle_t tx_chan = NULL;
|
||||
gdma_channel_handle_t rx_chan = NULL;
|
||||
gdma_channel_alloc_config_t tx_chan_alloc_config = {};
|
||||
gdma_channel_alloc_config_t rx_chan_alloc_config = {};
|
||||
gdma_channel_alloc_config_t chan_alloc_config = {};
|
||||
|
||||
#if SOC_HAS(AHB_GDMA)
|
||||
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = true,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = tx_chan,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
|
||||
test_gdma_m2m_transaction(tx_chan, rx_chan, false, trig_retention_backup);
|
||||
|
||||
@@ -366,16 +336,7 @@ static void test_gdma_m2m_mode(bool trig_retention_backup)
|
||||
#endif // SOC_HAS(AHB_GDMA)
|
||||
|
||||
#if SOC_HAS(AXI_GDMA)
|
||||
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = true,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = tx_chan,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
|
||||
// the AXI GDMA allows to put the DMA link list in the external memory
|
||||
test_gdma_m2m_transaction(tx_chan, rx_chan, true, trig_retention_backup);
|
||||
@@ -414,18 +375,8 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
|
||||
TEST_ASSERT_NOT_NULL(dst_data);
|
||||
gdma_channel_handle_t tx_chan = NULL;
|
||||
gdma_channel_handle_t rx_chan = NULL;
|
||||
gdma_channel_alloc_config_t tx_chan_alloc_config = {};
|
||||
gdma_channel_alloc_config_t rx_chan_alloc_config = {};
|
||||
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = true,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = tx_chan,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan));
|
||||
gdma_channel_alloc_config_t chan_alloc_config = {};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
|
||||
gdma_link_list_handle_t tx_link_list = NULL;
|
||||
@@ -673,22 +624,12 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]")
|
||||
{
|
||||
[[maybe_unused]] gdma_channel_handle_t tx_chan = NULL;
|
||||
[[maybe_unused]] gdma_channel_handle_t rx_chan = NULL;
|
||||
[[maybe_unused]] gdma_channel_alloc_config_t tx_chan_alloc_config = {};
|
||||
[[maybe_unused]] gdma_channel_alloc_config_t rx_chan_alloc_config = {};
|
||||
[[maybe_unused]] gdma_channel_alloc_config_t chan_alloc_config = {};
|
||||
|
||||
#if SOC_HAS(AHB_GDMA)
|
||||
#if GDMA_LL_GET(AHB_PSRAM_CAPABLE)
|
||||
printf("Testing AHB-GDMA memory copy SRAM->PSRAM->SRAM\n");
|
||||
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = true,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = tx_chan,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
|
||||
test_gdma_memcpy_from_to_psram(tx_chan, rx_chan);
|
||||
|
||||
@@ -700,16 +641,7 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]")
|
||||
#if SOC_HAS(AXI_GDMA)
|
||||
#if GDMA_LL_GET(AXI_PSRAM_CAPABLE)
|
||||
printf("Testing AXI-GDMA memory copy SRAM->PSRAM->SRAM\n");
|
||||
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
.flags.reserve_sibling = true,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = tx_chan,
|
||||
};
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&chan_alloc_config, &tx_chan, &rx_chan));
|
||||
|
||||
test_gdma_memcpy_from_to_psram(tx_chan, rx_chan);
|
||||
|
||||
|
||||
@@ -116,18 +116,17 @@ TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]")
|
||||
{
|
||||
gdma_channel_handle_t tx_chan = NULL;
|
||||
gdma_channel_alloc_config_t tx_chan_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
#if SOC_HAS(AHB_GDMA)
|
||||
printf("Test CRC calculation for AHB GDMA\r\n");
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan, NULL));
|
||||
test_gdma_crc_calculation(tx_chan, 4);
|
||||
TEST_ESP_OK(gdma_del_channel(tx_chan));
|
||||
#endif // SOC_HAS(AHB_GDMA)
|
||||
|
||||
#if SOC_HAS(AXI_GDMA)
|
||||
printf("Test CRC calculation for AXI GDMA\r\n");
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan));
|
||||
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan, NULL));
|
||||
test_gdma_crc_calculation(tx_chan, 3);
|
||||
TEST_ESP_OK(gdma_del_channel(tx_chan));
|
||||
#endif // SOC_HAS(AXI_GDMA)
|
||||
|
||||
@@ -579,10 +579,8 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
// alloc DMA channel and connect to LCD peripheral
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
ret = LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &bus->dma_chan);
|
||||
gdma_channel_alloc_config_t dma_chan_config = {0};
|
||||
ret = LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &bus->dma_chan, NULL);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "alloc DMA channel failed");
|
||||
gdma_connect(bus->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
|
||||
gdma_strategy_config_t strategy_config = {
|
||||
|
||||
@@ -976,12 +976,11 @@ static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel)
|
||||
{
|
||||
// alloc DMA channel and connect to LCD peripheral
|
||||
gdma_channel_alloc_config_t dma_chan_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
|
||||
.flags.isr_cache_safe = true,
|
||||
#endif
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &rgb_panel->dma_chan), TAG, "alloc DMA channel failed");
|
||||
ESP_RETURN_ON_ERROR(LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &rgb_panel->dma_chan, NULL), TAG, "alloc DMA channel failed");
|
||||
gdma_connect(rgb_panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
|
||||
|
||||
// configure DMA strategy
|
||||
|
||||
@@ -34,25 +34,27 @@
|
||||
|
||||
static const char *TAG = "crypto_shared_gdma";
|
||||
|
||||
static gdma_channel_handle_t rx_channel;
|
||||
static gdma_channel_handle_t tx_channel;
|
||||
static gdma_channel_handle_t s_rx_channel;
|
||||
static gdma_channel_handle_t s_tx_channel;
|
||||
|
||||
/* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
|
||||
static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
|
||||
static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config,
|
||||
gdma_channel_handle_t *tx_channel, gdma_channel_handle_t *rx_channel)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
int time_waited_ms = 0;
|
||||
|
||||
while (1) {
|
||||
#if SOC_AXI_GDMA_SUPPORTED
|
||||
ret = gdma_new_axi_channel(channel_config, channel);
|
||||
ret = gdma_new_axi_channel(channel_config, tx_channel, rx_channel);
|
||||
#else /* !SOC_AXI_GDMA_SUPPORTED */
|
||||
ret = gdma_new_ahb_channel(channel_config, channel);
|
||||
ret = gdma_new_ahb_channel(channel_config, tx_channel, rx_channel);
|
||||
#endif /* SOC_AXI_GDMA_SUPPORTED */
|
||||
if (ret == ESP_OK) {
|
||||
break;
|
||||
} else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) {
|
||||
*channel = NULL;
|
||||
if (tx_channel && *tx_channel) *tx_channel = NULL;
|
||||
if (rx_channel && *rx_channel) *rx_channel = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -67,22 +69,17 @@ static esp_err_t crypto_shared_gdma_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
gdma_channel_alloc_config_t channel_config_tx = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
gdma_channel_alloc_config_t channel_config = {0};
|
||||
|
||||
gdma_channel_alloc_config_t channel_config_rx = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
};
|
||||
|
||||
ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel);
|
||||
// Allocate TX and RX channels separately (they don't need to be in the same pair)
|
||||
ret = crypto_shared_gdma_new_channel(&channel_config, &s_tx_channel, NULL);
|
||||
if (ret != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = crypto_shared_gdma_new_channel(&channel_config_rx, &rx_channel);
|
||||
ret = crypto_shared_gdma_new_channel(&channel_config, NULL, &s_rx_channel);
|
||||
if (ret != ESP_OK) {
|
||||
gdma_del_channel(tx_channel); // Clean up already allocated TX channel
|
||||
gdma_del_channel(s_tx_channel); // Clean up already allocated TX channel
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -90,7 +87,7 @@ static esp_err_t crypto_shared_gdma_init(void)
|
||||
.max_data_burst_size = 16,
|
||||
.access_ext_mem = true, // crypto peripheral may want to access PSRAM
|
||||
};
|
||||
gdma_config_transfer(tx_channel, &transfer_cfg);
|
||||
gdma_config_transfer(s_tx_channel, &transfer_cfg);
|
||||
|
||||
/* When using AHB-GDMA version 1, the max data burst size must be 0, otherwise buffers need to be aligned as well.
|
||||
* Whereas, in case of the other GDMA versions, the RX max burst size is default enabled, but with default burst size of 4,
|
||||
@@ -101,21 +98,21 @@ static esp_err_t crypto_shared_gdma_init(void)
|
||||
transfer_cfg.max_data_burst_size = 0;
|
||||
#endif
|
||||
|
||||
gdma_config_transfer(rx_channel, &transfer_cfg);
|
||||
gdma_config_transfer(s_rx_channel, &transfer_cfg);
|
||||
|
||||
#ifdef SOC_AES_SUPPORTED
|
||||
gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
#elif SOC_SHA_SUPPORTED
|
||||
gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
|
||||
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=%d", ret);
|
||||
tx_channel = NULL;
|
||||
rx_channel = NULL;
|
||||
s_tx_channel = NULL;
|
||||
s_rx_channel = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -141,7 +138,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
{
|
||||
int rx_ch_id = 0;
|
||||
|
||||
if (tx_channel == NULL) {
|
||||
if (s_tx_channel == NULL) {
|
||||
/* Allocate a pair of RX and TX for crypto, should only happen the first time we use the GMDA
|
||||
or if user called esp_crypto_shared_gdma_release */
|
||||
esp_err_t ret = crypto_shared_gdma_init();
|
||||
@@ -151,16 +148,16 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
}
|
||||
|
||||
/* Tx channel is shared between AES and SHA, need to connect to peripheral every time */
|
||||
gdma_disconnect(tx_channel);
|
||||
gdma_disconnect(s_tx_channel);
|
||||
|
||||
#ifdef SOC_SHA_SUPPORTED
|
||||
if (peripheral == GDMA_TRIG_PERIPH_SHA) {
|
||||
gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
|
||||
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
|
||||
} else
|
||||
#endif // SOC_SHA_SUPPORTED
|
||||
#ifdef SOC_AES_SUPPORTED
|
||||
if (peripheral == GDMA_TRIG_PERIPH_AES) {
|
||||
gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
|
||||
} else
|
||||
#endif // SOC_AES_SUPPORTED
|
||||
{
|
||||
@@ -168,7 +165,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
}
|
||||
|
||||
/* tx channel is reset by gdma_connect(), also reset rx to ensure a known state */
|
||||
gdma_get_channel_id(rx_channel, &rx_ch_id);
|
||||
gdma_get_channel_id(s_rx_channel, &rx_ch_id);
|
||||
|
||||
// IDF-14335: Use gdma_reset() instead
|
||||
#if SOC_AXI_GDMA_SUPPORTED
|
||||
@@ -184,7 +181,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
#if (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT && SOC_AXI_GDMA_SUPPORTED)
|
||||
if (efuse_hal_flash_encryption_enabled()) {
|
||||
int tx_ch_id = 0;
|
||||
gdma_get_channel_id(tx_channel, &tx_ch_id);
|
||||
gdma_get_channel_id(s_tx_channel, &tx_ch_id);
|
||||
|
||||
if (check_dma_descs_need_ext_mem_ecc_aes_access(input) || check_dma_descs_need_ext_mem_ecc_aes_access(output)) {
|
||||
axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(&AXI_DMA, rx_ch_id, true);
|
||||
@@ -196,8 +193,8 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
}
|
||||
#endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */
|
||||
|
||||
gdma_start(tx_channel, (intptr_t)input);
|
||||
gdma_start(rx_channel, (intptr_t)output);
|
||||
gdma_start(s_tx_channel, (intptr_t)input);
|
||||
gdma_start(s_rx_channel, (intptr_t)output);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -206,7 +203,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c
|
||||
bool esp_crypto_shared_gdma_done(void)
|
||||
{
|
||||
int rx_ch_id = 0;
|
||||
gdma_get_channel_id(rx_channel, &rx_ch_id);
|
||||
gdma_get_channel_id(s_rx_channel, &rx_ch_id);
|
||||
while (1) {
|
||||
if ((axi_dma_ll_rx_get_interrupt_status(&AXI_DMA, rx_ch_id, true) & 1)) {
|
||||
break;
|
||||
@@ -220,16 +217,16 @@ void esp_crypto_shared_gdma_free()
|
||||
{
|
||||
esp_crypto_sha_aes_lock_acquire();
|
||||
|
||||
if (rx_channel != NULL) {
|
||||
gdma_disconnect(rx_channel);
|
||||
gdma_del_channel(rx_channel);
|
||||
rx_channel = NULL;
|
||||
if (s_rx_channel != NULL) {
|
||||
gdma_disconnect(s_rx_channel);
|
||||
gdma_del_channel(s_rx_channel);
|
||||
s_rx_channel = NULL;
|
||||
}
|
||||
|
||||
if (tx_channel != NULL) {
|
||||
gdma_disconnect(tx_channel);
|
||||
gdma_del_channel(tx_channel);
|
||||
tx_channel = NULL;
|
||||
if (s_tx_channel != NULL) {
|
||||
gdma_disconnect(s_tx_channel);
|
||||
gdma_del_channel(s_tx_channel);
|
||||
s_tx_channel = NULL;
|
||||
}
|
||||
|
||||
esp_crypto_sha_aes_lock_release();
|
||||
|
||||
Reference in New Issue
Block a user