From 96e4fc85a0f970c5543e7e7d7cffd3dd6d23563b Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 22 Jul 2026 16:34:53 +0800 Subject: [PATCH 1/2] refactor(driver_spi): spi driver using dma link list driver --- components/esp_adc/esp32s2/adc_dma.c | 1 + .../include/esp_private/spi_common_internal.h | 16 +-- components/esp_driver_spi/linker.lf | 9 ++ .../esp_driver_spi/src/gpspi/spi_common.c | 131 +++++++++--------- components/esp_driver_spi/src/gpspi/spi_dma.c | 4 +- .../esp_driver_spi/src/gpspi/spi_master.c | 4 +- .../esp_driver_spi/src/gpspi/spi_slave.c | 5 +- .../esp_driver_spi/src/gpspi/spi_slave_hd.c | 81 ++++++----- .../spi_bench_mark/include/spi_performance.h | 24 ++-- .../esp_hal_gpspi/esp32/include/hal/spi_ll.h | 7 +- .../esp32s2/include/hal/spi_ll.h | 5 +- .../include/hal/spi_slave_hd_hal.h | 68 --------- components/esp_hal_gpspi/spi_slave_hd_hal.c | 73 ---------- 13 files changed, 151 insertions(+), 277 deletions(-) diff --git a/components/esp_adc/esp32s2/adc_dma.c b/components/esp_adc/esp32s2/adc_dma.c index fb04619960b..15713cdd3f6 100644 --- a/components/esp_adc/esp32s2/adc_dma.c +++ b/components/esp_adc/esp32s2/adc_dma.c @@ -14,6 +14,7 @@ #include "hal/spi_types.h" #include "hal/spi_ll.h" +#include "soc/lldesc.h" #include "esp_private/spi_common_internal.h" #include "esp_private/adc_dma.h" diff --git a/components/esp_driver_spi/include/esp_private/spi_common_internal.h b/components/esp_driver_spi/include/esp_private/spi_common_internal.h index adc90da881f..255fa27dd65 100644 --- a/components/esp_driver_spi/include/esp_private/spi_common_internal.h +++ b/components/esp_driver_spi/include/esp_private/spi_common_internal.h @@ -17,6 +17,7 @@ #include "hal/dma_types.h" #include "esp_private/spi_dma.h" #include "esp_private/gdma.h" +#include "esp_private/gdma_link.h" #include "esp_private/spi_share_hw_ctrl.h" #if SOC_PAU_SUPPORTED #include "soc/regdma.h" @@ -37,14 +38,6 @@ typedef dma_descriptor_align8_t spi_dma_desc_t; typedef dma_descriptor_align4_t spi_dma_desc_t; #endif -#if SOC_NON_CACHEABLE_OFFSET_SRAM -#include "hal/cache_ll.h" -#define ADDR_DMA_2_CPU(addr) ((typeof(addr))CACHE_LL_L2MEM_NON_CACHE_ADDR(addr)) -#define ADDR_CPU_2_DMA(addr) ((typeof(addr))CACHE_LL_L2MEM_CACHE_ADDR(addr)) -#else -#define ADDR_DMA_2_CPU(addr) (addr) -#define ADDR_CPU_2_DMA(addr) (addr) -#endif // Status of a spi bus typedef enum { @@ -82,6 +75,8 @@ typedef struct { int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. spi_dma_desc_t *dmadesc_tx; ///< DMA descriptor array for TX spi_dma_desc_t *dmadesc_rx; ///< DMA descriptor array for RX + gdma_link_list_handle_t tx_link_handle; ///< DMA tx link list for GDMA and SPIDMA + gdma_link_list_handle_t rx_link_handle; ///< DMA rx link list for GDMA and SPIDMA } spi_dma_ctx_t; #if SOC_PAU_SUPPORTED @@ -145,12 +140,13 @@ esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, in /** * Setupt/Configure dma descriptor link list * - * @param dmadesc start of dma descriptor memory + * @param dma_ctx DMA context pointer + * @param offset offset of the item in the link list * @param data start of data buffer to be configured in * @param len length of data buffer, in byte * @param is_rx if descriptor is for rx/receive direction */ -void spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx); +void spicommon_dma_desc_setup_link(const spi_dma_ctx_t *dma_ctx, int offset, const void *data, int len, bool is_rx); /** * @brief Setup private buffer for DMA transfer diff --git a/components/esp_driver_spi/linker.lf b/components/esp_driver_spi/linker.lf index faa66ce40c9..7c6e867c6db 100644 --- a/components/esp_driver_spi/linker.lf +++ b/components/esp_driver_spi/linker.lf @@ -5,3 +5,12 @@ entries: spi_hal_iram (noflash) if SPI_SLAVE_ISR_IN_IRAM = y: spi_slave_hal_iram (noflash) + +[mapping:gpspi_driver_gdma_link] +archive: libesp_driver_dma.a +entries: + if SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y: + gdma_link: gdma_link_mount_buffers (noflash) + gdma_link: gdma_link_count_buffer_size_till_eof (noflash) + gdma_link: gdma_link_get_buffer (noflash) + gdma_link: gdma_link_get_length (noflash) diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 0653a76dd82..e75f36d9c25 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -22,8 +22,9 @@ #include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h" #include "esp_private/esp_cache_private.h" +#include "esp_private/esp_dma_utils.h" +#include "esp_private/gdma_link.h" #include "esp_private/sleep_retention.h" -#include "esp_dma_utils.h" #include "hal/spi_hal.h" #if SOC_GDMA_SUPPORTED #include "hal/gdma_ll.h" @@ -312,7 +313,7 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch #endif gdma_transfer_config_t trans_cfg = { .max_data_burst_size = burst_size, -#if CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE +#if SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH .access_ext_mem = true, // allow to transfer data from/to external memory directly by DMA #endif }; @@ -355,69 +356,79 @@ cleanup: return ret; } -esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, int *actual_max_sz) +static void spicommon_dma_link_free(spi_host_device_t host_id) { - int dma_desc_ct = (cfg_max_sz + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; - if (dma_desc_ct == 0) { - dma_desc_ct = 1; //default to 4k when max is not given - } - spi_dma_ctx_t *dma_ctx = spi_bus_get_dma_ctx(host_id); if (!dma_ctx) { - return ESP_ERR_INVALID_STATE; + return; } - dma_ctx->dmadesc_tx = heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, 1, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - dma_ctx->dmadesc_rx = heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, 1, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - if (dma_ctx->dmadesc_tx == NULL || dma_ctx->dmadesc_rx == NULL) { - if (dma_ctx->dmadesc_tx) { - free(dma_ctx->dmadesc_tx); - dma_ctx->dmadesc_tx = NULL; - } - if (dma_ctx->dmadesc_rx) { - free(dma_ctx->dmadesc_rx); - dma_ctx->dmadesc_rx = NULL; - } - return ESP_ERR_NO_MEM; + if (dma_ctx->tx_link_handle) { + gdma_del_link_list(dma_ctx->tx_link_handle); + dma_ctx->tx_link_handle = NULL; + } + if (dma_ctx->rx_link_handle) { + gdma_del_link_list(dma_ctx->rx_link_handle); + dma_ctx->rx_link_handle = NULL; } - // cache sync using align_up length thanks to heap alloc already consider the cache alignment requirement - size_t aligned_len = ESP_ALIGN_UP(sizeof(spi_dma_desc_t) * dma_desc_ct, bus_ctx[host_id]->bus_attr.cache_align_int); - // write back and then invalidate the cache, because later we will read/write the link list items by non-cached address - esp_err_t ret = esp_cache_msync(dma_ctx->dmadesc_tx, aligned_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); - ESP_RETURN_ON_FALSE_ISR((ret == ESP_OK) || (ret == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_ARG, SPI_TAG, "dma desc sync failed"); - ret = esp_cache_msync(dma_ctx->dmadesc_rx, aligned_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); - ESP_RETURN_ON_FALSE_ISR((ret == ESP_OK) || (ret == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_ARG, SPI_TAG, "dma desc sync failed"); - - dma_ctx->dma_desc_num = dma_desc_ct; - *actual_max_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; - return ESP_OK; } -void SPI_COMMON_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx) +esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, int *actual_max_sz) { - dmadesc = ADDR_DMA_2_CPU(dmadesc); - int n = 0; - while (len) { - int dmachunklen = len; - if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) { - dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; - } - if (is_rx) { - //Receive needs DMA length rounded to next 32-bit boundary - dmadesc[n].dw0.size = (dmachunklen + 3) & (~3); - } else { - dmadesc[n].dw0.size = dmachunklen; - dmadesc[n].dw0.length = dmachunklen; - } - dmadesc[n].buffer = (uint8_t *)data; - dmadesc[n].dw0.suc_eof = 0; - dmadesc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]); - len -= dmachunklen; - data += dmachunklen; - n++; + esp_err_t ret = ESP_OK; + spi_dma_ctx_t *dma_ctx = spi_bus_get_dma_ctx(host_id); + ESP_RETURN_ON_FALSE(dma_ctx, ESP_ERR_INVALID_STATE, SPI_TAG, "dma context not initialized"); + size_t tx_buffer_alignment = dma_ctx->dma_align_tx_int ? dma_ctx->dma_align_tx_int : 1; + size_t rx_buffer_alignment = dma_ctx->dma_align_rx_int ? dma_ctx->dma_align_rx_int : 1; + if (dma_ctx->dma_align_tx_ext < BIT(31)) { + tx_buffer_alignment = MAX(tx_buffer_alignment, dma_ctx->dma_align_tx_ext); } - dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream. - dmadesc[n - 1].next = NULL; + if (dma_ctx->dma_align_rx_ext < BIT(31)) { + rx_buffer_alignment = MAX(rx_buffer_alignment, dma_ctx->dma_align_rx_ext); + } + + size_t tx_item_num = esp_dma_calculate_node_count(cfg_max_sz, tx_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE); + size_t rx_item_num = esp_dma_calculate_node_count(cfg_max_sz, rx_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE); + gdma_link_list_config_t link_cfg = { + .num_items = MAX(MAX(tx_item_num, rx_item_num), 1), //default to 1 when 'cfg_max_sz' is not given + .item_alignment = DMA_DESC_MEM_ALIGN_SIZE, + }; + ESP_RETURN_ON_ERROR(gdma_new_link_list(&link_cfg, &dma_ctx->tx_link_handle), SPI_TAG, "failed to allocate tx dma link"); + ESP_GOTO_ON_ERROR(gdma_new_link_list(&link_cfg, &dma_ctx->rx_link_handle), cleanup, SPI_TAG, "failed to allocate rx dma link"); + + // save link info + dma_ctx->dma_desc_num = link_cfg.num_items; + dma_ctx->dmadesc_tx = (spi_dma_desc_t *)gdma_link_get_head_addr(dma_ctx->tx_link_handle); + dma_ctx->dmadesc_rx = (spi_dma_desc_t *)gdma_link_get_head_addr(dma_ctx->rx_link_handle); + *actual_max_sz = dma_ctx->dma_desc_num * ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, rx_buffer_alignment); + return ESP_OK; + +cleanup: + spicommon_dma_link_free(host_id); + return ret; +} + +void SPI_COMMON_ISR_ATTR spicommon_dma_desc_setup_link(const spi_dma_ctx_t *dma_ctx, int offset, const void *data, int len, bool is_rx) +{ + size_t buffer_alignment; + if (esp_ptr_internal(data)) { + buffer_alignment = is_rx ? dma_ctx->dma_align_rx_int : dma_ctx->dma_align_tx_int; + } else { + buffer_alignment = is_rx ? dma_ctx->dma_align_rx_ext : dma_ctx->dma_align_tx_ext; + } + + gdma_buffer_mount_config_t mount_config = { + .buffer = (void *)data, + .buffer_alignment = buffer_alignment, + .length = is_rx ? ESP_ALIGN_UP(len, 4) : len, // dma rx hardware requires 4 bytes alignment + .flags = { + .mark_eof = true, + .mark_final = GDMA_FINAL_LINK_TO_NULL, + .bypass_buffer_align_check = true, // 'setup_priv_buffer' already do the check + } + }; + esp_err_t ret = gdma_link_mount_buffers(is_rx ? dma_ctx->rx_link_handle : dma_ctx->tx_link_handle, offset, &mount_config, 1, NULL); + assert(ret == ESP_OK); + (void)ret; } esp_err_t SPI_COMMON_ISR_ATTR spicommon_dma_setup_priv_buffer(spi_host_device_t host_id, uint32_t *buffer, uint32_t len, bool is_tx, bool psram_prefer, bool auto_malloc, uint32_t **ret_buffer) @@ -508,13 +519,7 @@ esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id) gdma_del_channel(dma_ctx->tx_dma_chan); } #endif - - if (dma_ctx->dmadesc_tx) { - free(dma_ctx->dmadesc_tx); - } - if (dma_ctx->dmadesc_rx) { - free(dma_ctx->dmadesc_rx); - } + spicommon_dma_link_free(host_id); free(dma_ctx); spi_dma_ctx[host_id] = NULL; return ESP_OK; diff --git a/components/esp_driver_spi/src/gpspi/spi_dma.c b/components/esp_driver_spi/src/gpspi/spi_dma.c index 14d54e3e467..14386f38a52 100644 --- a/components/esp_driver_spi/src/gpspi/spi_dma.c +++ b/components/esp_driver_spi/src/gpspi/spi_dma.c @@ -79,8 +79,8 @@ void SPI_DMA_ISR_ATTR spi_dma_start(spi_dma_chan_handle_t chan_handle, void *add spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id); if (chan_handle.dir == DMA_CHANNEL_DIRECTION_TX) { - spi_ll_dma_tx_start(spi_dma, chan_handle.chan_id, (lldesc_t *)addr); + spi_ll_dma_tx_start(spi_dma, chan_handle.chan_id, addr); } else { - spi_ll_dma_rx_start(spi_dma, chan_handle.chan_id, (lldesc_t *)addr); + spi_ll_dma_rx_start(spi_dma, chan_handle.chan_id, addr); } } diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index 7b09f236cfc..35a94ad2bbf 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -737,7 +737,7 @@ static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal const spi_dma_ctx_t *dma_ctx = host->dma_ctx; if (trans->rcv_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); + spicommon_dma_desc_setup_link(dma_ctx, 0, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); spi_dma_reset(dma_ctx->rx_dma_chan); spi_hal_hw_prepare_rx(hal->hw); @@ -751,7 +751,7 @@ static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal } #endif if (trans->send_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); + spicommon_dma_desc_setup_link(dma_ctx, 0, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); spi_dma_reset(dma_ctx->tx_dma_chan); spi_hal_hw_prepare_tx(hal->hw); diff --git a/components/esp_driver_spi/src/gpspi/spi_slave.c b/components/esp_driver_spi/src/gpspi/spi_slave.c index ec041bb5c43..ac02dd8a6f2 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave.c @@ -17,7 +17,6 @@ #include "esp_cache.h" #include "esp_heap_caps.h" #include "esp_rom_sys.h" -#include "soc/lldesc.h" #include "soc/soc_caps.h" #include "soc/spi_periph.h" #include "soc/soc_memory_layout.h" @@ -602,14 +601,14 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_tr static void SPI_SLAVE_ISR_ATTR s_spi_slave_dma_prepare_data(spi_dma_ctx_t *dma_ctx, spi_slave_hal_context_t *hal) { if (hal->rx_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, hal->rx_buffer, (hal->rx_bitlen + 7) / 8, true); + spicommon_dma_desc_setup_link(dma_ctx, 0, hal->rx_buffer, (hal->rx_bitlen + 7) / 8, true); spi_dma_reset(dma_ctx->rx_dma_chan); spi_slave_hal_hw_prepare_rx(hal->hw); spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx); } if (hal->tx_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, hal->tx_buffer, (hal->tx_bitlen + 7) / 8, false); + spicommon_dma_desc_setup_link(dma_ctx, 0, hal->tx_buffer, (hal->tx_bitlen + 7) / 8, false); spi_dma_reset(dma_ctx->tx_dma_chan); spi_slave_hal_hw_prepare_tx(hal->hw); diff --git a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c index ea004ba2001..d0ee8aa26d4 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c @@ -488,7 +488,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) spicommon_dma_rx_mb(host->host_id, host->rx_curr_trans.aligned_buffer); spi_slave_hd_rx_dma_error_check(host, host->rx_curr_trans); bool ret_queue = true; - host->rx_curr_trans.trans->trans_len = spi_slave_hd_hal_rxdma_seg_get_len(hal); + host->rx_curr_trans.trans->trans_len = gdma_link_count_buffer_size_till_eof(host->dma_ctx->rx_link_handle, 0); if (callback->cb_recv) { spi_slave_hd_event_t ev = { .event = SPI_EV_RECV, @@ -511,7 +511,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) if (!host->tx_curr_trans.trans) { ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_curr_trans, &awoken); if ((ret == pdTRUE) && host->tx_curr_trans.trans) { - spicommon_dma_desc_setup_link(hal->dmadesc_tx->desc, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len, false); + spicommon_dma_desc_setup_link(host->dma_ctx, 0, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len, false); spi_dma_reset(host->dma_ctx->tx_dma_chan); spi_slave_hd_hal_txdma(hal); spi_dma_start(host->dma_ctx->tx_dma_chan, host->dma_ctx->dmadesc_tx); @@ -530,7 +530,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) if (!host->rx_curr_trans.trans) { ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_curr_trans, &awoken); if ((ret == pdTRUE) && host->rx_curr_trans.trans) { - spicommon_dma_desc_setup_link(hal->dmadesc_rx->desc, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len, true); + spicommon_dma_desc_setup_link(host->dma_ctx, 0, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len, true); spi_dma_reset(host->dma_ctx->rx_dma_chan); spi_slave_hd_hal_rxdma(hal); spi_dma_start(host->dma_ctx->rx_dma_chan, host->dma_ctx->dmadesc_rx); @@ -561,6 +561,15 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) } } +static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(spi_slave_hd_hal_desc_append_t *desc_head, uint32_t desc_num, spi_slave_hd_hal_desc_append_t **p_desc, uint32_t steps) +{ + steps %= desc_num; + *p_desc += steps; + if (*p_desc >= (desc_head + desc_num)) { + *p_desc -= desc_num; + } +} + static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_tx_isr(void *arg) { spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg; @@ -569,13 +578,14 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_tx_isr(void *arg) BaseType_t awoken = pdFALSE; BaseType_t ret __attribute__((unused)); - spi_slave_hd_trans_priv_t ret_priv_trans = {}; - while (1) { - bool trans_finish = false; - trans_finish = spi_slave_hd_hal_get_tx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer); - if (!trans_finish) { - break; - } + while ((uint32_t)hal->tx_dma_head->desc != hal->current_eof_addr) { + slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_dma_head, 1); + int offset = hal->tx_dma_head - hal->dmadesc_tx; + spi_slave_hd_trans_priv_t ret_priv_trans = { + .trans = hal->tx_dma_head->arg, + .aligned_buffer = gdma_link_get_buffer(host->dma_ctx->tx_link_handle, offset), + }; + portENTER_CRITICAL_ISR(&host->int_spinlock); hal->tx_used_desc_cnt--; portEXIT_CRITICAL_ISR(&host->int_spinlock); @@ -613,18 +623,18 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_rx_isr(void *arg) BaseType_t awoken = pdFALSE; BaseType_t ret __attribute__((unused)); - spi_slave_hd_trans_priv_t ret_priv_trans = {}; - size_t trans_len; - while (1) { - bool trans_finish = false; - trans_finish = spi_slave_hd_hal_get_rx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer, &trans_len); - if (!trans_finish) { - break; - } + while ((uint32_t)hal->rx_dma_head->desc != hal->current_eof_addr) { + slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_dma_head, 1); + int offset = hal->rx_dma_head - hal->dmadesc_rx; + spi_slave_hd_trans_priv_t ret_priv_trans = { + .trans = hal->rx_dma_head->arg, + .aligned_buffer = gdma_link_get_buffer(host->dma_ctx->rx_link_handle, offset), + }; + ret_priv_trans.trans->trans_len = gdma_link_get_length(host->dma_ctx->rx_link_handle, offset); + portENTER_CRITICAL_ISR(&host->int_spinlock); hal->rx_used_desc_cnt--; portEXIT_CRITICAL_ISR(&host->int_spinlock); - ret_priv_trans.trans->trans_len = trans_len; bool ret_queue = true; spicommon_dma_rx_mb(host->host_id, ret_priv_trans.aligned_buffer); @@ -745,13 +755,16 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, spi_slave_hd_hal_context_t *hal = &host->hal; //Check if there are enough available DMA descriptors for software to use - int num_required = (len + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_tx_int : host->dma_ctx->dma_align_tx_ext; + // unsupported buffer which lead invalid buf_align should already checked by 'setup_priv_trans' + int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align)); int available_desc_num = hal->dma_desc_num - hal->tx_used_desc_cnt; if (num_required > available_desc_num) { return ESP_ERR_INVALID_STATE; } - spicommon_dma_desc_setup_link(hal->tx_cur_desc->desc, data, len, false); + int offset = hal->tx_cur_desc - hal->dmadesc_tx; + spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, false); hal->tx_cur_desc->arg = arg; if (!hal->tx_used_desc_cnt) { @@ -762,7 +775,8 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, spi_dma_start(host->dma_ctx->tx_dma_chan, hal->tx_cur_desc->desc); } else { //there is already a consecutive link - ADDR_DMA_2_CPU(hal->tx_dma_tail->desc)->next = hal->tx_cur_desc->desc; + gdma_link_list_handle_t link_handle = host->dma_ctx->tx_link_handle; + gdma_link_concat(link_handle, offset - 1, link_handle, offset); hal->tx_dma_tail = hal->tx_cur_desc; spi_dma_append(host->dma_ctx->tx_dma_chan); } @@ -771,12 +785,7 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, portENTER_CRITICAL(&host->int_spinlock); hal->tx_used_desc_cnt += num_required; portEXIT_CRITICAL(&host->int_spinlock); - for (int i = 0; i < num_required; i++) { - hal->tx_cur_desc++; - if (hal->tx_cur_desc == hal->dmadesc_tx + hal->dma_desc_num) { - hal->tx_cur_desc = hal->dmadesc_tx; - } - } + slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_cur_desc, num_required); return ESP_OK; } @@ -786,13 +795,15 @@ esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, spi_slave_hd_hal_context_t *hal = &host->hal; //Check if there are enough available dma descriptors for software to use - int num_required = (len + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_rx_int : host->dma_ctx->dma_align_rx_ext; + int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align)); int available_desc_num = hal->dma_desc_num - hal->rx_used_desc_cnt; if (num_required > available_desc_num) { return ESP_ERR_INVALID_STATE; } - spicommon_dma_desc_setup_link(hal->rx_cur_desc->desc, data, len, true); + int offset = hal->rx_cur_desc - hal->dmadesc_rx; + spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, true); hal->rx_cur_desc->arg = arg; if (!hal->rx_used_desc_cnt) { @@ -803,7 +814,8 @@ esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, spi_dma_start(host->dma_ctx->rx_dma_chan, hal->rx_cur_desc->desc); } else { //there is already a consecutive link - ADDR_DMA_2_CPU(hal->rx_dma_tail->desc)->next = hal->rx_cur_desc->desc; + gdma_link_list_handle_t link_handle = host->dma_ctx->rx_link_handle; + gdma_link_concat(link_handle, offset - 1, link_handle, offset); hal->rx_dma_tail = hal->rx_cur_desc; spi_dma_append(host->dma_ctx->rx_dma_chan); } @@ -812,12 +824,7 @@ esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, portENTER_CRITICAL(&host->int_spinlock); hal->rx_used_desc_cnt += num_required; portEXIT_CRITICAL(&host->int_spinlock); - for (int i = 0; i < num_required; i++) { - hal->rx_cur_desc++; - if (hal->rx_cur_desc == hal->dmadesc_rx + hal->dma_desc_num) { - hal->rx_cur_desc = hal->dmadesc_rx; - } - } + slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_cur_desc, num_required); return ESP_OK; } diff --git a/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h b/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h index efdeb320b2d..eb24466403b 100644 --- a/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h +++ b/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h @@ -10,7 +10,7 @@ #if CONFIG_IDF_TARGET_ESP32 #define IDF_TARGET_MAX_SPI_CLK_FREQ 16*1000*1000 -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 15 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 20 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15 #if !CONFIG_FREERTOS_SMP // IDF-5826 #define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 34 // TODO: IDF-5180 @@ -29,27 +29,27 @@ #elif CONFIG_IDF_TARGET_ESP32S3 #define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000 -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 20 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15 -#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 32 +#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 34 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 30 #elif CONFIG_IDF_TARGET_ESP32C2 #define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000 -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 23 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 28 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 18 -#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 47 +#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 52 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 42 #elif CONFIG_IDF_TARGET_ESP32C3 #define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000 #if !CONFIG_FREERTOS_SMP // IDF-5826 -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 21 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15 -#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 35 +#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 37 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 30 #else -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 21 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 17 #define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 60 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 60 @@ -57,16 +57,16 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #define IDF_TARGET_MAX_SPI_CLK_FREQ 26666*1000 -#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 37 //TODO: IDF-9551, check perform -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 19 +#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 38 //TODO: IDF-9551, check perform +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 22 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 32 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15 #elif CONFIG_IDF_TARGET_ESP32H2 #define IDF_TARGET_MAX_SPI_CLK_FREQ 24*1000*1000 -#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 32 +#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 35 #define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 25 -#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 61 +#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 64 #define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 54 #elif CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h index f79e9a4648f..90025ae2587 100644 --- a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,6 @@ #include #include //for abs() #include "esp_types.h" -#include "esp32/rom/lldesc.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" #include "soc/dport_reg.h" @@ -1159,7 +1158,7 @@ static inline void spi_ll_dma_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) * @param addr Address of the beginning DMA descriptor. */ __attribute__((always_inline)) -static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) +static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, void *addr) { dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.start = 1; @@ -1224,7 +1223,7 @@ static inline void spi_ll_dma_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) * @param addr Address of the beginning DMA descriptor. */ __attribute__((always_inline)) -static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) +static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, void *addr) { dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.start = 1; diff --git a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h index a684ac5c1cd..d7ab3ef5764 100644 --- a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h @@ -21,7 +21,6 @@ #include "soc/spi_struct.h" #include "soc/spi_reg.h" #include "soc/dport_reg.h" -#include "soc/lldesc.h" #include "soc/soc_caps.h" #include "hal/assert.h" #include "hal/misc.h" @@ -1331,7 +1330,7 @@ static inline void spi_ll_dma_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) * @param addr Address of the beginning DMA descriptor. */ __attribute__((always_inline)) -static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) +static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, void *addr) { dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.start = 1; @@ -1423,7 +1422,7 @@ static inline void spi_ll_dma_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) * @param addr Address of the beginning DMA descriptor. */ __attribute__((always_inline)) -static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) +static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, void *addr) { dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.start = 1; diff --git a/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h b/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h index 6d59f6c295f..e1109220f8b 100644 --- a/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h +++ b/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h @@ -105,8 +105,6 @@ typedef struct { /* address of the hardware */ spi_dev_t *dev; ///< Beginning address of the peripheral registers. - bool dma_enabled; ///< DMA enabled or not - bool append_mode; ///< True for DMA append mode, false for segment mode uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``. uint32_t current_eof_addr; spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up). @@ -193,14 +191,6 @@ void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_eve */ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal); -/** - * @brief Get the length of total received data - * - * @param hal Context of the HAL layer - * @return The received length - */ -int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal); - /** * @brief Prepare hardware for a new dma rx trans * @@ -266,64 +256,6 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal); */ int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal); -//////////////////////////////////////////////////////////////////////////////// -// Append Mode -//////////////////////////////////////////////////////////////////////////////// -/** - * @brief Return the finished TX transaction - * - * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer. - * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour, - * this API will go wrong. - * - * @param hal Context of the HAL layer - * @param out_trans Pointer to the caller-defined transaction - * @param real_buff_addr Actually data buffer head the HW used - * @return 1: Transaction is finished; 0: Transaction is not finished - */ -bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr); - -/** - * @brief Return the finished RX transaction - * - * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer. - * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour, - * this API will go wrong. - * - * @param hal Context of the HAL layer - * @param out_trans Pointer to the caller-defined transaction - * @param real_buff_addr Actually data buffer head the HW used - * @param out_len Actual number of bytes of received data - * @return 1: Transaction is finished; 0: Transaction is not finished - */ -bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len); - -/** - * @brief Load the TX DMA descriptors without stopping the DMA - * - * @param hal Context of the HAL layer - * @param data Buffer of the transaction data - * @param len Length of the data - * @param arg Pointer used by the caller to indicate the transaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished - * @return - * - ESP_OK: on success - * - ESP_ERR_INVALID_STATE: Function called in invalid state. - */ -esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg); - -/** - * @brief Load the RX DMA descriptors without stopping the DMA - * - * @param hal Context of the HAL layer - * @param data Buffer of the transaction data - * @param len Length of the data - * @param arg Pointer used by the caller to indicate the transaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished - * @return - * - ESP_OK: on success - * - ESP_ERR_INVALID_STATE: Function called in invalid state. - */ -esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg); - #endif //#if SOC_GPSPI_SUPPORTED #ifdef __cplusplus diff --git a/components/esp_hal_gpspi/spi_slave_hd_hal.c b/components/esp_hal_gpspi/spi_slave_hd_hal.c index b03e8dab44c..b1e543b0fb1 100644 --- a/components/esp_hal_gpspi/spi_slave_hd_hal.c +++ b/components/esp_hal_gpspi/spi_slave_hd_hal.c @@ -10,9 +10,7 @@ #include "esp_types.h" #include "esp_attr.h" #include "esp_err.h" -#include "soc/lldesc.h" #include "soc/soc_caps.h" -#include "soc/soc.h" //for SOC_NON_CACHEABLE_OFFSET_SRAM #include "soc/spi_periph.h" #include "hal/spi_slave_hd_hal.h" #include "hal/assert.h" @@ -21,8 +19,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h { spi_dev_t *hw = spi_periph_signal[hal_config->host_id].hw; hal->dev = hw; - hal->dma_enabled = hal_config->dma_enabled; - hal->append_mode = hal_config->append_mode; hal->tx_cur_desc = hal->dmadesc_tx; hal->rx_cur_desc = hal->dmadesc_rx; hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num - 1; @@ -70,37 +66,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h spi_ll_slave_set_seg_mode(hal->dev, true); } -#if SOC_NON_CACHEABLE_OFFSET_SRAM -#include "hal/cache_ll.h" -#define ADDR_DMA_2_CPU(addr) ((typeof(addr))CACHE_LL_L2MEM_NON_CACHE_ADDR(addr)) -#define ADDR_CPU_2_DMA(addr) ((typeof(addr))CACHE_LL_L2MEM_CACHE_ADDR(addr)) -#else -#define ADDR_DMA_2_CPU(addr) (addr) -#define ADDR_CPU_2_DMA(addr) (addr) -#endif - -static int s_desc_get_received_len_addr(spi_dma_desc_t* head, spi_dma_desc_t** out_next, void **out_buff_head) -{ - spi_dma_desc_t* desc_cpu = ADDR_DMA_2_CPU(head); - int len = 0; - if (out_buff_head) { - *out_buff_head = desc_cpu->buffer; - } - while (head) { - len += desc_cpu->dw0.length; - bool eof = desc_cpu->dw0.suc_eof; - desc_cpu = ADDR_DMA_2_CPU(desc_cpu->next); - head = head->next; - if (eof) { - break; - } - } - if (out_next) { - *out_next = head; - } - return len; -} - void spi_slave_hd_hal_hw_prepare_rx(spi_slave_hd_hal_context_t *hal) { spi_ll_dma_rx_fifo_reset(hal->dev); @@ -234,41 +199,3 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal) //this is by -byte return spi_ll_slave_get_rx_byte_len(hal->dev); } - -int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal) -{ - spi_dma_desc_t *desc = hal->dmadesc_rx->desc; - return s_desc_get_received_len_addr(desc, NULL, NULL); -} - -bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr) -{ - if ((uint32_t)hal->tx_dma_head->desc == hal->current_eof_addr) { - return false; - } - - //find used paired desc-trans by desc addr - hal->tx_dma_head++; - if (hal->tx_dma_head >= hal->dmadesc_tx + hal->dma_desc_num) { - hal->tx_dma_head = hal->dmadesc_tx; - } - *out_trans = hal->tx_dma_head->arg; - s_desc_get_received_len_addr(hal->tx_dma_head->desc, NULL, real_buff_addr); - return true; -} - -bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len) -{ - if ((uint32_t)hal->rx_dma_head->desc == hal->current_eof_addr) { - return false; - } - - //find used paired desc-trans by desc addr - hal->rx_dma_head++; - if (hal->rx_dma_head >= hal->dmadesc_rx + hal->dma_desc_num) { - hal->rx_dma_head = hal->dmadesc_rx; - } - *out_trans = hal->rx_dma_head->arg; - *out_len = s_desc_get_received_len_addr(hal->rx_dma_head->desc, NULL, real_buff_addr); - return true; -} From 9ce985dca078e19e70435b9162b6d4e25058be90 Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 29 Jul 2026 16:26:54 +0800 Subject: [PATCH 2/2] refactor(driver_spi): slave hd move dma context to driver layer --- .../esp_driver_spi/src/gpspi/spi_slave_hd.c | 119 +++++++++++------- .../include/hal/spi_slave_hd_hal.h | 36 ------ components/esp_hal_gpspi/spi_slave_hd_hal.c | 4 - 3 files changed, 76 insertions(+), 83 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c index d0ee8aa26d4..081edb55fbc 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c @@ -5,6 +5,7 @@ */ #include +#include #include "esp_compiler.h" #include "esp_log.h" #include "esp_check.h" @@ -41,6 +42,26 @@ typedef struct { bool dma_hw_error; //true if DMA hardware over/underflow occurred } spi_slave_hd_trans_priv_t; +typedef struct { + spi_dma_desc_t *desc; // DMA descriptor + void *arg; // Original transaction descriptor +} slave_hd_append_desc_t; + +/** append dma pool layout + * + * |**********............-------*******| + * ^ ^ ^ ^ + * | | | | + * root done hw_eof free + */ +typedef struct { + slave_hd_append_desc_t *desc_root; ///< Root of the DMA descriptors. + slave_hd_append_desc_t *free_desc; ///< Current DMA descriptor that could be linked (set up). + slave_hd_append_desc_t *done_desc; ///< Head of the finished descriptors which are not dealed by software + uint32_t eof_desc; ///< DMA desc of current end + uint32_t used_desc_cnt; ///< Number of the descriptors that have been setup +} slave_hd_append_context_t; + typedef struct { spi_host_device_t host_id; int cs_io_num; @@ -53,6 +74,8 @@ typedef struct { spi_slave_hd_callback_config_t callback; spi_slave_hd_hal_context_t hal; bool append_mode; + slave_hd_append_context_t append_tx_ctx; + slave_hd_append_context_t append_rx_ctx; QueueHandle_t tx_trans_queue; QueueHandle_t tx_ret_queue; @@ -113,6 +136,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b SPIHD_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG); #endif SPIHD_CHECK(!three_wire_mode || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "mosi pin must be output capable in 3-wire mode", ESP_ERR_INVALID_ARG); + SPIHD_CHECK(!append_mode || bus_config->max_transfer_sz > SPI_MAX_DMA_LEN, "max_transfer_sz must greater than 4092 to using append mode", ESP_ERR_INVALID_ARG); SPIHD_CHECK(ESP_OK == spicommon_bus_alloc(host_id, "slave_hd"), "host already in use", ESP_ERR_INVALID_STATE); // spi_slave_hd_slot_t contains atomic variable, memory must be allocated from internal memory @@ -149,18 +173,24 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b goto cleanup; } - host->hal.dma_desc_num = host->dma_ctx->dma_desc_num; - host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT); - host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT); - if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx)) { + slave_hd_append_context_t *append_tx = &host->append_tx_ctx; + slave_hd_append_context_t *append_rx = &host->append_rx_ctx; + uint32_t dma_desc_num = host->dma_ctx->dma_desc_num; + append_tx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT); + append_rx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT); + if (!(append_tx->desc_root && append_rx->desc_root)) { ret = ESP_ERR_NO_MEM; goto cleanup; } //Pair each desc to each possible trans - for (int i = 0; i < host->hal.dma_desc_num; i ++) { - host->hal.dmadesc_tx[i].desc = &host->dma_ctx->dmadesc_tx[i]; - host->hal.dmadesc_rx[i].desc = &host->dma_ctx->dmadesc_rx[i]; + for (int i = 0; i < dma_desc_num; i ++) { + append_tx->desc_root[i].desc = &host->dma_ctx->dmadesc_tx[i]; + append_rx->desc_root[i].desc = &host->dma_ctx->dmadesc_rx[i]; } + append_tx->free_desc = append_tx->desc_root; + append_rx->free_desc = append_rx->desc_root; + append_tx->done_desc = append_tx->desc_root + dma_desc_num - 1; + append_rx->done_desc = append_rx->desc_root + dma_desc_num - 1; ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, NULL); if (ret != ESP_OK) { @@ -350,8 +380,8 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id) spicommon_bus_free_io_cfg(host_id); spicommon_cs_free_io(host->cs_io_num, &host->bus_attr->gpio_reserve); - free(host->hal.dmadesc_tx); - free(host->hal.dmadesc_rx); + free(host->append_tx_ctx.desc_root); + free(host->append_rx_ctx.desc_root); spicommon_dma_chan_free(host_id); spicommon_bus_free(host_id); @@ -561,7 +591,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) } } -static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(spi_slave_hd_hal_desc_append_t *desc_head, uint32_t desc_num, spi_slave_hd_hal_desc_append_t **p_desc, uint32_t steps) +static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(slave_hd_append_desc_t *desc_head, uint32_t desc_num, slave_hd_append_desc_t **p_desc, uint32_t steps) { steps %= desc_num; *p_desc += steps; @@ -574,20 +604,21 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_tx_isr(void *arg) { spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg; spi_slave_hd_callback_config_t *callback = &host->callback; - spi_slave_hd_hal_context_t *hal = &host->hal; + slave_hd_append_context_t *append = &host->append_tx_ctx; + uint32_t dma_desc_num = host->dma_ctx->dma_desc_num; BaseType_t awoken = pdFALSE; BaseType_t ret __attribute__((unused)); - while ((uint32_t)hal->tx_dma_head->desc != hal->current_eof_addr) { - slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_dma_head, 1); - int offset = hal->tx_dma_head - hal->dmadesc_tx; + while ((uint32_t)append->done_desc->desc != append->eof_desc) { + slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1); + int offset = append->done_desc - append->desc_root; spi_slave_hd_trans_priv_t ret_priv_trans = { - .trans = hal->tx_dma_head->arg, + .trans = append->done_desc->arg, .aligned_buffer = gdma_link_get_buffer(host->dma_ctx->tx_link_handle, offset), }; portENTER_CRITICAL_ISR(&host->int_spinlock); - hal->tx_used_desc_cnt--; + append->used_desc_cnt--; portEXIT_CRITICAL_ISR(&host->int_spinlock); bool ret_queue = true; @@ -619,21 +650,22 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_rx_isr(void *arg) { spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg; spi_slave_hd_callback_config_t *callback = &host->callback; - spi_slave_hd_hal_context_t *hal = &host->hal; + slave_hd_append_context_t *append = &host->append_rx_ctx; + uint32_t dma_desc_num = host->dma_ctx->dma_desc_num; BaseType_t awoken = pdFALSE; BaseType_t ret __attribute__((unused)); - while ((uint32_t)hal->rx_dma_head->desc != hal->current_eof_addr) { - slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_dma_head, 1); - int offset = hal->rx_dma_head - hal->dmadesc_rx; + while ((uint32_t)append->done_desc->desc != append->eof_desc) { + slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1); + int offset = append->done_desc - append->desc_root; spi_slave_hd_trans_priv_t ret_priv_trans = { - .trans = hal->rx_dma_head->arg, + .trans = append->done_desc->arg, .aligned_buffer = gdma_link_get_buffer(host->dma_ctx->rx_link_handle, offset), }; ret_priv_trans.trans->trans_len = gdma_link_get_length(host->dma_ctx->rx_link_handle, offset); portENTER_CRITICAL_ISR(&host->int_spinlock); - hal->rx_used_desc_cnt--; + append->used_desc_cnt--; portEXIT_CRITICAL_ISR(&host->int_spinlock); bool ret_queue = true; @@ -668,10 +700,11 @@ static SPI_SLAVE_ISR_ATTR bool s_spi_slave_hd_append_gdma_isr(gdma_channel_handl assert(event_data); spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)user_data; - host->hal.current_eof_addr = event_data->tx_eof_desc_addr; if (host->dma_ctx->tx_dma_chan == dma_chan) { + host->append_tx_ctx.eof_desc = event_data->tx_eof_desc_addr; spi_slave_hd_append_tx_isr(user_data); } else { + host->append_rx_ctx.eof_desc = event_data->rx_eof_desc_addr; spi_slave_hd_append_rx_isr(user_data); } return true; @@ -687,11 +720,11 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_append_legacy_isr(void *arg) portENTER_CRITICAL_ISR(&host->int_spinlock); if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_RECV)) { - hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan); + host->append_rx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan); rx_done = true; } if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_SEND)) { - hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan); + host->append_tx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan); tx_done = true; } portEXIT_CRITICAL_ISR(&host->int_spinlock); @@ -753,39 +786,39 @@ static esp_err_t get_ret_queue_result(spi_host_device_t host_id, spi_slave_chan_ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg) { spi_slave_hd_hal_context_t *hal = &host->hal; + slave_hd_append_context_t *append = &host->append_tx_ctx; + uint32_t dma_desc_num = host->dma_ctx->dma_desc_num; //Check if there are enough available DMA descriptors for software to use int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_tx_int : host->dma_ctx->dma_align_tx_ext; // unsupported buffer which lead invalid buf_align should already checked by 'setup_priv_trans' int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align)); - int available_desc_num = hal->dma_desc_num - hal->tx_used_desc_cnt; + int available_desc_num = dma_desc_num - append->used_desc_cnt; if (num_required > available_desc_num) { return ESP_ERR_INVALID_STATE; } - int offset = hal->tx_cur_desc - hal->dmadesc_tx; + int offset = append->free_desc - append->desc_root; spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, false); - hal->tx_cur_desc->arg = arg; + append->free_desc->arg = arg; - if (!hal->tx_used_desc_cnt) { + if (!append->used_desc_cnt) { //start a link - hal->tx_dma_tail = hal->tx_cur_desc; spi_dma_reset(host->dma_ctx->tx_dma_chan); spi_slave_hd_hal_hw_prepare_tx(hal); - spi_dma_start(host->dma_ctx->tx_dma_chan, hal->tx_cur_desc->desc); + spi_dma_start(host->dma_ctx->tx_dma_chan, append->free_desc->desc); } else { //there is already a consecutive link gdma_link_list_handle_t link_handle = host->dma_ctx->tx_link_handle; gdma_link_concat(link_handle, offset - 1, link_handle, offset); - hal->tx_dma_tail = hal->tx_cur_desc; spi_dma_append(host->dma_ctx->tx_dma_chan); } //Move the current descriptor pointer according to the number of the linked descriptors portENTER_CRITICAL(&host->int_spinlock); - hal->tx_used_desc_cnt += num_required; + append->used_desc_cnt += num_required; portEXIT_CRITICAL(&host->int_spinlock); - slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_cur_desc, num_required); + slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required); return ESP_OK; } @@ -793,38 +826,38 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg) { spi_slave_hd_hal_context_t *hal = &host->hal; + slave_hd_append_context_t *append = &host->append_rx_ctx; + uint32_t dma_desc_num = host->dma_ctx->dma_desc_num; //Check if there are enough available dma descriptors for software to use int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_rx_int : host->dma_ctx->dma_align_rx_ext; int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align)); - int available_desc_num = hal->dma_desc_num - hal->rx_used_desc_cnt; + int available_desc_num = dma_desc_num - append->used_desc_cnt; if (num_required > available_desc_num) { return ESP_ERR_INVALID_STATE; } - int offset = hal->rx_cur_desc - hal->dmadesc_rx; + int offset = append->free_desc - append->desc_root; spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, true); - hal->rx_cur_desc->arg = arg; + append->free_desc->arg = arg; - if (!hal->rx_used_desc_cnt) { + if (!append->used_desc_cnt) { //start a link - hal->rx_dma_tail = hal->rx_cur_desc; spi_dma_reset(host->dma_ctx->rx_dma_chan); spi_slave_hd_hal_hw_prepare_rx(hal); - spi_dma_start(host->dma_ctx->rx_dma_chan, hal->rx_cur_desc->desc); + spi_dma_start(host->dma_ctx->rx_dma_chan, append->free_desc->desc); } else { //there is already a consecutive link gdma_link_list_handle_t link_handle = host->dma_ctx->rx_link_handle; gdma_link_concat(link_handle, offset - 1, link_handle, offset); - hal->rx_dma_tail = hal->rx_cur_desc; spi_dma_append(host->dma_ctx->rx_dma_chan); } //Move the current descriptor pointer according to the number of the linked descriptors portENTER_CRITICAL(&host->int_spinlock); - hal->rx_used_desc_cnt += num_required; + append->used_desc_cnt += num_required; portEXIT_CRITICAL(&host->int_spinlock); - slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_cur_desc, num_required); + slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required); return ESP_OK; } diff --git a/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h b/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h index e1109220f8b..7d3ce00f9a8 100644 --- a/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h +++ b/components/esp_hal_gpspi/include/hal/spi_slave_hd_hal.h @@ -47,8 +47,6 @@ #include "esp_err.h" #include "soc/soc_caps.h" #include "hal/spi_types.h" -#include "hal/dma_types.h" -#include "hal/gdma_types.h" #if SOC_GPSPI_SUPPORTED #include "hal/spi_ll.h" #endif @@ -59,26 +57,6 @@ extern "C" { #if SOC_GPSPI_SUPPORTED -//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol -#if !defined(SOC_GDMA_TRIG_PERIPH_SPI2_BUS) -typedef dma_descriptor_align4_t spi_dma_desc_t; -#else -#if defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) -typedef dma_descriptor_align8_t spi_dma_desc_t; -#elif defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) -typedef dma_descriptor_align4_t spi_dma_desc_t; -#endif -#endif - -/** - * @brief Type of dma descriptor with appended members - * this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users. - */ -typedef struct { - spi_dma_desc_t *desc; ///< DMA descriptor - void *arg; ///< This points to the transaction descriptor user passed in -} spi_slave_hd_hal_desc_append_t; - /// Configuration of the HAL typedef struct { uint32_t host_id; ///< Host ID of the spi peripheral @@ -99,22 +77,8 @@ typedef struct { /// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`. typedef struct { - /* These two need to be malloced by the driver first */ - spi_slave_hd_hal_desc_append_t *dmadesc_tx; ///< Head of the TX DMA descriptors. - spi_slave_hd_hal_desc_append_t *dmadesc_rx; ///< Head of the RX DMA descriptors. - /* address of the hardware */ spi_dev_t *dev; ///< Beginning address of the peripheral registers. - uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``. - uint32_t current_eof_addr; - spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up). - spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware - spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware - uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup - spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up). - spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware - spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware - uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup /* Internal status used by the HAL implementation, initialized as 0. */ uint32_t intr_not_triggered; diff --git a/components/esp_hal_gpspi/spi_slave_hd_hal.c b/components/esp_hal_gpspi/spi_slave_hd_hal.c index b1e543b0fb1..18e5aeacb4c 100644 --- a/components/esp_hal_gpspi/spi_slave_hd_hal.c +++ b/components/esp_hal_gpspi/spi_slave_hd_hal.c @@ -19,10 +19,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h { spi_dev_t *hw = spi_periph_signal[hal_config->host_id].hw; hal->dev = hw; - hal->tx_cur_desc = hal->dmadesc_tx; - hal->rx_cur_desc = hal->dmadesc_rx; - hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num - 1; - hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num - 1; spi_ll_slave_hd_init(hw); spi_ll_set_addr_bitlen(hw, hal_config->address_bits);