Merge branch 'fix/fix_mspi_dma_burst_c5_eco2_v5.5' into 'release/v5.5'

mspi: fixed mspi dma burst timing issue on c5 eco0-2 and c6 eco0-3 (v5.5)

See merge request espressif/esp-idf!45035
This commit is contained in:
morris
2026-01-15 20:59:11 +08:00
10 changed files with 119 additions and 19 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ endif()
if(${target} STREQUAL "linux")
set(priv_requires esp_ringbuf)
else()
set(priv_requires esp_pm esp_driver_gpio esp_ringbuf esp_mm)
set(priv_requires esp_pm esp_driver_gpio esp_ringbuf esp_mm esp_psram)
endif()
idf_component_register(
+14 -8
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -34,6 +34,7 @@
#include "esp_private/esp_dma_utils.h"
#include "esp_private/gdma_link.h"
#include "esp_private/esp_cache_private.h"
#include "esp_private/esp_psram_mspi.h"
#include "uhci_private.h"
#include "esp_memory_utils.h"
#include "esp_cache.h"
@@ -107,6 +108,7 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
{
bool need_yield = false;
uhci_controller_handle_t uhci_ctrl = (uhci_controller_handle_t) user_data;
bool is_buf_from_psram = esp_ptr_external_ram(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index]);
// If the data is not all received, handle it in not normal_eof block. Otherwise, in eof block.
if (!event_data->flags.normal_eof) {
size_t rx_size = uhci_ctrl->rx_dir.buffer_size_per_desc_node[uhci_ctrl->rx_dir.node_index];
@@ -116,9 +118,8 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
.flags.totally_received = false,
};
bool need_cache_sync = esp_ptr_internal(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index]) ? (uhci_ctrl->int_mem_cache_line_size > 0) : (uhci_ctrl->ext_mem_cache_line_size > 0);
if (need_cache_sync) {
esp_cache_msync(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index], rx_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
if (is_buf_from_psram) {
esp_psram_mspi_mb();
}
if (uhci_ctrl->rx_dir.on_rx_trans_event) {
need_yield |= uhci_ctrl->rx_dir.on_rx_trans_event(uhci_ctrl, &evt_data, uhci_ctrl->user_data);
@@ -138,10 +139,8 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
.flags.totally_received = true,
};
bool need_cache_sync = esp_ptr_internal(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index]) ? (uhci_ctrl->int_mem_cache_line_size > 0) : (uhci_ctrl->ext_mem_cache_line_size > 0);
size_t m2c_size = UHCI_ALIGN_UP(rx_size, uhci_ctrl->rx_dir.cache_line);
if (need_cache_sync) {
esp_cache_msync(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index], m2c_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
if (is_buf_from_psram) {
esp_psram_mspi_mb();
}
// release power manager lock
if (uhci_ctrl->pm_lock) {
@@ -347,6 +346,13 @@ esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer,
gdma_link_mount_buffers(uhci_ctrl->rx_dir.dma_link, 0, mount_configs, node_count, NULL);
// Invalidate cache before DMA starts to ensure no dirty cache lines.
// All DMA nodes (mount_configs) share the same contiguous user buffer, so checking mount_configs[0].buffer is sufficient.
bool need_cache_sync = esp_ptr_internal(mount_configs[0].buffer) ? (uhci_ctrl->int_mem_cache_line_size > 0) : (uhci_ctrl->ext_mem_cache_line_size > 0);
if (need_cache_sync) {
ESP_RETURN_ON_ERROR(esp_cache_msync(mount_configs[0].buffer, usable_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), TAG, "cache sync failed");
}
gdma_reset(uhci_ctrl->rx_dir.dma_chan);
gdma_start(uhci_ctrl->rx_dir.dma_chan, gdma_link_get_head_addr(uhci_ctrl->rx_dir.dma_link));
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
+1 -1
View File
@@ -15,7 +15,7 @@ if(${target} STREQUAL "esp32")
list(APPEND priv_requires bootloader_support esp_driver_spi esp_driver_gpio)
endif()
set(srcs)
set(srcs "system_layer/esp_psram_mspi.c")
if(CONFIG_SPIRAM)
list(APPEND srcs "system_layer/esp_psram.c")
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_PSRAM_MSPI_MB_WORKAROUND (CONFIG_IDF_TARGET_ESP32C5 && CONFIG_ESP32C5_REV_MIN_FULL < 102) || (CONFIG_IDF_TARGET_ESP32C61 && CONFIG_ESP32C61_REV_MIN_FULL < 101)
/**
* @brief Initialize PSRAM MSPI memory barrier
*
* @return ESP_OK on success, otherwise an error code
*/
esp_err_t esp_psram_mspi_mb_init(void);
/**
* @brief PSRAM MSPI memory barrier
*/
void esp_psram_mspi_mb(void);
#ifdef __cplusplus
}
#endif
+15 -5
View File
@@ -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
*/
@@ -28,6 +28,7 @@
#include "esp_private/esp_psram_extram.h"
#include "esp_private/esp_mmu_map_private.h"
#include "esp_private/esp_psram_impl.h"
#include "esp_private/esp_psram_mspi.h"
#include "esp_private/startup_internal.h"
#if SOC_SPIRAM_XIP_SUPPORTED
#include "esp_private/mmu_psram_flash.h"
@@ -113,6 +114,8 @@ static const DRAM_ATTR char TAG[] = "esp_psram";
ESP_SYSTEM_INIT_FN(add_psram_to_heap, CORE, BIT(0), 103)
{
esp_err_t ret = ESP_FAIL;
#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
#if (CONFIG_IDF_TARGET_ESP32C5 && CONFIG_ESP32C5_REV_MIN_FULL <= 100) || (CONFIG_IDF_TARGET_ESP32C61 && CONFIG_ESP32C61_REV_MIN_FULL <= 100)
@@ -120,17 +123,24 @@ ESP_SYSTEM_INIT_FN(add_psram_to_heap, CORE, BIT(0), 103)
ESP_EARLY_LOGW(TAG, "Please avoid using PSRAM for security sensitive data e.g., TLS stack allocations (CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC)");
#endif
if (esp_psram_is_initialized()) {
esp_err_t r = esp_psram_extram_add_to_heap_allocator();
if (r != ESP_OK) {
ret = esp_psram_extram_add_to_heap_allocator();
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
abort();
return ret;
}
#if CONFIG_SPIRAM_USE_MALLOC
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
#endif
}
#endif
return ESP_OK;
ret = esp_psram_mspi_mb_init();
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to initialize PSRAM MSPI memory barrier!");
return ret;
}
return ret;
}
#if CONFIG_IDF_TARGET_ESP32
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_intr_alloc.h"
#include "esp_cache.h"
#include "esp_heap_caps.h"
#include "esp_private/esp_psram_mspi.h"
__attribute__((unused)) static DRAM_ATTR char TAG[] = "MSPI Timing";
#if ESP_PSRAM_MSPI_MB_WORKAROUND
static void *s_psram_mb_dummy_cacheline; //dummy cacheline for cache memory barrier
#endif
esp_err_t esp_psram_mspi_mb_init(void)
{
#if ESP_PSRAM_MSPI_MB_WORKAROUND
s_psram_mb_dummy_cacheline = heap_caps_calloc(1, CONFIG_CACHE_L1_CACHE_LINE_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_CACHE_ALIGNED);
if (!s_psram_mb_dummy_cacheline) {
ESP_EARLY_LOGE(TAG, "Failed to allocate dummy cacheline for PSRAM memory barrier!");
}
#endif
return ESP_OK;
}
void IRAM_ATTR esp_psram_mspi_mb(void)
{
#if ESP_PSRAM_MSPI_MB_WORKAROUND
if (s_psram_mb_dummy_cacheline) {
uint32_t *p = (uint32_t *)s_psram_mb_dummy_cacheline;
*p = (*p + 1) % UINT32_MAX;
__attribute__((unused)) esp_err_t ret = ESP_FAIL;
ret = esp_cache_msync(s_psram_mb_dummy_cacheline, sizeof(uint32_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); //malloc is aligned, no need to writeback all
assert(ret == ESP_OK);
asm volatile("fence");
}
#endif
}
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut