feat(mspi): supported mspi flash and psram isr

This commit is contained in:
armando
2025-11-24 14:57:25 +08:00
committed by Armando (Dou Yiwen)
parent 5c0c17231c
commit 7fe40f12ba
70 changed files with 1432 additions and 26 deletions
+8
View File
@@ -1,6 +1,12 @@
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
if(${target} STREQUAL "linux")
idf_component_register(INCLUDE_DIRS "include"
REQUIRES soc hal)
return()
endif()
set(srcs)
set(includes "include" "${target}/include")
@@ -24,6 +30,8 @@ elseif(NOT BOOTLOADER_BUILD)
endif()
list(APPEND srcs "${target}/mspi_periph.c")
idf_component_register(
SRCS ${srcs}
INCLUDE_DIRS ${includes}
@@ -17,3 +17,5 @@
*/
//For compatibility
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#include "soc/interrupts.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_SPI0_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -17,3 +17,5 @@
*/
//For compatibility
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = -1,
},
[1] = {
.irq = ETS_SPI1_INTR_SOURCE,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -17,3 +17,5 @@
*/
//For compatibility
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = -1,
},
[1] = {
.irq = ETS_SPI1_INTR_SOURCE,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -32,12 +32,29 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define MSPI_LL_CORE_CLOCK_80_MHZ 80
#define MSPI_LL_CORE_CLOCK_120_MHZ 120
#define MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT MSPI_LL_CORE_CLOCK_80_MHZ
#define MSPI_LL_ADDR_INT_SUPPORTED 1
#define MSPI_LL_PMS_INT_SUPPORTED 1
#define MSPI_LL_ECC_INT_SUPPORTED 1
#define MSPI_LL_EVENT_SLV_ST_END (1<<3)
#define MSPI_LL_EVENT_MST_ST_END (1<<4)
#define MSPI_LL_EVENT_ECC_ERR (1<<5)
#define MSPI_LL_EVENT_PMS_REJECT (1<<6)
#define MSPI_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define MSPI_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define MSPI_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define MSPI_LL_EVENT_MASK (MSPI_LL_EVENT_ECC_ERR | MSPI_LL_EVENT_PMS_REJECT | MSPI_LL_EVENT_AXI_RADDR_ERR | \
MSPI_LL_EVENT_AXI_WR_FLASH_ERR | MSPI_LL_EVENT_AXI_WADDR_ERR)
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
#define MSPI_LL_INTR_SHARED 1
/*---------------------------------------------------------------
MSPI
---------------------------------------------------------------*/
@@ -442,6 +459,46 @@ static inline void mspi_timing_ll_get_psram_dummy(uint8_t mspi_id, int *usr_rdum
*extra_dummy = REG_GET_FIELD(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_EXTRA_DUMMY_CYCLELEN);
}
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.mem_int_ena.val |= intr_mask;
} else {
SPIMEM0.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.mem_int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.mem_int_raw.val;
}
#ifdef __cplusplus
}
#endif
@@ -29,12 +29,27 @@ extern "C" {
#define PSRAM_CTRLR_LL_MSPI_ID_0 0
#define PSRAM_CTRLR_LL_MSPI_ID_1 1
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_0
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_1
#define PSRAM_LL_CS_SEL SPI_MEM_CS1_DIS_M
#define PSRAM_CTRLR_LL_PMS_REGION_NUMS 4
#define PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE (1<<0)
#define PSRAM_CTRLR_LL_PMS_ATTR_READABLE (1<<1)
#define PSRAM_CTRLR_LL_PMS_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_EVENT_SLV_ST_END (1<<3)
#define PSRAM_CTRLR_LL_EVENT_MST_ST_END (1<<4)
#define PSRAM_CTRLR_LL_EVENT_ECC_ERR (1<<5)
#define PSRAM_CTRLR_LL_EVENT_PMS_REJECT (1<<6)
#define PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define PSRAM_CTRLR_LL_EVENT_MASK (PSRAM_CTRLR_LL_EVENT_ECC_ERR | PSRAM_CTRLR_LL_EVENT_PMS_REJECT | PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR | \
PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR | PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR)
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* @brief PSRAM enum for cs id.
*/
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -17,3 +17,5 @@
*/
//For compatibility
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -32,12 +32,28 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define MSPI_LL_CORE_CLOCK_80_MHZ 80
#define MSPI_LL_CORE_CLOCK_120_MHZ 120
#define MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT MSPI_LL_CORE_CLOCK_80_MHZ
#define MSPI_LL_EVENT_SLV_ST_END (1<<3)
#define MSPI_LL_EVENT_MST_ST_END (1<<4)
#define MSPI_LL_EVENT_ECC_ERR (1<<5)
#define MSPI_LL_EVENT_PMS_REJECT (1<<6)
#define MSPI_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define MSPI_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define MSPI_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define MSPI_LL_EVENT_MASK (MSPI_LL_EVENT_ECC_ERR | MSPI_LL_EVENT_PMS_REJECT | MSPI_LL_EVENT_AXI_RADDR_ERR | \
MSPI_LL_EVENT_AXI_WR_FLASH_ERR | MSPI_LL_EVENT_AXI_WADDR_ERR)
#define MSPI_LL_ADDR_INT_SUPPORTED 1
#define MSPI_LL_PMS_INT_SUPPORTED 1
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
#define MSPI_LL_INTR_SHARED 1
/************************** MSPI pll clock configurations **************************/
/*
@@ -426,6 +442,46 @@ static inline void mspi_timing_ll_get_psram_dummy(uint8_t mspi_id, int *usr_rdum
*extra_dummy = REG_GET_FIELD(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_EXTRA_DUMMY_CYCLELEN);
}
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.mem_int_ena.val |= intr_mask;
} else {
SPIMEM0.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.mem_int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.mem_int_raw.val;
}
#ifdef __cplusplus
}
#endif
@@ -29,12 +29,27 @@ extern "C" {
#define PSRAM_CTRLR_LL_MSPI_ID_0 0
#define PSRAM_CTRLR_LL_MSPI_ID_1 1
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_0
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_1
#define PSRAM_LL_CS_SEL SPI_MEM_CS1_DIS_M
#define PSRAM_CTRLR_LL_PMS_REGION_NUMS 4
#define PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE (1<<0)
#define PSRAM_CTRLR_LL_PMS_ATTR_READABLE (1<<1)
#define PSRAM_CTRLR_LL_PMS_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_EVENT_SLV_ST_END (1<<3)
#define PSRAM_CTRLR_LL_EVENT_MST_ST_END (1<<4)
#define PSRAM_CTRLR_LL_EVENT_ECC_ERR (1<<5)
#define PSRAM_CTRLR_LL_EVENT_PMS_REJECT (1<<6)
#define PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define PSRAM_CTRLR_LL_EVENT_MASK (PSRAM_CTRLR_LL_EVENT_ECC_ERR | PSRAM_CTRLR_LL_EVENT_PMS_REJECT | PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR | \
PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR | PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR)
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* @brief PSRAM enum for cs id.
*/
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -30,6 +30,9 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
//Timing tuning not applied, and flash has its own clock source. Can change flash clock source
#define MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -30,6 +30,9 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
//Timing tuning not applied, and flash has its own clock source. Can change flash clock source
#define MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -23,9 +23,29 @@
#include "soc/soc.h"
#include "soc/clk_tree_defs.h"
#include "soc/pcr_struct.h"
#include "soc/spi_mem_struct.h"
#include "hal/misc.h"
#include "hal/assert.h"
#define MSPI_LL_ADDR_INT_SUPPORTED 1
#define MSPI_LL_PMS_INT_SUPPORTED 1
#define MSPI_LL_ECC_INT_SUPPORTED 1
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define MSPI_LL_EVENT_SLV_ST_END (1<<3)
#define MSPI_LL_EVENT_MST_ST_END (1<<4)
#define MSPI_LL_EVENT_ECC_ERR (1<<5)
#define MSPI_LL_EVENT_PMS_REJECT (1<<6)
#define MSPI_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define MSPI_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define MSPI_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define MSPI_LL_EVENT_MASK (MSPI_LL_EVENT_ECC_ERR | MSPI_LL_EVENT_PMS_REJECT | MSPI_LL_EVENT_AXI_RADDR_ERR | \
MSPI_LL_EVENT_AXI_WR_FLASH_ERR | MSPI_LL_EVENT_AXI_WADDR_ERR)
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
#define MSPI_LL_INTR_SHARED 1
#ifdef __cplusplus
extern "C" {
#endif
@@ -60,6 +80,46 @@ static inline void _mspi_timing_ll_set_flash_clk_src(uint32_t mspi_id, soc_perip
}
}
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.int_ena.val |= intr_mask;
} else {
SPIMEM0.int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.int_raw.val;
}
#ifdef __cplusplus
}
#endif
@@ -29,12 +29,27 @@ extern "C" {
#define PSRAM_CTRLR_LL_MSPI_ID_0 0
#define PSRAM_CTRLR_LL_MSPI_ID_1 1
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_0
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_1
#define PSRAM_LL_CS_SEL SPI_MEM_CS1_DIS_M
#define PSRAM_CTRLR_LL_PMS_REGION_NUMS 4
#define PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE (1<<0)
#define PSRAM_CTRLR_LL_PMS_ATTR_READABLE (1<<1)
#define PSRAM_CTRLR_LL_PMS_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_EVENT_SLV_ST_END (1<<3)
#define PSRAM_CTRLR_LL_EVENT_MST_ST_END (1<<4)
#define PSRAM_CTRLR_LL_EVENT_ECC_ERR (1<<5)
#define PSRAM_CTRLR_LL_EVENT_PMS_REJECT (1<<6)
#define PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define PSRAM_CTRLR_LL_EVENT_MASK (PSRAM_CTRLR_LL_EVENT_ECC_ERR | PSRAM_CTRLR_LL_EVENT_PMS_REJECT | PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR | \
PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR | PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR)
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* @brief PSRAM enum for cs id.
*/
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -43,6 +43,7 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 4
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
@@ -59,7 +60,25 @@ extern "C" {
#define MSPI_TIMING_LL_FLASH_FAST_MODE_MASK (SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_SLOW_MODE_MASK 0
#define MSPI_LL_ADDR_INT_SUPPORTED 1
#define MSPI_LL_PMS_INT_SUPPORTED 1
#define MSPI_LL_ECC_INT_SUPPORTED 1
#define MSPI_LL_FLASH_THRESH_INT_SUPPORTED 1
#define MSPI_LL_EVENT_SLV_ST_END (1<<3)
#define MSPI_LL_EVENT_MST_ST_END (1<<4)
#define MSPI_LL_EVENT_ECC_ERR (1<<5)
#define MSPI_LL_EVENT_PMS_REJECT (1<<6)
#define MSPI_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define MSPI_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define MSPI_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define MSPI_LL_EVENT_RX_TRANS_OVF (1<<26)
#define MSPI_LL_EVENT_TX_TRANS_UDF (1<<27)
#define MSPI_LL_EVENT_MASK (MSPI_LL_EVENT_ECC_ERR | MSPI_LL_EVENT_PMS_REJECT | MSPI_LL_EVENT_AXI_RADDR_ERR | \
MSPI_LL_EVENT_AXI_WR_FLASH_ERR | MSPI_LL_EVENT_AXI_WADDR_ERR | MSPI_LL_EVENT_RX_TRANS_OVF | \
MSPI_LL_EVENT_TX_TRANS_UDF)
#define MSPI_LL_AXI_DISABLE_SUPPORTED 1
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
/**
* MSPI DQS ID
@@ -636,6 +655,46 @@ static inline uint32_t mspi_timing_ll_get_invalid_dqs_mask(uint8_t spi_num)
}
}
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.int_ena.val |= intr_mask;
} else {
SPIMEM0.int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.int_raw.val;
}
/**
* Enable AXI access to flash
*
@@ -33,6 +33,8 @@ extern "C" {
#define PSRAM_CTRLR_LL_MSPI_ID_2 2
#define PSRAM_CTRLR_LL_MSPI_ID_3 3
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_2
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_3
#define PSRAM_CTRLR_LL_PMS_REGION_NUMS 4
#define PSRAM_CTRLR_LL_PMS_ATTR_WRITABLE (1<<0)
@@ -40,6 +42,23 @@ extern "C" {
#define PSRAM_CTRLR_LL_FIFO_MAX_BYTES 64
#define PSRAM_CTRLR_LL_THRESH_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_PMS_INT_SUPPORTED 1
#define PSRAM_CTRLR_LL_EVENT_SLV_ST_END (1<<3)
#define PSRAM_CTRLR_LL_EVENT_MST_ST_END (1<<4)
#define PSRAM_CTRLR_LL_EVENT_ECC_ERR (1<<5)
#define PSRAM_CTRLR_LL_EVENT_PMS_REJECT (1<<6)
#define PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR (1<<7)
#define PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR (1<<8)
#define PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR (1<<9)
#define PSRAM_CTRLR_LL_EVENT_RX_TRANS_OVF (1<<26)
#define PSRAM_CTRLR_LL_EVENT_TX_TRANS_UDF (1<<27)
#define PSRAM_CTRLR_LL_EVENT_MASK (PSRAM_CTRLR_LL_EVENT_ECC_ERR | PSRAM_CTRLR_LL_EVENT_PMS_REJECT | PSRAM_CTRLR_LL_EVENT_AXI_RADDR_ERR | \
PSRAM_CTRLR_LL_EVENT_AXI_WR_FLASH_ERR | PSRAM_CTRLR_LL_EVENT_AXI_WADDR_ERR | PSRAM_CTRLR_LL_EVENT_RX_TRANS_OVF | \
PSRAM_CTRLR_LL_EVENT_TX_TRANS_UDF)
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* @brief Set PSRAM write cmd
*
@@ -829,6 +848,46 @@ static inline void psram_ctrlr_ll_wait_all_transaction_done(void)
}
}
/**
* @brief Enable/Disable PSRAM controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_enable_intr(uint32_t mspi_id, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM2.mem_int_ena.val |= intr_mask;
} else {
SPIMEM2.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear PSRAM controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_clear_intr(uint32_t mspi_id, uint32_t intr_mask)
{
SPIMEM2.mem_int_clr.val = intr_mask;
}
/**
* @brief Get PSRAM controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t psram_ctrlr_ll_get_intr_raw(uint32_t mspi_id)
{
return SPIMEM2.mem_int_raw.val;
}
/**
* @brief Backup PSRAM controller registers
*
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
[2] = {
.irq = ETS_PSRAM_MSPI_INTR_SOURCE,
},
[3] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -17,3 +17,5 @@
*/
//For compatibility
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_LL_INTR_SHARED 1
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = -1,
},
[1] = {
.irq = ETS_SPI1_INTR_SOURCE,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -30,6 +30,7 @@
#include "hal/assert.h"
#include "soc/soc.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_mem_struct.h"
#include "soc/io_mux_reg.h"
#include "soc/syscon_struct.h"
@@ -37,6 +38,10 @@
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 2
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define ARRAY_SIZE(arr) (sizeof((arr))/sizeof(*(arr)))
#define MSPI_TIMING_LL_FLASH_OCT_MASK (SPI_MEM_FCMD_OCT | SPI_MEM_FADDR_OCT | SPI_MEM_FDIN_OCT | SPI_MEM_FDOUT_OCT)
#define MSPI_TIMING_LL_FLASH_QUAD_MASK (SPI_MEM_FASTRD_MODE | SPI_MEM_FREAD_DUAL | SPI_MEM_FREAD_DIO | SPI_MEM_FREAD_QUAD | SPI_MEM_FREAD_QIO)
@@ -50,6 +55,8 @@ extern "C" {
#define MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT 80
#define MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED 1
#define MSPI_LL_INTR_SHARED 1
#define MSPI_LL_EVENT_MASK 0
typedef enum {
MSPI_TIMING_LL_FLASH_OPI_MODE = BIT(0),
@@ -562,6 +569,46 @@ static inline void mspi_ll_set_flash_protection_access(uint8_t spi_num, uint32_t
}
}
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.int_ena.val |= intr_mask;
} else {
SPIMEM0.int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.int_raw.val;
}
#ifdef __cplusplus
}
#endif
@@ -29,6 +29,8 @@ extern "C" {
#define PSRAM_CTRLR_LL_MSPI_ID_0 0
#define PSRAM_CTRLR_LL_MSPI_ID_1 1
#define PSRAM_CTRLR_LL_MSPI_ID_SYSTEM PSRAM_CTRLR_LL_MSPI_ID_0
#define PSRAM_CTRLR_LL_MSPI_ID_PERI PSRAM_CTRLR_LL_MSPI_ID_1
#define PSRAM_LL_CS_SEL SPI_MEM_CS1_DIS_M
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = -1,
},
[1] = {
.irq = ETS_SPI1_INTR_SOURCE,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -31,13 +31,88 @@
#include "soc/soc.h"
#include "soc/spi_mem_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/spi_mem_struct.h"
#include "soc/spi_mem_s_struct.h"
#include "soc/spi_mem_c_reg.h"
#include "soc/spi1_mem_c_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MSPI_LL_PERIPH_NUM 4
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define MSPI_LL_AXI_DISABLE_SUPPORTED 1
#define MSPI_LL_INTR_EVENT_SUPPORTED 1
// TODO: ["ESP32S31"] IDF-14653
/**
* @brief Enable/Disable MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
* @param enable enable / disable
*/
__attribute__((always_inline))
static inline void mspi_ll_enable_intr(uint8_t spi_num, uint32_t intr_mask, bool enable)
{
if (enable) {
SPIMEM0.mem_int_ena.val |= intr_mask;
} else {
SPIMEM0.mem_int_ena.val &= ~intr_mask;
}
}
/**
* @brief Clear MSPI controller interrupt
*
* @param mspi_id mspi_id
* @param intr_mask interrupt mask
*/
__attribute__((always_inline))
static inline void mspi_ll_clear_intr(uint8_t spi_num, uint32_t intr_mask)
{
SPIMEM0.mem_int_clr.val = intr_mask;
}
/**
* @brief Get MSPI controller interrupt raw
*
* @param mspi_id mspi_id
*/
__attribute__((always_inline))
static inline uint32_t mspi_ll_get_intr_raw(uint8_t spi_num)
{
return SPIMEM0.mem_int_raw.val;
}
/**
* Enable AXI access to flash
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_ll_flash_enable_axi_access(uint8_t spi_num, bool enable)
{
SPIMEM0.mem_cache_fctrl.close_axi_inf_en = !enable;
}
/**
* Enable AXI access to PSRAM
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_ll_psram_enable_axi_access(uint8_t spi_num, bool enable)
{
SPIMEM2.mem_cache_fctrl.close_axi_inf_en = !enable;
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/periph_defs.h"
#include "hal/mspi_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
const mspi_info_t mspi_hw_info = {
.instances = {
[0] = {
.irq = ETS_MSPI_FLASH_INTR_SOURCE,
},
[1] = {
.irq = -1,
},
[2] = {
.irq = ETS_MSPI_PSRAM_INTR_SOURCE,
},
[3] = {
.irq = -1,
},
}
};
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#include "hal/mspi_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
struct {
const uint32_t irq; //irq source for interrupt mux
} instances[MSPI_LL_PERIPH_NUM];
} mspi_info_t;
extern const mspi_info_t mspi_hw_info;
#ifdef __cplusplus
}
#endif
+18 -12
View File
@@ -144,19 +144,24 @@ if(NOT non_os_build)
endif()
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
list(APPEND srcs "mspi_timing_tuning/mspi_timing_tuning.c")
list(APPEND srcs "mspi/mspi_timing_tuning/mspi_timing_tuning.c")
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY AND NOT CONFIG_IDF_TARGET_ESP32S3)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
set(mspi_delay_file
"${CMAKE_CURRENT_LIST_DIR}/mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c"
)
if(EXISTS "${mspi_delay_file}")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
endif()
endif()
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_DQS)
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
endif()
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY)
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
endif()
list(APPEND srcs "mspi/mspi_intr/mspi_intr.c")
endif()
if(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED AND CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB)
@@ -179,15 +184,15 @@ else()
if(ESP_TEE_BUILD)
list(APPEND srcs "esp_clk.c" "hw_random.c")
if(CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1)
list(APPEND srcs "mspi_timing_tuning/mspi_timing_tuning.c")
list(APPEND srcs "mspi/mspi_timing_tuning/mspi_timing_tuning.c")
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY)
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
endif()
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_DQS)
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
endif()
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY)
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
endif()
endif()
endif()
@@ -198,7 +203,8 @@ endif()
set(public_include_dirs "include" "include/soc"
"dma/include" "ldo/include" "debug_probe/include" "etm/include"
"mspi_timing_tuning/include" "mspi_timing_tuning/tuning_scheme_impl/include"
"mspi/mspi_timing_tuning/include" "mspi/mspi_timing_tuning/tuning_scheme_impl/include"
"mspi/mspi_intr/include"
"power_supply/include" "modem/include")
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}")
@@ -223,12 +229,12 @@ idf_component_register(SRCS ${srcs}
PRIV_INCLUDE_DIRS port/include include/esp_private
REQUIRES ${requires}
PRIV_REQUIRES "${priv_requires}"
LDFRAGMENTS linker.lf dma/linker.lf ldo/linker.lf mspi_timing_tuning/linker.lf)
LDFRAGMENTS linker.lf dma/linker.lf ldo/linker.lf mspi/linker.lf)
idf_build_get_property(target IDF_TARGET)
add_subdirectory(port/${target})
if(CONFIG_SOC_SPI_MEM_SUPPORT_TIMING_TUNING)
add_subdirectory(mspi_timing_tuning/port/${target})
add_subdirectory(mspi/mspi_timing_tuning/port/${target})
endif()
add_subdirectory(lowpower)
+123
View File
@@ -85,3 +85,126 @@ There may be multiple GDMA instances on a chip, some is attached to the AHB bus
Some high-performance peripherals, such as MIPI, require DMA to provide more functions, such as hardware handshake mechanism, address growth mode, out-of-order transmission and so on. Therefore, a new DMA controller, called `DW_GDMA` was born. The prefix *DW* is taken from *DesignWare*.
Please note that the specific DMA controller to be used for peripherals is determined by the specific chip. It is possible that, on chip A, SPI works with AHB GDMA, while on chip B, SPI works with AXI GDMA.
## MSPI Interrupt Logic - Chip Differences Analysis
### 1. Overview
This document describes the implementation differences of MSPI interrupt handling mechanism across different chips in ESP-IDF.
#### Related Files
| File | Description |
|------|-------------|
| `components/esp_hw_support/mspi/mspi_intr/mspi_intr.c` | Shared MSPI interrupt management |
| `components/esp_psram/system_layer/esp_psram_mspi.c` | PSRAM specific interrupt handling |
---
### 2. Architecture Design
The MSPI interrupt system is divided into two modes based on chip characteristics:
| Mode | Description |
|------------------|--------------------------------------------------|
| **Shared IRQ** | Flash and PSRAM share a single MSPI IRQ source |
| **Separate IRQ** | Flash and PSRAM have independent MSPI IRQs |
#### Architecture Diagrams
##### 2.1 Shared IRQ Mode
```
┌──────────────────────────────────────┐
│ MSPI Hardware IRQ │
└──────────────────┬───────────────────┘
┌──────────────────────────────────────┐
│ mspi_isr_handler() │
│ [mspi_intr.c] │
│ │
│ 1. mspi_ll_get_intr_raw() │
│ 2. mspi_ll_clear_intr() │
│ 3. Check error events and log │
└──────────────────┬───────────────────┘
┌──────────────────┴───────────────────┐
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ s_isr.psram_isr │ │ s_isr.flash_isr │
│ (PSRAM handler) │ │ (Flash handler) │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
└────────────┬─────────────────────┘
┌─────────────────────────┐
│ abort() if fatal error │
└─────────────────────────┘
```
##### 2.2 Separate IRQ Mode
```
┌─────────────────────┐ ┌─────────────────────┐
│ Flash MSPI IRQ │ │ PSRAM MSPI IRQ │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ [Reserved] │ │ mspi_psram_isr_handler_ │
│ │ │ wrapper() │
│ To be registered by flash │ │ [esp_psram_mspi.c] │
│ driver or system component │ │ │
│ │ │ 1. psram_ctrlr_ll_get_ │
│ Events to handle: │ │ intr_raw() │
│ - MSPI0 CPU read events │ │ 2. psram_ctrlr_ll_clear_ │
│ - MSPI1 ESP-Flash driver │ │ intr() │
│ events │ │ 3. mspi_psram_isr_handler() │
│ │ │ 4. abort() if fatal error │
└─────────────────────────────┘ └─────────────────────────────┘
```
---
### 3. API Reference
#### 3.1 mspi_intr.c
This file (and these APIs) is only available on MSPI_LL_INTR_SHARED chips
```c
/**
* @brief Register MSPI ISR
* @param isr Pointer to structure containing psram_isr and flash_isr
* @return ESP_OK on success
*/
esp_err_t esp_mspi_register_isr(mspi_isr_t *isr);
/**
* @brief Unregister MSPI ISR
* @return ESP_OK on success
*/
esp_err_t esp_mspi_unregister_isr(void);
```
#### 3.2 esp_psram_mspi.c
- On MSPI_LL_INTR_SHARED chips, this file registers PSRAM specific ISR to the shared MSPI dispatcher (in mspi_intr.c)
- On !MSPI_LL_INTR_SHARED chips, this file registers PSRAM own ISR via interrupt allocator
```c
/**
* @brief Register PSRAM MSPI ISR
* @return ESP_OK on success
*/
esp_err_t esp_psram_mspi_register_isr(void);
/**
* @brief Unregister PSRAM MSPI ISR
* @return ESP_OK on success
*/
esp_err_t esp_psram_mspi_unregister_isr(void);
```
@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief MSPI ISR
*/
typedef struct mspi_isr_s {
/**
* @brief MSPI PSRAM ISR
*
* @param[in] arg Argument to the ISR
* @param[in] intr_events Interrupt events
*/
void (*psram_isr)(void *arg, uint32_t intr_events);
/**
* @brief MSPI Flash ISR
*
* @param[in] arg Argument to the ISR
* @param[in] intr_events Interrupt events
*/
void (*flash_isr)(void *arg, uint32_t intr_events);
} mspi_isr_t;
/**
* @brief Register MSPI interrupt
* @note ISR dispatcher will decide if abort, dispatched ISRs should not abort
*
* This ISR mainly:
* - Report MSPI bus errors, e.g. fifo overflow, underflow.
* - ECC error, which will be useful for a Nand flash replacement mechanism.
* - etc.
*
* @return ESP_OK on success, otherwise an error code
*/
esp_err_t esp_mspi_register_isr(mspi_isr_t *isr);
/**
* @brief Unregister MSPI interrupt
*
* @return ESP_OK on success, otherwise an error code
*/
esp_err_t esp_mspi_unregister_isr(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,140 @@
/*
* SPDX-FileCopyrightText: 2025 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 "hal/mspi_ll.h"
#include "hal/mspi_periph.h"
#include "esp_private/startup_internal.h"
#include "esp_private/mspi_intr.h"
#if MSPI_LL_INTR_EVENT_SUPPORTED && MSPI_LL_INTR_SHARED
#if CONFIG_ESP_PANIC_HANDLER_IRAM
#define MSPI_ISR_ATTR IRAM_ATTR
#define MSPI_ISR_FLAGS ESP_INTR_FLAG_IRAM
#else
#define MSPI_ISR_ATTR
#define MSPI_ISR_FLAGS 0
#endif
ESP_LOG_ATTR_TAG_DRAM(TAG, "mspi_intr");
static intr_handle_t s_intr_handle = NULL;
static volatile mspi_isr_t s_isr = {
NULL,
NULL,
};
static void MSPI_ISR_ATTR mspi_isr_handler(void *arg)
{
uint32_t intr_events = mspi_ll_get_intr_raw(MSPI_TIMING_LL_MSPI_ID_0);
mspi_ll_clear_intr(MSPI_TIMING_LL_MSPI_ID_0, intr_events);
ESP_DRAM_LOGE(TAG, "MSPI error");
ESP_DRAM_LOGD(TAG, "intr_events: 0x%" PRIx32, intr_events);
bool is_ecc_error = false;
#if MSPI_LL_ECC_INT_SUPPORTED
if (intr_events & MSPI_LL_EVENT_ECC_ERR) {
ESP_DRAM_LOGD(TAG, "ecc error");
is_ecc_error = true;
}
#endif
#if MSPI_LL_PMS_INT_SUPPORTED
if (intr_events & MSPI_LL_EVENT_PMS_REJECT) {
ESP_DRAM_LOGE(TAG, "pms reject");
}
#endif
#if MSPI_LL_ADDR_INT_SUPPORTED
if (intr_events & MSPI_LL_EVENT_AXI_RADDR_ERR) {
ESP_DRAM_LOGE(TAG, "read addr error");
}
if (intr_events & MSPI_LL_EVENT_AXI_WADDR_ERR) {
ESP_DRAM_LOGE(TAG, "write addr error");
}
if (intr_events & MSPI_LL_EVENT_AXI_WR_FLASH_ERR) {
ESP_DRAM_LOGE(TAG, "write flash error");
}
#endif
#if MSPI_LL_THRESH_INT_SUPPORTED
if (intr_events & MSPI_LL_EVENT_RX_TRANS_OVF) {
ESP_DRAM_LOGE(TAG, "rx trans overflow");
}
if (intr_events & MSPI_LL_EVENT_TX_TRANS_UDF) {
ESP_DRAM_LOGE(TAG, "tx trans underflow");
}
#endif
if (s_isr.psram_isr) {
s_isr.psram_isr(arg, intr_events);
}
if (s_isr.flash_isr) {
s_isr.flash_isr(arg, intr_events);
}
// For ecc error, will handle in the flash/psram isr
if (!is_ecc_error) {
abort();
}
//no yield for now
}
esp_err_t esp_mspi_register_isr(mspi_isr_t *isr)
{
esp_err_t ret = ESP_FAIL;
if (isr && isr->psram_isr) {
s_isr.psram_isr = isr->psram_isr;
}
if (isr && isr->flash_isr) {
s_isr.flash_isr = isr->flash_isr;
}
if (!s_intr_handle) {
ret = esp_intr_alloc(mspi_hw_info.instances[MSPI_TIMING_LL_MSPI_ID_0].irq,
MSPI_ISR_FLAGS,
mspi_isr_handler,
NULL,
&s_intr_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to allocate MSPI flash interrupt");
mspi_ll_clear_intr(MSPI_TIMING_LL_MSPI_ID_0, MSPI_LL_EVENT_MASK);
mspi_ll_enable_intr(MSPI_TIMING_LL_MSPI_ID_0, MSPI_LL_EVENT_MASK, true);
}
return ESP_OK;
}
esp_err_t esp_mspi_unregister_isr(void)
{
esp_err_t ret = ESP_FAIL;
if (s_intr_handle == NULL) {
ESP_EARLY_LOGE(TAG, "MSPI interrupt not registered");
return ESP_ERR_INVALID_STATE;
}
ret = esp_intr_free(s_intr_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to free MSPI interrupt");
s_isr.psram_isr = NULL;
s_isr.flash_isr = NULL;
return ret;
}
#endif //#if MSPI_LL_INTR_EVENT_SUPPORTED && MSPI_LL_INTR_SHARED
+1 -1
View File
@@ -18,7 +18,7 @@ endif()
set(srcs)
if(CONFIG_SPIRAM)
list(APPEND srcs "system_layer/esp_psram.c")
list(APPEND srcs "system_layer/esp_psram.c" "system_layer/esp_psram_mspi.c")
if(${target} STREQUAL "esp32")
list(APPEND srcs "esp32/esp_psram_extram_cache.c"
+16
View File
@@ -0,0 +1,16 @@
# PSRAM MSPI Interrupt Handling
## Overview
This file (`system_layer/esp_psram_mspi.c`) handles PSRAM-specific MSPI interrupt registration.
| Chip Type | `MSPI_LL_INTR_SHARED` | Behavior |
|--------------|-----------------------|------------------------------------------------------|
| Shared IRQ | 1 | Register to shared MSPI dispatcher |
| Separate IRQ | 0 | Register standalone PSRAM ISR via `esp_intr_alloc()` |
## Documentation
For detailed architecture, flow diagrams, and API reference, see:
**[esp_hw_support/README.md - MSPI Interrupt Logic](../esp_hw_support/README.md#mspi-interrupt-logic---chip-differences-analysis)**
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register MSPI PSRAM interrupt
*
* This ISR mainly:
* - Report MSPI bus errors, e.g. fifo overflow, underflow. For example, when data:
* - peripheral -> dma -> mspi -> psram, if the mspi fifo is empty, there will be a fifo underflow error.)
* - peripheral <- dma <- mspi <- psram, if the mspi fifo is full, there will be a fifo overflow error.)
* - etc.
*
* @return ESP_OK on success, otherwise an error code
*/
esp_err_t esp_psram_mspi_register_isr(void);
/**
* @brief Unregister MSPI PSRAM interrupt
*
* @return ESP_OK on success, otherwise an error code
*/
esp_err_t esp_psram_mspi_unregister_isr(void);
#ifdef __cplusplus
}
#endif
+14 -4
View File
@@ -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"
@@ -111,8 +112,10 @@ typedef struct {
static psram_ctx_t s_psram_ctx;
static const DRAM_ATTR char TAG[] = "esp_psram";
ESP_SYSTEM_INIT_FN(add_psram_to_heap, CORE, BIT(0), 103)
ESP_SYSTEM_INIT_FN(psram_core_stage_init, 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,8 +123,8 @@ 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();
}
@@ -130,7 +133,14 @@ ESP_SYSTEM_INIT_FN(add_psram_to_heap, CORE, BIT(0), 103)
#endif
}
#endif
return ESP_OK;
ret = esp_psram_mspi_register_isr();
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to register PSRAM ISR!");
abort();
}
return ret;
}
#if CONFIG_IDF_TARGET_ESP32
@@ -0,0 +1,126 @@
/*
* SPDX-FileCopyrightText: 2025 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 "hal/mspi_ll.h"
#include "hal/mspi_periph.h"
#include "esp_private/mspi_intr.h"
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S2
#include "hal/psram_ctrlr_ll.h"
#endif
#if PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED
#if CONFIG_ESP_PANIC_HANDLER_IRAM
#define PSRAM_ISR_ATTR IRAM_ATTR
#define PSRAM_ISR_FLAGS ESP_INTR_FLAG_IRAM
#else
#define PSRAM_ISR_ATTR
#define PSRAM_ISR_FLAGS 0
#endif
ESP_LOG_ATTR_TAG_DRAM(TAG, "psram_mspi");
static void PSRAM_ISR_ATTR mspi_psram_isr_handler(void *arg, uint32_t intr_events)
{
#if PSRAM_CTRLR_LL_PMS_INT_SUPPORTED
if (intr_events & PSRAM_CTRLR_LL_EVENT_PMS_REJECT) {
ESP_DRAM_LOGE(TAG, "psram pms reject");
}
#endif
#if PSRAM_CTRLR_LL_THRESH_INT_SUPPORTED
if (intr_events & PSRAM_CTRLR_LL_EVENT_RX_TRANS_OVF) {
ESP_DRAM_LOGE(TAG, "psram rx trans overflow");
}
if (intr_events & PSRAM_CTRLR_LL_EVENT_TX_TRANS_UDF) {
ESP_DRAM_LOGE(TAG, "psram tx trans underflow");
}
#endif
}
#if !MSPI_LL_INTR_SHARED
/**
* For PSRAM/FLASH separate MSPI chips, register a PSRAM standalone ISR
*/
__attribute__((__unused__)) static intr_handle_t s_mspi_psram_intr_handle = NULL;
static void PSRAM_ISR_ATTR mspi_psram_isr_handler_wrapper(void *arg)
{
uint32_t intr_events = psram_ctrlr_ll_get_intr_raw(PSRAM_CTRLR_LL_MSPI_ID_SYSTEM);
psram_ctrlr_ll_clear_intr(PSRAM_CTRLR_LL_MSPI_ID_SYSTEM, intr_events);
ESP_DRAM_LOGE(TAG, "MSPI PSRAM error");
mspi_psram_isr_handler(arg, intr_events);
abort();
}
#endif
esp_err_t esp_psram_mspi_register_isr(void)
{
esp_err_t ret = ESP_FAIL;
#if MSPI_LL_INTR_SHARED
mspi_isr_t isr = {
.psram_isr = mspi_psram_isr_handler,
};
ret = esp_mspi_register_isr(&isr);
#else
ret = esp_intr_alloc(mspi_hw_info.instances[PSRAM_CTRLR_LL_MSPI_ID_SYSTEM].irq,
PSRAM_ISR_FLAGS,
mspi_psram_isr_handler_wrapper,
NULL,
&s_mspi_psram_intr_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to allocate MSPI psram interrupt");
psram_ctrlr_ll_clear_intr(PSRAM_CTRLR_LL_MSPI_ID_SYSTEM, PSRAM_CTRLR_LL_EVENT_MASK);
psram_ctrlr_ll_enable_intr(PSRAM_CTRLR_LL_MSPI_ID_SYSTEM, PSRAM_CTRLR_LL_EVENT_MASK, true);
#endif
return ret;
}
esp_err_t esp_psram_mspi_unregister_isr(void)
{
esp_err_t ret = ESP_FAIL;
#if MSPI_LL_INTR_SHARED
ret = esp_mspi_unregister_isr();
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to unregister MSPI psram interrupt");
#else
if (s_mspi_psram_intr_handle == NULL) {
ESP_EARLY_LOGE(TAG, "MSPI psram interrupt not registered");
return ESP_ERR_INVALID_STATE;
}
ret = esp_intr_free(s_mspi_psram_intr_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to free MSPI psram interrupt");
#endif
return ESP_OK;
}
#else
esp_err_t esp_psram_mspi_register_isr(void)
{
return ESP_OK;
}
esp_err_t esp_psram_mspi_unregister_isr(void)
{
return ESP_OK;
}
#endif //#if PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED
+11 -2
View File
@@ -17,6 +17,7 @@
#include "esp_private/cache_utils.h"
#include "spi_flash_mmap.h"
#include "esp_flash_internal.h"
#include "esp_private/mspi_intr.h"
#include "esp_newlib.h"
#include "esp_xt_wdt.h"
#include "esp_cpu.h"
@@ -25,6 +26,7 @@
#include "hal/wdt_hal.h"
#include "hal/uart_types.h"
#include "hal/uart_ll.h"
#include "hal/mspi_ll.h"
#include "freertos/FreeRTOS.h"
#if CONFIG_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
@@ -73,7 +75,7 @@ ESP_SYSTEM_INIT_FN(init_show_cpu_freq, CORE, BIT(0), 10)
* as it is a critical module for device functioning.
*/
#if SOC_BOD_SUPPORTED && !CONFIG_SECURE_ENABLE_TEE
ESP_SYSTEM_INIT_FN(init_brownout, CORE, BIT(0), 104)
ESP_SYSTEM_INIT_FN(init_brownout, CORE, BIT(0), 105)
{
// [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) ->
// malloc (esp_libc) -> heap_caps_malloc (heap), so heap must be at least initialized
@@ -98,7 +100,7 @@ ESP_SYSTEM_INIT_FN(init_brownout, CORE, BIT(0), 104)
}
#endif
ESP_SYSTEM_INIT_FN(init_newlib_time, CORE, BIT(0), 105)
ESP_SYSTEM_INIT_FN(init_newlib_time, CORE, BIT(0), 106)
{
esp_libc_time_init();
return ESP_OK;
@@ -123,6 +125,13 @@ ESP_SYSTEM_INIT_FN(init_flash, CORE, BIT(0), 130)
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
esp_pm_flash_freq_limit_init();
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
// Register MSPI Flash interrupt
#if MSPI_LL_INTR_EVENT_SUPPORTED && MSPI_LL_INTR_SHARED
esp_mspi_register_isr(NULL);
#endif
//else register flash standalone ISR to deal with CPU / API flash access
return ESP_OK;
}
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
+9 -7
View File
@@ -42,13 +42,15 @@ CORE: 101: esp_timer_init_nonos in components/esp_timer/src/esp_timer_init.c on
CORE: 102: init_libc in components/esp_libc/src/init.c on BIT(0)
# Add the psram to heap, psram vaddr region is reserved when initialising the heap, after
# psram is initialised (and necessary reservation for psram usage), the rest of the psram
# will be added to the heap
CORE: 103: add_psram_to_heap in components/esp_psram/system_layer/esp_psram.c on BIT(0)
# PSRAM core stage init, including
# - Add the psram to heap, psram vaddr region is reserved when initialising the heap, after
# psram is initialised (and necessary reservation for psram usage), the rest of the psram
# will be added to the heap
# - Register PSRAM ISR routine
CORE: 103: psram_core_stage_init in components/esp_psram/system_layer/esp_psram.c on BIT(0)
CORE: 104: init_brownout in components/esp_system/startup_funcs.c on BIT(0)
CORE: 105: init_newlib_time in components/esp_system/startup_funcs.c on BIT(0)
CORE: 105: init_brownout in components/esp_system/startup_funcs.c on BIT(0)
CORE: 106: init_newlib_time in components/esp_system/startup_funcs.c on BIT(0)
# Peripheral-specific implementation operators should be filled first
# Then register vfs console, and follow by esp_libc stdio initialization
@@ -127,7 +129,7 @@ SECONDARY: 230: usb_serial_jtag_conn_status_init in components/esp_driver_usb_se
# psram adjust timing point need a separate task which should be created at startup.
# Valid only `CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR` is enabled.
SECONDARY: 240: psram_adjust_timing_point_via_temperature in components/esp_hw_support/mspi_timing_tuning/port/esp32s3/mspi_timing_by_mspi_delay.c on BIT(0)
SECONDARY: 240: psram_adjust_timing_point_via_temperature in components/esp_hw_support/mspi/mspi_timing_tuning/port/esp32s3/mspi_timing_by_mspi_delay.c on BIT(0)
# Has to be the last step!
# Now that the application is about to start, disable boot watchdog
@@ -3152,6 +3152,7 @@ typedef struct {
volatile spi_mem_s_date_reg_t mem_date;
} spi_mem_s_dev_t;
extern spi_mem_s_dev_t SPIMEM2;
#ifndef __cplusplus
_Static_assert(sizeof(spi_mem_s_dev_t) == 0x400, "Invalid size of spi_mem_s_dev_t structure");