diff --git a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c index ef4f7909e2..5e2e457bed 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c +++ b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer_sleep.c @@ -88,6 +88,7 @@ static void test_gptimer_sleep_retention(bool back_up_before_sleep) TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); } #endif + esp_sleep_set_sleep_context(NULL); uint64_t count_value_after_sleep = 0; TEST_ESP_OK(gptimer_get_raw_count(timer, &count_value_after_sleep)); diff --git a/components/esp_hw_support/port/esp32p4/mspi_timing_config.c b/components/esp_hw_support/port/esp32p4/mspi_timing_config.c index 5c2db003e6..ed209a88ad 100644 --- a/components/esp_hw_support/port/esp32p4/mspi_timing_config.c +++ b/components/esp_hw_support/port/esp32p4/mspi_timing_config.c @@ -26,7 +26,8 @@ void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_spe ESP_EARLY_LOGD(TAG, "psram_freq_mhz: %" PRIu32 " mhz, bus clock div: %" PRIu32, psram_freq_mhz, freqdiv); PERIPH_RCC_ATOMIC() { //MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here. - psram_ctrlr_ll_set_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, MSPI_TIMING_CORE_CLOCK_DIV); + psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true); + psram_ctrlr_ll_set_core_clock_div(PSRAM_CTRLR_LL_MSPI_ID_2, MSPI_TIMING_CORE_CLOCK_DIV); psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_3, freqdiv); psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, freqdiv); } diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 0ac1107cc6..4beed8a3cb 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -27,6 +27,7 @@ #include "hal/lp_aon_hal.h" #include "soc/lp_system_reg.h" #include "hal/pmu_hal.h" +#include "hal/psram_ctrlr_ll.h" #include "hal/lp_sys_ll.h" #include "esp_private/esp_pmu.h" #include "pmu_param.h" @@ -168,8 +169,8 @@ const pmu_sleep_config_t* pmu_sleep_config_default( // Get light sleep analog default pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags); #if CONFIG_SPIRAM - analog_default.hp_sys.analog.pd_cur = 1; - analog_default.lp_sys[PMU_MODE_LP_SLEEP].analog.pd_cur = 1; + analog_default.hp_sys.analog.pd_cur = 0; + analog_default.lp_sys[PMU_MODE_LP_SLEEP].analog.pd_cur = 0; #endif #if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON @@ -290,11 +291,6 @@ void pmu_sleep_shutdown_ldo(void) { CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_XPD); } -FORCE_INLINE_ATTR void sleep_writeback_l1_dcache(void) { - Cache_WriteBack_All(CACHE_MAP_L1_DCACHE); - while (!REG_GET_BIT(CACHE_SYNC_CTRL_REG, CACHE_SYNC_DONE)); -} - static TCM_DRAM_ATTR uint32_t s_mpll_freq_mhz_before_sleep = 0; TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) @@ -309,12 +305,28 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev); pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev); + // For the sleep where powered down the TOP domain, the L1 cache data memory will be lost and needs to be written back here. + // For the sleep without power down the TOP domain, regdma retention may still be enabled, and dirty data in the L1 cache needs + // to be written back so that regdma can get the correct link. So we always need to write back to L1 DCache here. // !!! Need to manually check that data in L2 memory will not be modified from now on. !!! - sleep_writeback_l1_dcache(); + Cache_WriteBack_All(CACHE_MAP_L1_DCACHE); - // !!! Need to manually check that data in PSRAM will not be accessed from now on. !!! +#if CONFIG_SPIRAM + psram_ctrlr_ll_wait_all_transaction_done(); +#endif s_mpll_freq_mhz_before_sleep = rtc_clk_mpll_get_freq(); if (s_mpll_freq_mhz_before_sleep) { +#if CONFIG_SPIRAM + _psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_XTAL); + _psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_3, PSRAM_CLK_SRC_XTAL); + if (!s_pmu_sleep_regdma_backup_enabled) { + // MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here. + // If it's a PD_TOP sleep, psram MSPI core clock will be disabled by REGDMA + // !!! Need to manually check that data in PSRAM will not be accessed from now on. !!! + _psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, false); + _psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, false); + } +#endif rtc_clk_mpll_disable(); } @@ -350,6 +362,16 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) if (s_mpll_freq_mhz_before_sleep) { rtc_clk_mpll_enable(); rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep); +#if CONFIG_SPIRAM + if (!s_pmu_sleep_regdma_backup_enabled) { + // MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here. + // If it's a PD_TOP sleep, psram MSPI core clock will be enabled by REGDMA + _psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true); + _psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true); + } + _psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_MPLL); + _psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_3, PSRAM_CLK_SRC_MPLL); +#endif } // Wait eFuse memory update done. diff --git a/components/esp_hw_support/sleep_gpio.c b/components/esp_hw_support/sleep_gpio.c index 1ef17e64c7..8c23325e9b 100644 --- a/components/esp_hw_support/sleep_gpio.c +++ b/components/esp_hw_support/sleep_gpio.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,11 +63,17 @@ void esp_sleep_config_gpio_isolate(void) } #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM - gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS1), GPIO_PULLUP_ONLY); + int32_t mspi_io_cs1_io_num = esp_mspi_get_io(ESP_MSPI_IO_CS1); + if (GPIO_IS_VALID_GPIO(mspi_io_cs1_io_num)) { + gpio_sleep_set_pull_mode(mspi_io_cs1_io_num, GPIO_PULLUP_ONLY); + } #endif // CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND - gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS0), GPIO_PULLUP_ONLY); + int32_t mspi_io_cs0_io_num = esp_mspi_get_io(ESP_MSPI_IO_CS0); + if (GPIO_IS_VALID_GPIO(mspi_io_cs0_io_num)) { + gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS0), GPIO_PULLUP_ONLY); + } #endif // CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND #if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 97cbafd73b..f3eb153a98 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -73,14 +73,24 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_iomux_retention_init(v return ESP_OK; } -static __attribute__((unused)) esp_err_t sleep_sys_periph_spimem_retention_init(void *arg) +static __attribute__((unused)) esp_err_t sleep_sys_periph_flash_spimem_retention_init(void *arg) { - esp_err_t err = sleep_retention_entries_create(spimem_regs_retention, ARRAY_SIZE(spimem_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); - ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "SPI mem"); - ESP_LOGD(TAG, "SPI Mem sleep retention initialization"); + esp_err_t err = sleep_retention_entries_create(flash_spimem_regs_retention, ARRAY_SIZE(flash_spimem_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "Flash SPI mem"); + ESP_LOGD(TAG, "Flash SPI Mem sleep retention initialization"); return ESP_OK; } +#if CONFIG_SPIRAM +static __attribute__((unused)) esp_err_t sleep_sys_periph_psram_spimem_retention_init(void *arg) +{ + esp_err_t err = sleep_retention_entries_create(psram_spimem_regs_retention, ARRAY_SIZE(psram_spimem_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "PSRAM SPI mem"); + ESP_LOGD(TAG, "PSRAM SPI Mem sleep retention initialization"); + return ESP_OK; +} +#endif + static __attribute__((unused)) esp_err_t sleep_sys_periph_systimer_retention_init(void *arg) { esp_err_t err = sleep_retention_entries_create(systimer_regs_retention, ARRAY_SIZE(systimer_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); @@ -130,8 +140,12 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_retention_init(void *a #endif err = sleep_sys_periph_iomux_retention_init(arg); if(err) goto error; - err = sleep_sys_periph_spimem_retention_init(arg); + err = sleep_sys_periph_flash_spimem_retention_init(arg); if(err) goto error; +#if CONFIG_SPIRAM + err = sleep_sys_periph_psram_spimem_retention_init(arg); + if(err) goto error; +#endif err = sleep_sys_periph_systimer_retention_init(arg); if(err) goto error; #if SOC_PAU_IN_TOP_DOMAIN diff --git a/components/esp_system/test_apps/.build-test-rules.yml b/components/esp_system/test_apps/.build-test-rules.yml index e0343c14e3..76aa754ff1 100644 --- a/components/esp_system/test_apps/.build-test-rules.yml +++ b/components/esp_system/test_apps/.build-test-rules.yml @@ -7,6 +7,7 @@ components/esp_system/test_apps/console: components/esp_system/test_apps/esp_system_unity_tests: disable: - if: IDF_TARGET == "esp32c5" or (CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1) + - if: IDF_TARGET == "esp32c5" or (CONFIG_NAME == "psram_with_pd_top" and (SOC_SPIRAM_SUPPORTED != 1 or SOC_PM_SUPPORT_TOP_PD != 1)) components/esp_system/test_apps/linux_apis: enable: diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt index 7bccda3753..0f33f8666d 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt @@ -12,11 +12,14 @@ set(SRC "test_app_main.c" "test_ipc.c" "test_reset_reason.c" "test_shared_stack_printf.c" - "test_sleep.c" "test_stack_check.c" "test_system_time.c" "test_task_wdt.c") +if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED OR CONFIG_SOC_DEEP_SLEEP_SUPPORTED) + list(APPEND SRC "test_sleep.c") +endif() + if(CONFIG_ESP_IPC_ISR_ENABLE) list(APPEND SRC "test_ipc_isr.c") if(CONFIG_IDF_TARGET_ARCH_XTENSA) diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_sleep.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_sleep.c index 7da14280b5..10ac4c2f2c 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_sleep.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_sleep.c @@ -8,6 +8,7 @@ #include #include #include "esp_sleep.h" +#include "esp_private/esp_sleep_internal.h" #include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -31,7 +32,14 @@ #include "nvs_flash.h" #include "nvs.h" -#if SOC_DEEP_SLEEP_SUPPORTED +#if CONFIG_SPIRAM +#include "esp_private/esp_psram_extram.h" +#endif + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +#include "esp_private/sleep_cpu.h" +#endif + #if SOC_PMU_SUPPORTED #include "esp_private/esp_pmu.h" #else @@ -42,6 +50,297 @@ #define ESP_EXT0_WAKEUP_LEVEL_HIGH 1 __attribute__((unused)) static struct timeval tv_start, tv_stop; +/////////////////////////// Light Sleep Test Cases //////////////////////////////////// +#if SOC_LIGHT_SLEEP_SUPPORTED +TEST_CASE("wake up from light sleep using timer", "[lightsleep]") +{ + esp_sleep_enable_timer_wakeup(2000000); + gettimeofday(&tv_start, NULL); + esp_light_sleep_start(); + gettimeofday(&tv_stop, NULL); + float dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f + + (tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f; + TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); +} + +//NOTE: Explained in IDF-1445 | MR !14996 +#if !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384) +static void test_light_sleep(void* arg) +{ + vTaskDelay(2); + for (int i = 0; i < 1000; ++i) { + printf("%d %d\n", xPortGetCoreID(), i); + fflush(stdout); + esp_light_sleep_start(); + } + SemaphoreHandle_t done = (SemaphoreHandle_t) arg; + xSemaphoreGive(done); + vTaskDelete(NULL); +} + +TEST_CASE("light sleep stress test", "[lightsleep]") +{ + SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0); + esp_sleep_enable_timer_wakeup(1000); + xTaskCreatePinnedToCore(&test_light_sleep, "ls0", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0); +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 + xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1); +#endif + xSemaphoreTake(done, portMAX_DELAY); +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 + xSemaphoreTake(done, portMAX_DELAY); +#endif + vSemaphoreDelete(done); +} + +static void timer_func(void* arg) +{ + esp_rom_delay_us(50); +} + +TEST_CASE("light sleep stress test with periodic esp_timer", "[lightsleep]") +{ + SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0); + esp_sleep_enable_timer_wakeup(1000); + esp_timer_handle_t timer; + esp_timer_create_args_t config = { + .callback = &timer_func, + }; + TEST_ESP_OK(esp_timer_create(&config, &timer)); + esp_timer_start_periodic(timer, 500); + xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0); +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 + xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1); +#endif + xSemaphoreTake(done, portMAX_DELAY); +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 + xSemaphoreTake(done, portMAX_DELAY); +#endif + vSemaphoreDelete(done); + esp_timer_stop(timer); + esp_timer_delete(timer); +} +#endif // !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384) + +#if defined(CONFIG_ESP_SYSTEM_RTC_EXT_XTAL) +#define MAX_SLEEP_TIME_ERROR_US 200 +#else +#define MAX_SLEEP_TIME_ERROR_US 100 +#endif + +TEST_CASE("light sleep duration is correct", "[lightsleep][ignore]") +{ + // don't power down XTAL — powering it up takes different time on + // different boards + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + + // run one light sleep without checking timing, to warm up the cache + esp_sleep_enable_timer_wakeup(1000); + esp_light_sleep_start(); + + const int sleep_intervals_ms[] = { + 1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 15, + 20, 25, 50, 100, 200, 500, + }; + + const int sleep_intervals_count = sizeof(sleep_intervals_ms) / sizeof(sleep_intervals_ms[0]); + for (int i = 0; i < sleep_intervals_count; ++i) { + uint64_t sleep_time = sleep_intervals_ms[i] * 1000; + esp_sleep_enable_timer_wakeup(sleep_time); + for (int repeat = 0; repeat < 5; ++repeat) { + uint64_t start = esp_clk_rtc_time(); + int64_t start_hs = esp_timer_get_time(); + esp_light_sleep_start(); + int64_t stop_hs = esp_timer_get_time(); + uint64_t stop = esp_clk_rtc_time(); + + int diff_us = (int)(stop - start); + int diff_hs_us = (int)(stop_hs - start_hs); + printf("%lld %d\n", sleep_time, (int)(diff_us - sleep_time)); + int32_t threshold = MAX(sleep_time / 100, MAX_SLEEP_TIME_ERROR_US); + TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_us); + TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_hs_us); + fflush(stdout); + } + + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +TEST_CASE("light sleep and frequency switching", "[lightsleep]") +{ +#ifndef CONFIG_PM_ENABLE + uart_sclk_t clk_source = UART_SCLK_DEFAULT; +#if SOC_UART_SUPPORT_REF_TICK + clk_source = UART_SCLK_REF_TICK; +#elif SOC_UART_SUPPORT_XTAL_CLK + clk_source = UART_SCLK_XTAL; +#endif + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_set_sclk(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), (soc_module_clk_t)clk_source); + } + uint32_t sclk_freq; + TEST_ESP_OK(uart_get_sclk_freq(clk_source, &sclk_freq)); + HP_UART_SRC_CLK_ATOMIC() { + uart_ll_set_baudrate(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), CONFIG_ESP_CONSOLE_UART_BAUDRATE, sclk_freq); + } +#endif + + rtc_cpu_freq_config_t config_xtal, config_default; + rtc_clk_cpu_freq_get_config(&config_default); + rtc_clk_cpu_freq_mhz_to_config(esp_clk_xtal_freq() / MHZ, &config_xtal); + + esp_sleep_enable_timer_wakeup(1000); + for (int i = 0; i < 1000; ++i) { + if (i % 2 == 0) { + rtc_clk_cpu_freq_set_config_fast(&config_xtal); + } else { + rtc_clk_cpu_freq_set_config_fast(&config_default); + } + printf("%d\n", i); + fflush(stdout); + esp_light_sleep_start(); + } +} + +#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED +__attribute__((unused)) static float get_time_ms(void) +{ + gettimeofday(&tv_stop, NULL); + + float dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f + + (tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f; + return fabs(dt); +} + +__attribute__((unused)) static uint32_t get_cause(void) +{ +#if SOC_PMU_SUPPORTED + uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU); +#else + uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause(); +#endif + return wakeup_cause; +} + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) && SOC_PM_SUPPORT_EXT0_WAKEUP +// Fails on S2 IDF-2903 + +// This test case verifies deactivation of trigger for wake up sources +TEST_CASE("disable source trigger behavior", "[lightsleep]") +{ + float dt = 0; + + printf("Setup timer and ext0 to wake up immediately from GPIO_13 \n"); + + // Setup ext0 configuration to wake up almost immediately + // The wakeup time is proportional to input capacitance * pullup resistance + ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); + ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); + ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13)); + ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH)); + + // Setup timer to wakeup with timeout + esp_sleep_enable_timer_wakeup(2000000); + + // Save start time + gettimeofday(&tv_start, NULL); + esp_light_sleep_start(); + + dt = get_time_ms(); + printf("Ext0 sleep time = %d \n", (int) dt); + + // Check wakeup from Ext0 using time measurement because wakeup cause is + // not available in light sleep mode + TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt); + + TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0); + + // Disable Ext0 source. Timer source should be triggered + ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT0)); + printf("Disable ext0 trigger and leave timer active.\n"); + + gettimeofday(&tv_start, NULL); + esp_light_sleep_start(); + + dt = get_time_ms(); + printf("Timer sleep time = %d \n", (int) dt); + + TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); + + // Additionally check wakeup cause + TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0); + + // Disable timer source. + ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER)); + + // Setup ext0 configuration to wake up immediately + ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); + ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); + ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13)); + ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH)); + + printf("Disable timer trigger to wake up from ext0 source.\n"); + + gettimeofday(&tv_start, NULL); + esp_light_sleep_start(); + + dt = get_time_ms(); + printf("Ext0 sleep time = %d \n", (int) dt); + + TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt); + TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0); + + // Check error message when source is already disabled + esp_err_t err_code = esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); + TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE); + + // Disable ext0 wakeup source, as this might interfere with other tests + ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT0)); +} +#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) +#endif //SOC_RTCIO_INPUT_OUTPUT_SUPPORTED + +#if CONFIG_SPIRAM +static void test_psram_accessible_after_lightsleep(void) +{ + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + + esp_sleep_enable_timer_wakeup(100 * 1000); + esp_light_sleep_start(); + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif + + TEST_ASSERT_EQUAL(true, esp_psram_extram_test()); + + esp_sleep_set_sleep_context(NULL); + esp_restart(); +} + +static void restart_for_reinit_psram(void) +{ + TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason()); + printf("PSRAM survives after lightsleep test - OK\n"); +} + +TEST_CASE_MULTIPLE_STAGES("Test PSRAM survives after lightsleep", "[lightsleep]", + test_psram_accessible_after_lightsleep, + restart_for_reinit_psram); +#endif + +#endif // SOC_LIGHT_SLEEP_SUPPORTED + +/////////////////////////// Deep Sleep Test Cases //////////////////////////////////// +#if SOC_DEEP_SLEEP_SUPPORTED static void check_sleep_reset(void) { TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); @@ -99,158 +398,6 @@ TEST_CASE_MULTIPLE_STAGES("light sleep followed by deep sleep", "[deepsleep][res do_light_sleep_deep_sleep_timer, check_sleep_reset) -TEST_CASE("wake up from light sleep using timer", "[deepsleep]") -{ - esp_sleep_enable_timer_wakeup(2000000); - struct timeval tv_start, tv_stop; - gettimeofday(&tv_start, NULL); - esp_light_sleep_start(); - gettimeofday(&tv_stop, NULL); - float dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f + - (tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f; - TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); -} - -//NOTE: Explained in IDF-1445 | MR !14996 -#if !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384) -static void test_light_sleep(void* arg) -{ - vTaskDelay(2); - for (int i = 0; i < 1000; ++i) { - printf("%d %d\n", xPortGetCoreID(), i); - fflush(stdout); - esp_light_sleep_start(); - } - SemaphoreHandle_t done = (SemaphoreHandle_t) arg; - xSemaphoreGive(done); - vTaskDelete(NULL); -} - -TEST_CASE("light sleep stress test", "[deepsleep]") -{ - SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0); - esp_sleep_enable_timer_wakeup(1000); - xTaskCreatePinnedToCore(&test_light_sleep, "ls0", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0); -#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 - xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1); -#endif - xSemaphoreTake(done, portMAX_DELAY); -#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 - xSemaphoreTake(done, portMAX_DELAY); -#endif - vSemaphoreDelete(done); -} - -static void timer_func(void* arg) -{ - esp_rom_delay_us(50); -} - -TEST_CASE("light sleep stress test with periodic esp_timer", "[deepsleep]") -{ - SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0); - esp_sleep_enable_timer_wakeup(1000); - esp_timer_handle_t timer; - esp_timer_create_args_t config = { - .callback = &timer_func, - }; - TEST_ESP_OK(esp_timer_create(&config, &timer)); - esp_timer_start_periodic(timer, 500); - xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0); -#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 - xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1); -#endif - xSemaphoreTake(done, portMAX_DELAY); -#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 - xSemaphoreTake(done, portMAX_DELAY); -#endif - vSemaphoreDelete(done); - esp_timer_stop(timer); - esp_timer_delete(timer); -} -#endif // !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384) - -#if defined(CONFIG_ESP_SYSTEM_RTC_EXT_XTAL) -#define MAX_SLEEP_TIME_ERROR_US 200 -#else -#define MAX_SLEEP_TIME_ERROR_US 100 -#endif - -TEST_CASE("light sleep duration is correct", "[deepsleep][ignore]") -{ - // don't power down XTAL — powering it up takes different time on - // different boards - esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); - - // run one light sleep without checking timing, to warm up the cache - esp_sleep_enable_timer_wakeup(1000); - esp_light_sleep_start(); - - const int sleep_intervals_ms[] = { - 1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 15, - 20, 25, 50, 100, 200, 500, - }; - - const int sleep_intervals_count = sizeof(sleep_intervals_ms) / sizeof(sleep_intervals_ms[0]); - for (int i = 0; i < sleep_intervals_count; ++i) { - uint64_t sleep_time = sleep_intervals_ms[i] * 1000; - esp_sleep_enable_timer_wakeup(sleep_time); - for (int repeat = 0; repeat < 5; ++repeat) { - uint64_t start = esp_clk_rtc_time(); - int64_t start_hs = esp_timer_get_time(); - esp_light_sleep_start(); - int64_t stop_hs = esp_timer_get_time(); - uint64_t stop = esp_clk_rtc_time(); - - int diff_us = (int)(stop - start); - int diff_hs_us = (int)(stop_hs - start_hs); - printf("%lld %d\n", sleep_time, (int)(diff_us - sleep_time)); - int32_t threshold = MAX(sleep_time / 100, MAX_SLEEP_TIME_ERROR_US); - TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_us); - TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_hs_us); - fflush(stdout); - } - - vTaskDelay(10 / portTICK_PERIOD_MS); - } -} - -TEST_CASE("light sleep and frequency switching", "[deepsleep]") -{ -#ifndef CONFIG_PM_ENABLE - uart_sclk_t clk_source = UART_SCLK_DEFAULT; -#if SOC_UART_SUPPORT_REF_TICK - clk_source = UART_SCLK_REF_TICK; -#elif SOC_UART_SUPPORT_XTAL_CLK - clk_source = UART_SCLK_XTAL; -#endif - HP_UART_SRC_CLK_ATOMIC() { - uart_ll_set_sclk(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), (soc_module_clk_t)clk_source); - } - uint32_t sclk_freq; - TEST_ESP_OK(uart_get_sclk_freq(clk_source, &sclk_freq)); - HP_UART_SRC_CLK_ATOMIC() { - uart_ll_set_baudrate(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), CONFIG_ESP_CONSOLE_UART_BAUDRATE, sclk_freq); - } -#endif - - rtc_cpu_freq_config_t config_xtal, config_default; - rtc_clk_cpu_freq_get_config(&config_default); - rtc_clk_cpu_freq_mhz_to_config(esp_clk_xtal_freq() / MHZ, &config_xtal); - - esp_sleep_enable_timer_wakeup(1000); - for (int i = 0; i < 1000; ++i) { - if (i % 2 == 0) { - rtc_clk_cpu_freq_set_config_fast(&config_xtal); - } else { - rtc_clk_cpu_freq_set_config_fast(&config_default); - } - printf("%d\n", i); - fflush(stdout); - esp_light_sleep_start(); - } -} - static void do_deep_sleep(void) { esp_sleep_enable_timer_wakeup(100000); @@ -382,106 +529,6 @@ TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub from stack in RTC RAM", "[dee #endif // CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP #endif // ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB -#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED - -__attribute__((unused)) static float get_time_ms(void) -{ - gettimeofday(&tv_stop, NULL); - - float dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f + - (tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f; - return fabs(dt); -} - -__attribute__((unused)) static uint32_t get_cause(void) -{ -#if SOC_PMU_SUPPORTED - uint32_t wakeup_cause = pmu_ll_hp_get_wakeup_cause(&PMU); -#else - uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause(); -#endif - return wakeup_cause; -} - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) && SOC_PM_SUPPORT_EXT0_WAKEUP -// Fails on S2 IDF-2903 - -// This test case verifies deactivation of trigger for wake up sources -TEST_CASE("disable source trigger behavior", "[deepsleep]") -{ - float dt = 0; - - printf("Setup timer and ext0 to wake up immediately from GPIO_13 \n"); - - // Setup ext0 configuration to wake up almost immediately - // The wakeup time is proportional to input capacitance * pullup resistance - ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); - ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); - ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13)); - ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH)); - - // Setup timer to wakeup with timeout - esp_sleep_enable_timer_wakeup(2000000); - - // Save start time - gettimeofday(&tv_start, NULL); - esp_light_sleep_start(); - - dt = get_time_ms(); - printf("Ext0 sleep time = %d \n", (int) dt); - - // Check wakeup from Ext0 using time measurement because wakeup cause is - // not available in light sleep mode - TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt); - - TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0); - - // Disable Ext0 source. Timer source should be triggered - ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT0)); - printf("Disable ext0 trigger and leave timer active.\n"); - - gettimeofday(&tv_start, NULL); - esp_light_sleep_start(); - - dt = get_time_ms(); - printf("Timer sleep time = %d \n", (int) dt); - - TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); - - // Additionally check wakeup cause - TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0); - - // Disable timer source. - ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER)); - - // Setup ext0 configuration to wake up immediately - ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13)); - ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13)); - ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13)); - ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH)); - - printf("Disable timer trigger to wake up from ext0 source.\n"); - - gettimeofday(&tv_start, NULL); - esp_light_sleep_start(); - - dt = get_time_ms(); - printf("Ext0 sleep time = %d \n", (int) dt); - - TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt); - TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0); - - // Check error message when source is already disabled - esp_err_t err_code = esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); - TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE); - - // Disable ext0 wakeup source, as this might interfere with other tests - ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT0)); -} -#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) - -#endif //SOC_RTCIO_INPUT_OUTPUT_SUPPORTED - static void trigger_deepsleep(void) { struct timeval start; diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c index c924b5c5bb..caec9f1e76 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c @@ -68,6 +68,7 @@ TEST_CASE("Task WDT task timeout after peripheral powerdown lightsleep", "[task_ TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); + esp_sleep_set_sleep_context(NULL); // Short delay to allow timeout to occur esp_rom_delay_us(TASK_WDT_TIMEOUT_MS * 1000); diff --git a/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py b/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py index 93d73937ce..03c3ba980b 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py +++ b/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py @@ -11,6 +11,7 @@ from pytest_embedded import Dut pytest.param('default', marks=[pytest.mark.supported_targets]), pytest.param('pd_vddsdio', marks=[pytest.mark.supported_targets]), pytest.param('psram', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32s3, pytest.mark.esp32p4]), + pytest.param('psram_with_pd_top', marks=[pytest.mark.esp32p4]), pytest.param('single_core_esp32', marks=[pytest.mark.esp32]), ] ) diff --git a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default index fcbda27d40..e8104032cf 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default +++ b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default @@ -1,5 +1,4 @@ # Default configuration # Used for testing stack smashing protection CONFIG_COMPILER_STACK_CHECK=y -CONFIG_ESP_SLEEP_DEBUG=y CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y diff --git a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.psram_with_pd_top b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.psram_with_pd_top new file mode 100644 index 0000000000..440009beb1 --- /dev/null +++ b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.psram_with_pd_top @@ -0,0 +1,4 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y diff --git a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.defaults b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.defaults index 55604ff94b..c381fad085 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.defaults +++ b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.defaults @@ -4,3 +4,4 @@ CONFIG_ESP_TASK_WDT_INIT=n # esp_sleep_enable_gpio_switch() has the change to break UART RX during light sleep stress tests # Remove this when IDF-4897 is fixed CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=n +CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h b/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h index 822a4759be..7579bd674e 100644 --- a/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h +++ b/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h @@ -289,15 +289,16 @@ static inline void psram_ctrlr_ll_enable_rd_splice(uint32_t mspi_id, bool en) * @param en enable / disable */ __attribute__((always_inline)) -static inline void psram_ctrlr_ll_enable_module_clock(uint32_t mspi_id, bool en) +static inline void _psram_ctrlr_ll_enable_module_clock(uint32_t mspi_id, bool en) { (void)mspi_id; HP_SYS_CLKRST.soc_clk_ctrl0.reg_psram_sys_clk_en = en; + HP_SYS_CLKRST.peri_clk_ctrl00.reg_psram_pll_clk_en = en; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define psram_ctrlr_ll_enable_module_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; psram_ctrlr_ll_enable_module_clock(__VA_ARGS__) +#define psram_ctrlr_ll_enable_module_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _psram_ctrlr_ll_enable_module_clock(__VA_ARGS__) /** * @brief Reset PSRAM module clock @@ -325,7 +326,7 @@ static inline void psram_ctrlr_ll_reset_module_clock(uint32_t mspi_id) * @param clk_src clock source, see valid sources in type `soc_periph_psram_clk_src_t` */ __attribute__((always_inline)) -static inline void psram_ctrlr_ll_select_clk_source(uint32_t mspi_id, soc_periph_psram_clk_src_t clk_src) +static inline void _psram_ctrlr_ll_select_clk_source(uint32_t mspi_id, soc_periph_psram_clk_src_t clk_src) { (void)mspi_id; uint32_t clk_val = 0; @@ -347,13 +348,12 @@ static inline void psram_ctrlr_ll_select_clk_source(uint32_t mspi_id, soc_periph break; } - HP_SYS_CLKRST.peri_clk_ctrl00.reg_psram_pll_clk_en = 1; HP_SYS_CLKRST.peri_clk_ctrl00.reg_psram_clk_src_sel = clk_val; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define psram_ctrlr_ll_select_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; psram_ctrlr_ll_select_clk_source(__VA_ARGS__) +#define psram_ctrlr_ll_select_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; _psram_ctrlr_ll_select_clk_source(__VA_ARGS__) /** * @brief Set PSRAM core clock @@ -362,15 +362,29 @@ static inline void psram_ctrlr_ll_select_clk_source(uint32_t mspi_id, soc_periph * @param freqdiv Divider value */ __attribute__((always_inline)) -static inline void psram_ctrlr_ll_set_core_clock(uint8_t spi_num, uint32_t freqdiv) +static inline void _psram_ctrlr_ll_set_core_clock_div(uint8_t spi_num, uint32_t freqdiv) { - HP_SYS_CLKRST.peri_clk_ctrl00.reg_psram_core_clk_en = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl00, reg_psram_core_clk_div_num, freqdiv - 1); } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define psram_ctrlr_ll_set_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; psram_ctrlr_ll_set_core_clock(__VA_ARGS__) +#define psram_ctrlr_ll_set_core_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; _psram_ctrlr_ll_set_core_clock_div(__VA_ARGS__) + +/** + * @brief Enable or disable the PSRAM core clock + * + * @param en enable / disable + */ +__attribute__((always_inline)) +static inline void _psram_ctrlr_ll_enable_core_clock(uint8_t spi_num, bool en) +{ + HP_SYS_CLKRST.peri_clk_ctrl00.reg_psram_core_clk_en = en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define psram_ctrlr_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _psram_ctrlr_ll_enable_core_clock(__VA_ARGS__) /** * @brief Set PSRAM bus clock @@ -735,6 +749,24 @@ static inline void psram_ctrlr_ll_common_transaction(uint32_t mspi_id, is_write_erase_operation); } +/** + * @brief Wait MSPI PSRAM controller transaction done + * + */ +__attribute__((always_inline)) +static inline void psram_ctrlr_ll_wait_all_transaction_done(void) +{ +#define ALL_TRANSACTION_DONE ( SPI_MEM_S_ALL_FIFO_EMPTY | \ + SPI_MEM_S_RDATA_AFIFO_REMPTY | \ + SPI_MEM_S_RADDR_AFIFO_REMPTY | \ + SPI_MEM_S_WDATA_AFIFO_REMPTY | \ + SPI_MEM_S_WBLEN_AFIFO_REMPTY | \ + SPI_MEM_S_ALL_AXI_TRANS_AFIFO_EMPTY) + while (SPIMEM2.smem_axi_addr_ctrl.val != ALL_TRANSACTION_DONE) { + ; + } +} + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h b/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h index 23c82b2953..a63ae5fdec 100644 --- a/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h +++ b/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h @@ -76,7 +76,7 @@ extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_L * useful for external use. */ #define SPIMEM_RETENTION_LINK_LEN 8 -extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; +extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; /** * @brief Provide access to systimer configuration registers retention diff --git a/components/soc/esp32c5/beta3/system_retention_periph.c b/components/soc/esp32c5/beta3/system_retention_periph.c index 52822f9272..74d1b2a367 100644 --- a/components/soc/esp32c5/beta3/system_retention_periph.c +++ b/components/soc/esp32c5/beta3/system_retention_periph.c @@ -66,7 +66,7 @@ _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "In #define N_REGS_SPI0_MEM_1() (((SPI_SMEM_AC_REG(0) - SPI_FMEM_PMS0_ATTR_REG(0)) / 4) + 1) #define N_REGS_SPI0_MEM_2() (1) #define N_REGS_SPI0_MEM_3() (((SPI_MEM_DATE_REG(0) - SPI_MEM_MMU_POWER_CTRL_REG(0)) / 4) + 1) -const regdma_entries_config_t spimem_regs_retention[] = { +const regdma_entries_config_t flash_spimem_regs_retention[] = { /* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */ [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), REG_SPI_MEM_BASE(1), REG_SPI_MEM_BASE(1), N_REGS_SPI1_MEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* spi1_mem */ [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI_FMEM_PMS0_ATTR_REG(1), SPI_FMEM_PMS0_ATTR_REG(1), N_REGS_SPI1_MEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, @@ -79,7 +79,7 @@ const regdma_entries_config_t spimem_regs_retention[] = { [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLOCK_GATE_REG(0), N_REGS_SPI0_MEM_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_MMU_POWER_CTRL_REG(0), SPI_MEM_MMU_POWER_CTRL_REG(0), N_REGS_SPI0_MEM_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } }; -_Static_assert(ARRAY_SIZE(spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); +_Static_assert(ARRAY_SIZE(flash_spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); /* Systimer Registers Context */ #define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1) diff --git a/components/soc/esp32c6/include/soc/system_periph_retention.h b/components/soc/esp32c6/include/soc/system_periph_retention.h index 539b3500d3..54f7c3e205 100644 --- a/components/soc/esp32c6/include/soc/system_periph_retention.h +++ b/components/soc/esp32c6/include/soc/system_periph_retention.h @@ -75,7 +75,7 @@ extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_L * useful for external use. */ #define SPIMEM_RETENTION_LINK_LEN 8 -extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; +extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; /** * @brief Provide access to systimer configuration registers retention diff --git a/components/soc/esp32c6/system_retention_periph.c b/components/soc/esp32c6/system_retention_periph.c index 4ff06bdbcb..2d9227575a 100644 --- a/components/soc/esp32c6/system_retention_periph.c +++ b/components/soc/esp32c6/system_retention_periph.c @@ -67,7 +67,7 @@ _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "In #define N_REGS_SPI0_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(0) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(0)) / 4) + 1) #define N_REGS_SPI0_MEM_2() (1) #define N_REGS_SPI0_MEM_3() (((SPI_MEM_DATE_REG(0) - SPI_MEM_MMU_POWER_CTRL_REG(0)) / 4) + 1) -const regdma_entries_config_t spimem_regs_retention[] = { +const regdma_entries_config_t flash_spimem_regs_retention[] = { /* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */ [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), REG_SPI_MEM_BASE(1), REG_SPI_MEM_BASE(1), N_REGS_SPI1_MEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* spi1_mem */ [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), N_REGS_SPI1_MEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, @@ -80,7 +80,7 @@ const regdma_entries_config_t spimem_regs_retention[] = { [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLOCK_GATE_REG(0), N_REGS_SPI0_MEM_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_MMU_POWER_CTRL_REG(0), SPI_MEM_MMU_POWER_CTRL_REG(0), N_REGS_SPI0_MEM_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } }; -_Static_assert(ARRAY_SIZE(spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); +_Static_assert(ARRAY_SIZE(flash_spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); /* Systimer Registers Context */ #define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1) diff --git a/components/soc/esp32h2/include/soc/system_periph_retention.h b/components/soc/esp32h2/include/soc/system_periph_retention.h index 539b3500d3..54f7c3e205 100644 --- a/components/soc/esp32h2/include/soc/system_periph_retention.h +++ b/components/soc/esp32h2/include/soc/system_periph_retention.h @@ -75,7 +75,7 @@ extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_L * useful for external use. */ #define SPIMEM_RETENTION_LINK_LEN 8 -extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; +extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; /** * @brief Provide access to systimer configuration registers retention diff --git a/components/soc/esp32h2/system_retention_periph.c b/components/soc/esp32h2/system_retention_periph.c index d9f3c5b469..436840e682 100644 --- a/components/soc/esp32h2/system_retention_periph.c +++ b/components/soc/esp32h2/system_retention_periph.c @@ -66,7 +66,7 @@ _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "In #define N_REGS_SPI0_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(0) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(0)) / 4) + 1) #define N_REGS_SPI0_MEM_2() (1) #define N_REGS_SPI0_MEM_3() (((SPI_MEM_DATE_REG(0) - SPI_MEM_MMU_POWER_CTRL_REG(0)) / 4) + 1) -const regdma_entries_config_t spimem_regs_retention[] = { +const regdma_entries_config_t flash_spimem_regs_retention[] = { /* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */ [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), REG_SPI_MEM_BASE(1), REG_SPI_MEM_BASE(1), N_REGS_SPI1_MEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* spi1_mem */ [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), N_REGS_SPI1_MEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, @@ -79,7 +79,7 @@ const regdma_entries_config_t spimem_regs_retention[] = { [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLOCK_GATE_REG(0), N_REGS_SPI0_MEM_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_MMU_POWER_CTRL_REG(0), SPI_MEM_MMU_POWER_CTRL_REG(0), N_REGS_SPI0_MEM_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } }; -_Static_assert(ARRAY_SIZE(spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); +_Static_assert(ARRAY_SIZE(flash_spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); /* Systimer Registers Context */ #define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1) diff --git a/components/soc/esp32p4/include/soc/system_periph_retention.h b/components/soc/esp32p4/include/soc/system_periph_retention.h index d7fd022775..45041ad49b 100644 --- a/components/soc/esp32p4/include/soc/system_periph_retention.h +++ b/components/soc/esp32p4/include/soc/system_periph_retention.h @@ -62,18 +62,28 @@ extern const regdma_entries_config_t tg_regs_retention[TIMG_RETENTION_LINK_LEN]; * This is an internal function of the sleep retention driver, and is not * useful for external use. */ -#define IOMUX_RETENTION_LINK_LEN 2 +#define IOMUX_RETENTION_LINK_LEN 3 extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_LEN]; /** - * @brief Provide access to spimem configuration registers retention + * @brief Provide access to FLASH spimem configuration registers retention * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. */ -#define SPIMEM_RETENTION_LINK_LEN 8 -extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK_LEN]; +#define SPIMEM_FLASH_RETENTION_LINK_LEN 8 +extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_FLASH_RETENTION_LINK_LEN]; + +/** + * @brief Provide access to PSRAM spimem configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define SPIMEM_PSRAM_RETENTION_LINK_LEN 14 +extern const regdma_entries_config_t psram_spimem_regs_retention[SPIMEM_PSRAM_RETENTION_LINK_LEN]; /** * @brief Provide access to systimer configuration registers retention diff --git a/components/soc/esp32p4/system_retention_periph.c b/components/soc/esp32p4/system_retention_periph.c index 1cc4a49da4..18a2ea302f 100644 --- a/components/soc/esp32p4/system_retention_periph.c +++ b/components/soc/esp32p4/system_retention_periph.c @@ -7,13 +7,17 @@ #include "soc/cache_reg.h" #include "soc/gpio_reg.h" #include "soc/hp_system_reg.h" +#include "soc/hp_sys_clkrst_reg.h" #include "soc/io_mux_reg.h" +#include "soc/iomux_mspi_pin_reg.h" #include "soc/interrupt_core0_reg.h" #include "soc/interrupt_core1_reg.h" #include "soc/pau_reg.h" #include "soc/regdma.h" #include "soc/system_periph_retention.h" #include "soc/spi_mem_reg.h" +#include "soc/spi_mem_s_reg.h" +#include "soc/spi1_mem_s_reg.h" #include "soc/systimer_reg.h" #include "soc/timer_group_reg.h" #include "soc/timer_periph.h" @@ -44,36 +48,71 @@ _Static_assert(ARRAY_SIZE(hp_system_regs_retention) == HP_SYSTEM_RETENTION_LINK_ /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1) -#define N_REGS_IOMUX_1() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1) +#define N_REGS_GPIO_MTX() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1) +#define N_REGS_MSPI_IOMUX() (((IOMUX_MSPI_PIN_PSRAM_DQS_1_PIN0_REG - IOMUX_MSPI_PIN_CLK_EN0_REG) / 4) + 1) const regdma_entries_config_t iomux_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) }, /* io_mux */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), DR_REG_GPIO_BASE, DR_REG_GPIO_BASE, N_REGS_IOMUX_1(), 0, 0), .owner = ENTRY(0) }, + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) }, /* io_mux */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), DR_REG_GPIO_BASE, DR_REG_GPIO_BASE, N_REGS_GPIO_MTX(), 0, 0), .owner = ENTRY(0) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), IOMUX_MSPI_PIN_CLK_EN0_REG, IOMUX_MSPI_PIN_CLK_EN0_REG, N_REGS_GPIO_MTX(), 0, 0), .owner = ENTRY(0) }, }; _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "Inconsistent IOMUX retention link length definitions"); /* Memory SPI Registers Context */ -#define N_REGS_SPI1_MEM_0() (((SPI1_MEM_C_SUS_STATUS_REG - DR_REG_FLASH_SPI1_BASE) / 4) + 1) -#define N_REGS_SPI1_MEM_1() (((SPI1_MEM_C_DDR_REG - SPI1_MEM_C_INT_ENA_REG) / 4) + 1) -#define N_REGS_SPI1_MEM_2() (1) -#define N_REGS_SPI1_MEM_3() (1) -#define N_REGS_SPI0_MEM_0() ((SPI_MEM_C_SMEM_DDR_REG - DR_REG_FLASH_SPI0_BASE) / 4 + 1) -#define N_REGS_SPI0_MEM_1() (((SPI_MEM_C_SMEM_AC_REG - SPI_MEM_C_FMEM__PMS0_ATTR_REG) / 4) + 1) -#define N_REGS_SPI0_MEM_2() (1) -#define N_REGS_SPI0_MEM_3() (((SPI_MEM_C_DATE_REG - SPI_MEM_C_MMU_POWER_CTRL_REG) / 4) + 1) -const regdma_entries_config_t spimem_regs_retention[] = { +#define N_REGS_SPI1_C_MEM_0() (((SPI1_MEM_C_SUS_STATUS_REG - DR_REG_FLASH_SPI1_BASE) / 4) + 1) +#define N_REGS_SPI1_C_MEM_1() (((SPI1_MEM_C_DDR_REG - SPI1_MEM_C_INT_ENA_REG) / 4) + 1) +#define N_REGS_SPI1_C_MEM_2() (1) +#define N_REGS_SPI1_C_MEM_3() (1) +#define N_REGS_SPI0_C_MEM_0() ((SPI_MEM_C_SMEM_DDR_REG - DR_REG_FLASH_SPI0_BASE) / 4 + 1) +#define N_REGS_SPI0_C_MEM_1() (((SPI_MEM_C_SMEM_AC_REG - SPI_MEM_C_FMEM__PMS0_ATTR_REG) / 4) + 1) +#define N_REGS_SPI0_C_MEM_2() (1) +#define N_REGS_SPI0_C_MEM_3() (((SPI_MEM_C_DPA_CTRL_REG - SPI_MEM_C_MMU_POWER_CTRL_REG) / 4) + 1) + +const regdma_entries_config_t flash_spimem_regs_retention[] = { /* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */ - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), DR_REG_FLASH_SPI1_BASE, DR_REG_FLASH_SPI1_BASE, N_REGS_SPI1_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi1_mem */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI1_MEM_C_INT_ENA_REG, SPI1_MEM_C_INT_ENA_REG, N_REGS_SPI1_MEM_1(), 0, 0), .owner = ENTRY(0) }, - [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x02), SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_TIMING_CALI_REG, N_REGS_SPI1_MEM_2(), 0, 0), .owner = ENTRY(0) }, - [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x03), SPI1_MEM_C_CLOCK_GATE_REG, SPI1_MEM_C_CLOCK_GATE_REG, N_REGS_SPI1_MEM_3(), 0, 0), .owner = ENTRY(0) }, + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), DR_REG_FLASH_SPI1_BASE, DR_REG_FLASH_SPI1_BASE, N_REGS_SPI1_C_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi1_mem */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI1_MEM_C_INT_ENA_REG, SPI1_MEM_C_INT_ENA_REG, N_REGS_SPI1_C_MEM_1(), 0, 0), .owner = ENTRY(0) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x02), SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_TIMING_CALI_REG, N_REGS_SPI1_C_MEM_2(), 0, 0), .owner = ENTRY(0) }, /* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */ - [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x04), DR_REG_FLASH_SPI0_BASE, DR_REG_FLASH_SPI0_BASE, N_REGS_SPI0_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi0_mem */ - [5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x05), SPI_MEM_C_FMEM__PMS0_ATTR_REG, SPI_MEM_C_FMEM__PMS0_ATTR_REG, N_REGS_SPI0_MEM_1(), 0, 0), .owner = ENTRY(0) }, - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_C_CLOCK_GATE_REG, SPI_MEM_C_CLOCK_GATE_REG, N_REGS_SPI0_MEM_2(), 0, 0), .owner = ENTRY(0) }, - [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_C_MMU_POWER_CTRL_REG, SPI_MEM_C_MMU_POWER_CTRL_REG, N_REGS_SPI0_MEM_3(), 0, 0), .owner = ENTRY(0) } + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x04), DR_REG_FLASH_SPI0_BASE, DR_REG_FLASH_SPI0_BASE, N_REGS_SPI0_C_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi0_mem */ + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x05), SPI_MEM_C_FMEM__PMS0_ATTR_REG, SPI_MEM_C_FMEM__PMS0_ATTR_REG, N_REGS_SPI0_C_MEM_1(), 0, 0), .owner = ENTRY(0) }, + [5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_C_CLOCK_GATE_REG, SPI_MEM_C_CLOCK_GATE_REG, N_REGS_SPI0_C_MEM_2(), 0, 0), .owner = ENTRY(0) }, + [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_C_MMU_POWER_CTRL_REG, SPI_MEM_C_MMU_POWER_CTRL_REG, N_REGS_SPI0_C_MEM_3(), 0, 0), .owner = ENTRY(0) }, + [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SPIMEM_LINK(0x08), SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_UPDATE, SPI_MEM_C_TIMING_CALI_UPDATE_M, 1, 0), .owner = ENTRY(0) }, }; -_Static_assert(ARRAY_SIZE(spimem_regs_retention) == SPIMEM_RETENTION_LINK_LEN, "Inconsistent SPI Mem retention link length definitions"); +_Static_assert(ARRAY_SIZE(flash_spimem_regs_retention) == SPIMEM_FLASH_RETENTION_LINK_LEN, "Inconsistent Flash SPI Mem retention link length definitions"); + +#if CONFIG_SPIRAM +#define N_REGS_SPI0_S_MEM_0() (((SPI_MEM_S_USER2_REG - SPI_MEM_S_CTRL_REG) / 4) + 1) +#define N_REGS_SPI0_S_MEM_1() (((SPI_MEM_S_FSM_REG - SPI_MEM_S_MISC_REG) / 4) + 1) +#define N_REGS_SPI0_S_MEM_2() (((SPI_MEM_S_SMEM_DDR_REG - SPI_MEM_S_INT_ENA_REG) / 4) + 1) +#define N_REGS_SPI0_S_MEM_3() (((SPI_MEM_S_SMEM_DOUT_HEX_MODE_REG - SPI_MEM_S_ECC_CTRL_REG) / 4) + 1) +#define N_REGS_SPI0_S_MEM_4() (((SPI_MEM_S_DPA_CTRL_REG - SPI_MEM_S_MMU_POWER_CTRL_REG) / 4) + 1) +#define N_REGS_SPI1_S_MEM_0() ((SPI1_MEM_S_CACHE_FCTRL_REG - SPI1_MEM_S_CMD_REG) / 4 + 1) +#define N_REGS_SPI1_S_MEM_1() (((SPI1_MEM_S_SUS_STATUS_REG - SPI1_MEM_S_FLASH_WAITI_CTRL_REG) / 4) + 1) +#define N_REGS_SPI1_S_MEM_2() (((SPI1_MEM_S_DDR_REG - SPI1_MEM_S_INT_ENA_REG) / 4) + 1) +#define N_REGS_SPI1_S_MEM_3() (1) +#define N_REGS_SPI1_S_MEM_4() (1) + +const regdma_entries_config_t psram_spimem_regs_retention[SPIMEM_PSRAM_RETENTION_LINK_LEN] = { + [0] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x08), HP_SYS_CLKRST_PERI_CLK_CTRL00_REG, HP_SYS_CLKRST_REG_PSRAM_CORE_CLK_EN, HP_SYS_CLKRST_REG_PSRAM_CORE_CLK_EN_M, 1, 0), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on restore + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x09), HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, HP_SYS_CLKRST_REG_PSRAM_SYS_CLK_EN, HP_SYS_CLKRST_REG_PSRAM_SYS_CLK_EN_M, 1, 0), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on restore + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0a), SPI_MEM_S_CTRL_REG, SPI_MEM_S_CTRL_REG, N_REGS_SPI0_S_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi0_mem */ + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0b), SPI_MEM_S_MISC_REG, SPI_MEM_S_MISC_REG, N_REGS_SPI0_S_MEM_1(), 0, 0), .owner = ENTRY(0) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0c), SPI_MEM_S_INT_ENA_REG, SPI_MEM_S_INT_ENA_REG, N_REGS_SPI0_S_MEM_2(), 0, 0), .owner = ENTRY(0) }, + [5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0d), SPI_MEM_S_ECC_CTRL_REG, SPI_MEM_S_ECC_CTRL_REG, N_REGS_SPI0_S_MEM_3(), 0, 0), .owner = ENTRY(0) }, + [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0e), SPI_MEM_S_MMU_POWER_CTRL_REG, SPI_MEM_S_MMU_POWER_CTRL_REG, N_REGS_SPI0_S_MEM_4(), 0, 0), .owner = ENTRY(0) }, + [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x0f), SPI1_MEM_S_CMD_REG, SPI1_MEM_S_CMD_REG, N_REGS_SPI1_S_MEM_0(), 0, 0), .owner = ENTRY(0) }, /* spi1_mem */ + [8] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x10), SPI1_MEM_S_FLASH_WAITI_CTRL_REG, SPI1_MEM_S_FLASH_WAITI_CTRL_REG, N_REGS_SPI1_S_MEM_1(), 0, 0), .owner = ENTRY(0) }, + [9] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x11), SPI1_MEM_S_INT_ENA_REG, SPI1_MEM_S_INT_ENA_REG, N_REGS_SPI1_S_MEM_2(), 0, 0), .owner = ENTRY(0) }, + [10] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x12), SPI1_MEM_S_TIMING_CALI_REG, SPI1_MEM_S_TIMING_CALI_REG, N_REGS_SPI1_S_MEM_3(), 0, 0), .owner = ENTRY(0) }, + [11] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x13), SPI1_MEM_S_CLOCK_GATE_REG, SPI1_MEM_S_CLOCK_GATE_REG, N_REGS_SPI1_S_MEM_4(), 0, 0), .owner = ENTRY(0) }, + [12] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x14), HP_SYS_CLKRST_PERI_CLK_CTRL00_REG, 0, HP_SYS_CLKRST_REG_PSRAM_CORE_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on backup + [13] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x15), HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, 0, HP_SYS_CLKRST_REG_PSRAM_SYS_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on backup +}; + +_Static_assert(ARRAY_SIZE(psram_spimem_regs_retention) == SPIMEM_PSRAM_RETENTION_LINK_LEN, "Inconsistent PSRAM SPI Mem retention link length definitions"); +#endif /* Systimer Registers Context */ #define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1)