feat(esp_psram): wakeup PSRAM by CE# force control instead of dummy write

This commit is contained in:
wuzhenghui
2026-05-11 11:29:11 +08:00
parent 858ecf6f70
commit ecfdeef9d7
4 changed files with 61 additions and 10 deletions

View File

@@ -26,6 +26,7 @@
#include "soc/clk_tree_defs.h"
#include "soc/hp_system_struct.h"
#include "rom/opi_flash.h"
#include "esp_rom_sys.h"
#ifdef __cplusplus
extern "C" {
@@ -60,6 +61,14 @@ extern "C" {
#define PSRAM_CTRLR_LL_INTR_EVENT_SUPPORTED 1
/**
* ESP32-P4 MSPI revision < 3.0 lacks SPIMEM CS force-control (cs_keep_active /
* cs0_dis / cs1_dis) needed to assert CE# and wake PSRAM from half-sleep.
* The device driver must issue a dummy MSPI write instead.
* Revision >= 3.0 can use psram_ctrlr_ll_half_sleep_wakeup().
*/
#define PSRAM_CTRLR_LL_MSPI_WAKEUP_WORKAROUND (HAL_CONFIG(CHIP_SUPPORT_MIN_REV) < 300)
/**
* @brief Set PSRAM write cmd
*
@@ -946,6 +955,29 @@ static inline void psram_ctrlr_ll_enable_core_err_resp(void)
HP_SYSTEM.core_err_resp_dis.val = 0x0;
}
#if !PSRAM_CTRLR_LL_MSPI_WAKEUP_WORKAROUND
/**
* @brief Wake PSRAM from half-sleep via MSPI CS controls (P4 MSPI rev >= 3.0).
*
* MSPI2: mem_cs_oe_ctrl drives CS. MSPI3: cs_keep_active + cs0/cs1_dis for CE#.
* Restore MSPI2/MSPI3 cs settings when done.
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_half_sleep_wakeup(void)
{
bool old_oe_ctrl = SPIMEM2.mem_misc.mem_cs_oe_ctrl;
SPIMEM2.mem_misc.mem_cs_oe_ctrl = 1;
SPIMEM3.misc.cs_keep_active = 1;
SPIMEM3.misc.cs0_dis = 1;
SPIMEM3.misc.cs1_dis = 0;
esp_rom_delay_us(3);
SPIMEM3.misc.cs1_dis = 1;
SPIMEM3.misc.cs0_dis = 0;
SPIMEM3.misc.cs_keep_active = 0;
SPIMEM2.mem_misc.mem_cs_oe_ctrl = old_oe_ctrl;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -27,6 +27,7 @@
#include "soc/clk_tree_defs.h"
#include "soc/hp_system_struct.h"
#include "rom/opi_flash.h"
#include "esp_rom_sys.h"
#ifdef __cplusplus
extern "C" {
@@ -958,6 +959,27 @@ static inline void psram_ctrlr_ll_enable_core_err_resp(void)
HP_SYSTEM.core_err_resp_dis.val = 0x0;
}
/**
* @brief Wake PSRAM from half-sleep via MSPI CS controls.
*
* MSPI2: mem_cs_oe_ctrl drives CS. MSPI3: cs_keep_active + cs0/cs1_dis for CE#.
* Restore MSPI2/MSPI3 cs settings when done.
*/
__attribute__((always_inline))
static inline void psram_ctrlr_ll_half_sleep_wakeup(void)
{
bool old_oe_ctrl = SPIMEM2.mem_misc.mem_cs_oe_ctrl;
SPIMEM2.mem_misc.mem_cs_oe_ctrl = 1;
SPIMEM3.misc.cs_keep_active = 1;
SPIMEM3.misc.cs0_dis = 1;
SPIMEM3.misc.cs1_dis = 0;
esp_rom_delay_us(3);
SPIMEM3.misc.cs1_dis = 1;
SPIMEM3.misc.cs0_dis = 0;
SPIMEM3.misc.cs_keep_active = 0;
SPIMEM2.mem_misc.mem_cs_oe_ctrl = old_oe_ctrl;
}
#ifdef __cplusplus
}
#endif

View File

@@ -568,7 +568,7 @@ PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
// Record the tick exiting halfsleep mode
s_halfsleep_ctx.halfsleep_wakeup_tick = rtc_time_get();
// Do a SPI dummy write transmission to invalid address to wake up from halfsleep mode
#if PSRAM_CTRLR_LL_MSPI_WAKEUP_WORKAROUND
uint8_t null = 0;
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
AP_HEX_PSRAM_REG_WRITE, AP_HEX_PSRAM_WR_CMD_BITLEN,
@@ -577,6 +577,10 @@ PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
&null, 0,
NULL, 0,
false);
#else
// Set CE# to active to wakeup PSRAM halfsleep
psram_ctrlr_ll_half_sleep_wakeup();
#endif
}
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)

View File

@@ -565,15 +565,8 @@ void esp_psram_impl_exit_halfsleep_mode(void)
// Record the tick exiting halfsleep mode
s_halfsleep_ctx.halfsleep_wakeup_tick = rtc_time_get();
// Do a SPI dummy write transmission to invalid address to wake up from halfsleep mode
uint8_t null = 0;
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
AP_OCT_PSRAM_REG_WRITE, AP_OCT_PSRAM_WR_CMD_BITLEN,
0xFF, AP_OCT_PSRAM_ADDR_BITLEN,
0,
&null, 0,
NULL, 0,
false);
// Set CE# to active to wakeup PSRAM halfsleep
psram_ctrlr_ll_half_sleep_wakeup();
}
void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)