From 21b37a672a2ee4b27410f7bb007e0b745bc6a8f7 Mon Sep 17 00:00:00 2001 From: wanckl Date: Wed, 21 Jan 2026 15:55:02 +0800 Subject: [PATCH] fix(driver_spi): fixes psram dma rx buffer memory barrier issue --- .../include/esp_private/spi_common_internal.h | 8 ++++++++ components/esp_driver_spi/src/gpspi/spi_common.c | 14 ++++++++++++++ components/esp_driver_spi/src/gpspi/spi_master.c | 2 ++ components/esp_driver_spi/src/gpspi/spi_slave.c | 3 ++- components/esp_driver_spi/src/gpspi/spi_slave_hd.c | 6 +++--- 5 files changed, 29 insertions(+), 4 deletions(-) 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 1a0df7fbd73..2b1c6e82afe 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 @@ -154,6 +154,14 @@ void spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, in */ esp_err_t 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); +/** + * @brief Memory barrier for DMA RX buffer + * + * @param host_id SPI host ID + * @param rx_buffer RX buffer + */ +void spicommon_dma_rx_mb(spi_host_device_t host_id, void *rx_buffer); + /** * @brief Free DMA for SPI * diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index b4b83ead0cc..3903a523140 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -30,6 +30,9 @@ #if CONFIG_IDF_TARGET_ESP32 #include "soc/dport_reg.h" #endif +#if CONFIG_SPIRAM +#include "esp_private/esp_psram_mspi.h" +#endif #if SOC_PERIPH_CLK_CTRL_SHARED #define SPI_COMMON_PERI_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC() @@ -438,6 +441,17 @@ esp_err_t SPI_COMMON_ISR_ATTR spicommon_dma_setup_priv_buffer(spi_host_device_t return ESP_OK; } +void SPI_COMMON_ISR_ATTR spicommon_dma_rx_mb(spi_host_device_t host_id, void *rx_buffer) +{ + (void)host_id; +#if SOC_PSRAM_DMA_CAPABLE && CONFIG_SPIRAM + if (esp_ptr_external_ram(rx_buffer)) { + // dma rx data to psram need memory barrier fix + esp_psram_mspi_mb(); + } +#endif +} + //----------------------------------------------------------free dma periph-------------------------------------------------------// esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id) { diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index 2e4794ad9a7..99915cc0092 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -1002,6 +1002,7 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg) //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same spicommon_dmaworkaround_idle(dma_ctx->tx_dma_chan.chan_id); #endif //#if CONFIG_IDF_TARGET_ESP32 + spicommon_dma_rx_mb(host->id, host->cur_trans_buf.buffer_to_rcv); spi_trans_dma_error_check(host); } @@ -1429,6 +1430,7 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle, return ESP_ERR_TIMEOUT; } } + spicommon_dma_rx_mb(host->id, host->cur_trans_buf.buffer_to_rcv); spi_trans_dma_error_check(host); uint32_t trans_flags = host->cur_trans_buf.trans->flags; // save the flags before bus_lock release diff --git a/components/esp_driver_spi/src/gpspi/spi_slave.c b/components/esp_driver_spi/src/gpspi/spi_slave.c index bcdab9516e0..e3e2bbb7b62 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave.c @@ -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 */ @@ -654,6 +654,7 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) // When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready. if (use_dma) { freeze_cs(host); + spicommon_dma_rx_mb(host->id, host->cur_trans.rx_buffer); spi_slave_trans_dma_error_check(host); } 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 0fc06fa117d..e61b84fa911 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c @@ -8,6 +8,7 @@ #include "esp_compiler.h" #include "esp_log.h" #include "esp_check.h" +#include "esp_cache.h" #include "esp_memory_utils.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -19,9 +20,6 @@ #include "esp_private/esp_cache_private.h" #include "driver/spi_slave_hd.h" #include "hal/spi_slave_hd_hal.h" -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE -#include "esp_cache.h" -#endif #ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM #define SPI_SLAVE_ISR_ATTR IRAM_ATTR @@ -476,6 +474,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg) host->tx_curr_trans.trans = NULL; } if (rx_done) { + 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); @@ -617,6 +616,7 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_rx_isr(void *arg) ret_priv_trans.trans->trans_len = trans_len; bool ret_queue = true; + spicommon_dma_rx_mb(host->host_id, ret_priv_trans.aligned_buffer); spi_slave_hd_rx_dma_error_check(host, ret_priv_trans); if (callback->cb_recv) { spi_slave_hd_event_t ev = {