From ef7406257a0b38b1b69d6d8ee615e79c99ad30e0 Mon Sep 17 00:00:00 2001 From: wanckl Date: Mon, 23 Sep 2024 20:40:22 +0800 Subject: [PATCH 1/2] feat(driver_spi): spi master support sleep retention(recovery) --- .../include/driver/spi_common.h | 1 + .../esp_driver_spi/src/gpspi/spi_common.c | 57 +++++- .../esp_driver_spi/src/gpspi/spi_master.c | 3 +- .../test_apps/master/main/CMakeLists.txt | 2 +- .../test_apps/master/main/test_spi_master.c | 135 ++++++++++++++ .../master/main/test_spi_master_sct.c | 130 ++++++++++++- .../test_apps/master/sdkconfig.ci.defaults | 2 - .../master/sdkconfig.ci.freertos_compliance | 2 + .../test_apps/master/sdkconfig.ci.release | 1 + .../test_apps/master/sdkconfig.defaults | 4 +- .../soc/esp32/register/soc/spi_struct.h | 173 +----------------- components/soc/esp32/spi_periph.c | 3 - components/soc/esp32c2/spi_periph.c | 2 - components/soc/esp32c3/spi_periph.c | 2 - .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c5/include/soc/soc.h | 2 +- components/soc/esp32c5/include/soc/soc_caps.h | 1 + .../soc/esp32c5/register/soc/reg_base.h | 2 +- components/soc/esp32c5/spi_periph.c | 67 ++++--- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c6/include/soc/soc_caps.h | 1 + components/soc/esp32c6/spi_periph.c | 70 ++++--- .../esp32c61/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c61/include/soc/soc_caps.h | 1 + .../soc/esp32c61/register/soc/reg_base.h | 2 +- .../soc/esp32c61/register/soc/spi_reg.h | 76 ++++---- components/soc/esp32c61/spi_periph.c | 67 ++++--- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32h2/include/soc/soc_caps.h | 1 + components/soc/esp32h2/register/soc/spi_reg.h | 78 ++++---- components/soc/esp32h2/spi_periph.c | 69 ++++--- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + components/soc/esp32p4/spi_periph.c | 76 +++++--- components/soc/esp32s2/spi_periph.c | 3 - components/soc/esp32s3/spi_periph.c | 3 - components/soc/include/soc/spi_periph.h | 25 ++- .../api-reference/peripherals/spi_master.rst | 8 + .../api-reference/system/power_management.rst | 4 +- .../api-reference/peripherals/spi_master.rst | 8 + .../api-reference/system/power_management.rst | 4 +- 41 files changed, 698 insertions(+), 408 deletions(-) delete mode 100644 components/esp_driver_spi/test_apps/master/sdkconfig.ci.defaults diff --git a/components/esp_driver_spi/include/driver/spi_common.h b/components/esp_driver_spi/include/driver/spi_common.h index c0c1918afdbc..2f4de6a121ae 100644 --- a/components/esp_driver_spi/include/driver/spi_common.h +++ b/components/esp_driver_spi/include/driver/spi_common.h @@ -64,6 +64,7 @@ extern "C" #define SPICOMMON_BUSFLAG_IO4_IO7 (1<<8) ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized. #define SPICOMMON_BUSFLAG_OCTAL (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7) ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode. #define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS +#define SPICOMMON_BUSFLAG_SLP_ALLOW_PD (1<<9) ///< Allow to power down the peripheral during light sleep, and auto recover then. /** * @brief SPI DMA channels diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 7724af5a1cf5..7e2ed7cc5287 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -21,6 +21,7 @@ #include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h" #include "esp_private/esp_cache_private.h" +#include "esp_private/sleep_retention.h" #include "esp_dma_utils.h" #include "hal/spi_hal.h" #include "hal/gpio_hal.h" @@ -49,6 +50,7 @@ static const char *SPI_TAG = "spi"; typedef struct { int host_id; + _lock_t mutex; // mutex for controller spi_destroy_func_t destroy_func; void* destroy_arg; spi_bus_attr_t bus_attr; @@ -587,7 +589,8 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf } uint32_t missing_flag = flags & ~temp_flag; - missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag + missing_flag &= ~SPICOMMON_BUSFLAG_MASTER; //don't check this flag + missing_flag &= ~SPICOMMON_BUSFLAG_SLP_ALLOW_PD; if (missing_flag != 0) { //check pins existence @@ -778,6 +781,16 @@ spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id) return bus_ctx[host_id]->bus_attr.lock; } +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +static esp_err_t s_bus_create_sleep_retention_cb(void *arg) +{ + spicommon_bus_context_t *ctx = arg; + return sleep_retention_entries_create(spi_reg_retention_info[ctx->host_id - 1].entry_array, + spi_reg_retention_info[ctx->host_id - 1].array_size, + REGDMA_LINK_PRI_GPSPI, + spi_reg_retention_info[ctx->host_id - 1].module_id); +} +#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION //----------------------------------------------------------master bus init-------------------------------------------------------// esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan) { @@ -846,6 +859,34 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * goto cleanup; } +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = s_bus_create_sleep_retention_cb, + .arg = ctx, + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), + }; + + _lock_acquire(&ctx->mutex); + if (sleep_retention_module_init(spi_reg_retention_info[host_id - 1].module_id, &init_param) == ESP_OK) { + if ((bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) && (sleep_retention_module_allocate(spi_reg_retention_info[host_id - 1].module_id) != ESP_OK)) { + // even though the sleep retention create failed, SPI driver should still work, so just warning here + ESP_LOGW(SPI_TAG, "alloc sleep recover failed, peripherals may hold power on"); + } + } else { + // even the sleep retention init failed, SPI driver should still work, so just warning here + ESP_LOGW(SPI_TAG, "init sleep recover failed, spi may offline after sleep"); + } + _lock_release(&ctx->mutex); +#else + if (bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) { + ESP_LOGE(SPI_TAG, "power down peripheral in sleep is not enabled or not supported on your target"); + } +#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION + #ifdef CONFIG_PM_ENABLE err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master", &bus_attr->pm_lock); @@ -927,9 +968,23 @@ esp_err_t spi_bus_free(spi_host_device_t host_id) } spicommon_bus_free_io_cfg(&bus_attr->bus_cfg); +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + const periph_retention_module_t retention_id = spi_reg_retention_info[host_id - 1].module_id; + _lock_acquire(&ctx->mutex); + if (sleep_retention_get_created_modules() & BIT(retention_id)) { + assert(sleep_retention_get_inited_modules() & BIT(retention_id)); + sleep_retention_module_free(retention_id); + } + if (sleep_retention_get_inited_modules() & BIT(retention_id)) { + sleep_retention_module_deinit(retention_id); + } + _lock_release(&ctx->mutex); +#endif + #ifdef CONFIG_PM_ENABLE esp_pm_lock_delete(bus_attr->pm_lock); #endif + spi_bus_deinit_lock(bus_attr->lock); if (ctx->dma_ctx) { free(ctx->dma_ctx->dmadesc_tx); diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index bc2ce1967f56..7237a0edebcf 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -345,8 +345,7 @@ static esp_err_t spi_master_deinit_driver(void* arg) int host_id = host->id; SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG); - int x; - for (x = 0; x < DEV_NUM_MAX; x++) { + for (int x = 0; x < DEV_NUM_MAX; x++) { SPI_CHECK(host->device[x] == NULL, "not all CSses freed", ESP_ERR_INVALID_STATE); } diff --git a/components/esp_driver_spi/test_apps/master/main/CMakeLists.txt b/components/esp_driver_spi/test_apps/master/main/CMakeLists.txt index 6af72ca6623a..cc99e1467afa 100644 --- a/components/esp_driver_spi/test_apps/master/main/CMakeLists.txt +++ b/components/esp_driver_spi/test_apps/master/main/CMakeLists.txt @@ -8,7 +8,7 @@ set(srcs # sct test using slave hd APIs, need slave hd support # tmp skip sct test under iram_safe, both sct and slave hd are not cleaned -if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2 AND NOT CONFIG_COMPILER_DUMP_RTL_FILES) +if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2 AND CONFIG_SOC_SPI_SCT_SUPPORTED AND NOT CONFIG_COMPILER_DUMP_RTL_FILES) list(APPEND srcs "test_spi_master_sct.c") endif() diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c index c59347d3ebcd..d08e8996bd71 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c @@ -19,6 +19,9 @@ #include "esp_private/cache_utils.h" #include "esp_private/spi_common_internal.h" #include "esp_private/esp_clk.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/esp_pmu.h" #include "esp_heap_caps.h" #include "esp_clk_tree.h" #include "esp_timer.h" @@ -1788,3 +1791,135 @@ TEST_CASE("test_bus_free_safty_to_remain_devices", "[spi]") TEST_ESP_OK(spi_bus_remove_device(dev1)); TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST)); } + +TEST_CASE("test_spi_master_sleep_retention", "[spi]") +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + + spi_device_handle_t dev_handle; + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS; + buscfg.flags |= SPICOMMON_BUSFLAG_SLP_ALLOW_PD; + uint8_t send[16] = "hello spi x\n"; + uint8_t recv[16]; + spi_transaction_t trans_cfg = { + .length = 8 * sizeof(send), + .tx_buffer = send, + .rx_buffer = recv, + }; + + for (int periph = SPI2_HOST; periph < SPI_HOST_MAX; periph ++) { + for (int test_dma = 0; test_dma <= 1; test_dma ++) { + int use_dma = SPI_DMA_DISABLED; +#if SOC_GDMA_SUPPORT_SLEEP_RETENTION // TODO: IDF-11317 test dma on esp32 and s2 + use_dma = test_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED; +#endif + printf("Retention on GPSPI%d with dma: %d\n", periph + 1, use_dma); + TEST_ESP_OK(spi_bus_initialize(periph, &buscfg, use_dma)); + // set spi "self-loop" after bus initialized + spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, spi_periph_signal[periph].spid_out); + TEST_ESP_OK(spi_bus_add_device(periph, &devcfg, &dev_handle)); + + for (uint8_t cnt = 0; cnt < 3; cnt ++) { + printf("Going into sleep...\n"); + TEST_ESP_OK(esp_light_sleep_start()); + printf("Waked up!\n"); + + // check if the sleep happened as expected + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // check if the power domain also is powered down + TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + memset(recv, 0, sizeof(recv)); + send[10] = cnt + 'A'; + TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg)); + printf("%s", recv); + spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send)); + } + + TEST_ESP_OK(spi_bus_remove_device(dev_handle)); + TEST_ESP_OK(spi_bus_free(periph)); + } + } + + esp_sleep_set_sleep_context(NULL); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif +} + +#if 0 /* Temp disable, TODO: IDFCI-2455*/ +#if CONFIG_PM_ENABLE +TEST_CASE("test_spi_master_auto_sleep_retention", "[spi]") +{ + // Configure dynamic frequency scaling: + // maximum and minimum frequencies are set in sdkconfig, + // automatic light sleep is enabled if tickless idle support is enabled. + uint32_t xtal_hz = 0; + esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz); + esp_pm_config_t pm_config = { + .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, + .min_freq_mhz = xtal_hz / 1000000, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true, +#endif + }; + TEST_ESP_OK(esp_pm_configure(&pm_config)); + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + + for (uint8_t allow_pd = 0; allow_pd < 2; allow_pd ++) { + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + buscfg.flags = (allow_pd) ? SPICOMMON_BUSFLAG_SLP_ALLOW_PD : 0; + buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS; + TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_DISABLED)); + // set spi "self-loop" after bus initialized + spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out); + + spi_device_handle_t dev_handle; + spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev_handle)); + + uint8_t send[13] = "hello spi 0\n"; + uint8_t recv[13]; + spi_transaction_t trans_cfg = { + .length = 8 * sizeof(send), + .tx_buffer = send, + .rx_buffer = recv, + }; + + for (uint8_t cnt = 0; cnt < 3; cnt ++) { + printf("Going into Auto sleep with power %s ...\n", (buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? "down" : "hold"); + vTaskDelay(1000); //auto light sleep here + printf("Waked up!\n"); + + // check if the sleep happened as expected + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // check if the power domain also is powered down + TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + memset(recv, 0, sizeof(recv)); + send[10] = cnt + '0'; + TEST_ESP_OK(spi_device_polling_transmit(dev_handle, &trans_cfg)); + printf("%s", recv); + spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send)); + } + + TEST_ESP_OK(spi_bus_remove_device(dev_handle)); + TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST)); + } + esp_sleep_set_sleep_context(NULL); + pm_config.light_sleep_enable = false; + TEST_ESP_OK(esp_pm_configure(&pm_config)); +} +#endif //CONFIG_PM_ENABLE +#endif // 0 diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c index 2efb4184d91a..d0e203704d35 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c @@ -15,6 +15,9 @@ #include "esp_heap_caps.h" #include "driver/spi_master.h" #include "esp_private/spi_master_internal.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/esp_pmu.h" #include "driver/spi_slave_hd.h" #include "driver/spi_slave.h" #include "soc/spi_pins.h" @@ -22,7 +25,6 @@ __attribute__((unused)) static const char *TAG = "SCT"; -#if (SOC_SPI_SUPPORT_SLAVE_HD_VER2 && SOC_SPI_SCT_SUPPORTED) /*----------------------------------------------------------- * HD SCT Functional Test *-----------------------------------------------------------*/ @@ -230,7 +232,6 @@ TEST_CASE_MULTIPLE_DEVICES("SPI_Master_SCT_HD_Functional", "[spi_ms]", hd_master TEST_CASE("spi_master: test_sct_dma_desc_oob_on_tail", "[spi]") { spi_device_handle_t handle; - spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); buscfg.max_transfer_sz = 4092 * 8; @@ -291,4 +292,127 @@ TEST_CASE("spi_master: test_sct_dma_desc_oob_on_tail", "[spi]") TEST_ESP_OK(spi_bus_free(SPI2_HOST)); } -#endif //#if (SOC_SPI_SUPPORT_SLAVE_HD_VER2 && SOC_SPI_SCT_SUPPORTED) +/*----------------------------------------------------------- + * Sleep Retention Test + *-----------------------------------------------------------*/ +#define TEST_SLP_DATA_LEN 64 +//Master write, slave read, wrt slave reg +#define TEST_SLP_BUF_ID 12 +#define TEST_SLP_BUF_VAL 0x11223344 + +static void sleep_master(void) +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); +#if ESP_SLEEP_POWER_DOWN_CPU + sleep_cpu_configure(true); +#endif + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + + spi_device_handle_t handle; + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + buscfg.max_transfer_sz = 4092 * 10; +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + buscfg.flags |= SPICOMMON_BUSFLAG_SLP_ALLOW_PD; +#endif + spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + devcfg.command_bits = 8; + devcfg.address_bits = 8; + devcfg.dummy_bits = 8; + devcfg.flags = SPI_DEVICE_HALFDUPLEX; + TEST_ESP_OK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO)); + TEST_ESP_OK(spi_bus_add_device(SPI2_HOST, &devcfg, &handle)); + TEST_ESP_OK(spi_bus_multi_trans_mode_enable(handle, true)); + unity_send_signal("Master ready"); + + //Test data preparation + uint32_t master_tx_val = TEST_SLP_BUF_VAL; + uint8_t *master_tx_buf = heap_caps_calloc(1, TEST_SLP_DATA_LEN, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + test_fill_random_to_buffers_dualboard(199, master_tx_buf, master_tx_buf, TEST_SLP_DATA_LEN); + //---------------------Master TX---------------------------// + spi_multi_transaction_t *ret_seg_trans = NULL; + spi_multi_transaction_t tx_seg_trans[3] = { + { + .base = { + .cmd = 0x1, + .addr = TEST_SLP_BUF_ID, + .length = 4 * 8, + .tx_buffer = (uint8_t *) &master_tx_val, + }, + }, + { + .base = { + .cmd = 0x3, + .addr = 0xf2, + .length = TEST_SLP_DATA_LEN * 8, + .tx_buffer = master_tx_buf, + }, + .dummy_bits = 8, + }, + { + .base = { + .cmd = 0x7, + }, + }, + }; + + unity_wait_for_signal("Slave ready"); + printf("Going into sleep with power down ...\n"); + TEST_ESP_OK(esp_light_sleep_start()); + printf("Waked up!\n"); + // check if the sleep happened as expected + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // check if the power domain also is powered down + TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + TEST_ESP_OK(spi_device_queue_multi_trans(handle, tx_seg_trans, 3, portMAX_DELAY)); + TEST_ESP_OK(spi_device_get_multi_trans_result(handle, &ret_seg_trans, portMAX_DELAY)); + TEST_ASSERT(ret_seg_trans == tx_seg_trans); + ESP_LOG_BUFFER_HEX("Master tx", master_tx_buf, TEST_SLP_DATA_LEN); + + free(master_tx_buf); + TEST_ESP_OK(spi_bus_multi_trans_mode_enable(handle, false)); + TEST_ESP_OK(spi_bus_remove_device(handle)); + TEST_ESP_OK(spi_bus_free(SPI2_HOST)); + esp_sleep_set_sleep_context(NULL); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif +} + +static void sleep_slave(void) +{ + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG(); + slave_hd_cfg.dma_chan = SPI_DMA_CH_AUTO, + TEST_ESP_OK(spi_slave_hd_init(SPI2_HOST, &buscfg, &slave_hd_cfg)); + + //Test data preparation + uint32_t slave_rx_val = 0; + uint8_t *slave_rx_buf = heap_caps_calloc(1, TEST_SLP_DATA_LEN, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + uint8_t *master_tx_buf = heap_caps_calloc(1, TEST_SLP_DATA_LEN, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + test_fill_random_to_buffers_dualboard(199, master_tx_buf, master_tx_buf, TEST_SLP_DATA_LEN); + //---------------------Slave RX---------------------------// + spi_slave_hd_data_t *ret_trans = NULL; + spi_slave_hd_data_t slave_rx_trans = { + .data = slave_rx_buf, + .len = TEST_SLP_DATA_LEN, + }; + unity_wait_for_signal("Master ready"); + TEST_ESP_OK(spi_slave_hd_queue_trans(SPI2_HOST, SPI_SLAVE_CHAN_RX, &slave_rx_trans, portMAX_DELAY)); + unity_send_signal("Slave ready"); + TEST_ESP_OK(spi_slave_hd_get_trans_res(SPI2_HOST, SPI_SLAVE_CHAN_RX, &ret_trans, portMAX_DELAY)); + TEST_ASSERT(ret_trans == &slave_rx_trans); + + spitest_cmp_or_dump(master_tx_buf, slave_rx_buf, TEST_SLP_DATA_LEN); + spi_slave_hd_read_buffer(SPI2_HOST, TEST_SLP_BUF_ID, (uint8_t *)&slave_rx_val, 4); + ESP_LOGI("Slave", "Slave Reg[%d] value is: 0x%" PRIx32, TEST_SLP_BUF_ID, slave_rx_val); + TEST_ASSERT(slave_rx_val == TEST_SLP_BUF_VAL); + + free(master_tx_buf); + free(slave_rx_buf); + TEST_ESP_OK(spi_slave_hd_deinit(SPI2_HOST)); +} +TEST_CASE_MULTIPLE_DEVICES("test_spi_master_sct_sleep_retention", "[spi_ms]", sleep_master, sleep_slave); diff --git a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.defaults b/components/esp_driver_spi/test_apps/master/sdkconfig.ci.defaults deleted file mode 100644 index 250a29bc45bd..000000000000 --- a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.defaults +++ /dev/null @@ -1,2 +0,0 @@ -# don't delete. -# used for CI to compile a default config when 'sdkconfig.ci.xxxx' is exist diff --git a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.freertos_compliance b/components/esp_driver_spi/test_apps/master/sdkconfig.ci.freertos_compliance index c3eaa50fa4b9..272fdd428529 100644 --- a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.freertos_compliance +++ b/components/esp_driver_spi/test_apps/master/sdkconfig.ci.freertos_compliance @@ -1 +1,3 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE=y diff --git a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.release b/components/esp_driver_spi/test_apps/master/sdkconfig.ci.release index 3cff15d49e20..ee9acb0df404 100644 --- a/components/esp_driver_spi/test_apps/master/sdkconfig.ci.release +++ b/components/esp_driver_spi/test_apps/master/sdkconfig.ci.release @@ -1,3 +1,4 @@ +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_spi/test_apps/master/sdkconfig.defaults b/components/esp_driver_spi/test_apps/master/sdkconfig.defaults index b308cb2ddda0..fff8c78591b1 100644 --- a/components/esp_driver_spi/test_apps/master/sdkconfig.defaults +++ b/components/esp_driver_spi/test_apps/master/sdkconfig.defaults @@ -1,2 +1,4 @@ CONFIG_FREERTOS_HZ=1000 -CONFIG_ESP_TASK_WDT=n +CONFIG_ESP_TASK_WDT_INIT=n +# primitives for checking sleep internal state +CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/soc/esp32/register/soc/spi_struct.h b/components/soc/esp32/register/soc/spi_struct.h index 36fe885c73dd..320df8e94894 100644 --- a/components/soc/esp32/register/soc/spi_struct.h +++ b/components/soc/esp32/register/soc/spi_struct.h @@ -488,177 +488,7 @@ typedef volatile struct spi_dev_s { uint32_t dma_outlink_dscr_bf1; /*The content of current out descriptor data buffer pointer.*/ uint32_t dma_rx_status; /*spi dma read data from memory status.*/ uint32_t dma_tx_status; /*spi dma write data to memory status.*/ - uint32_t reserved_150; - uint32_t reserved_154; - uint32_t reserved_158; - uint32_t reserved_15c; - uint32_t reserved_160; - uint32_t reserved_164; - uint32_t reserved_168; - uint32_t reserved_16c; - uint32_t reserved_170; - uint32_t reserved_174; - uint32_t reserved_178; - uint32_t reserved_17c; - uint32_t reserved_180; - uint32_t reserved_184; - uint32_t reserved_188; - uint32_t reserved_18c; - uint32_t reserved_190; - uint32_t reserved_194; - uint32_t reserved_198; - uint32_t reserved_19c; - uint32_t reserved_1a0; - uint32_t reserved_1a4; - uint32_t reserved_1a8; - uint32_t reserved_1ac; - uint32_t reserved_1b0; - uint32_t reserved_1b4; - uint32_t reserved_1b8; - uint32_t reserved_1bc; - uint32_t reserved_1c0; - uint32_t reserved_1c4; - uint32_t reserved_1c8; - uint32_t reserved_1cc; - uint32_t reserved_1d0; - uint32_t reserved_1d4; - uint32_t reserved_1d8; - uint32_t reserved_1dc; - uint32_t reserved_1e0; - uint32_t reserved_1e4; - uint32_t reserved_1e8; - uint32_t reserved_1ec; - uint32_t reserved_1f0; - uint32_t reserved_1f4; - uint32_t reserved_1f8; - uint32_t reserved_1fc; - uint32_t reserved_200; - uint32_t reserved_204; - uint32_t reserved_208; - uint32_t reserved_20c; - uint32_t reserved_210; - uint32_t reserved_214; - uint32_t reserved_218; - uint32_t reserved_21c; - uint32_t reserved_220; - uint32_t reserved_224; - uint32_t reserved_228; - uint32_t reserved_22c; - uint32_t reserved_230; - uint32_t reserved_234; - uint32_t reserved_238; - uint32_t reserved_23c; - uint32_t reserved_240; - uint32_t reserved_244; - uint32_t reserved_248; - uint32_t reserved_24c; - uint32_t reserved_250; - uint32_t reserved_254; - uint32_t reserved_258; - uint32_t reserved_25c; - uint32_t reserved_260; - uint32_t reserved_264; - uint32_t reserved_268; - uint32_t reserved_26c; - uint32_t reserved_270; - uint32_t reserved_274; - uint32_t reserved_278; - uint32_t reserved_27c; - uint32_t reserved_280; - uint32_t reserved_284; - uint32_t reserved_288; - uint32_t reserved_28c; - uint32_t reserved_290; - uint32_t reserved_294; - uint32_t reserved_298; - uint32_t reserved_29c; - uint32_t reserved_2a0; - uint32_t reserved_2a4; - uint32_t reserved_2a8; - uint32_t reserved_2ac; - uint32_t reserved_2b0; - uint32_t reserved_2b4; - uint32_t reserved_2b8; - uint32_t reserved_2bc; - uint32_t reserved_2c0; - uint32_t reserved_2c4; - uint32_t reserved_2c8; - uint32_t reserved_2cc; - uint32_t reserved_2d0; - uint32_t reserved_2d4; - uint32_t reserved_2d8; - uint32_t reserved_2dc; - uint32_t reserved_2e0; - uint32_t reserved_2e4; - uint32_t reserved_2e8; - uint32_t reserved_2ec; - uint32_t reserved_2f0; - uint32_t reserved_2f4; - uint32_t reserved_2f8; - uint32_t reserved_2fc; - uint32_t reserved_300; - uint32_t reserved_304; - uint32_t reserved_308; - uint32_t reserved_30c; - uint32_t reserved_310; - uint32_t reserved_314; - uint32_t reserved_318; - uint32_t reserved_31c; - uint32_t reserved_320; - uint32_t reserved_324; - uint32_t reserved_328; - uint32_t reserved_32c; - uint32_t reserved_330; - uint32_t reserved_334; - uint32_t reserved_338; - uint32_t reserved_33c; - uint32_t reserved_340; - uint32_t reserved_344; - uint32_t reserved_348; - uint32_t reserved_34c; - uint32_t reserved_350; - uint32_t reserved_354; - uint32_t reserved_358; - uint32_t reserved_35c; - uint32_t reserved_360; - uint32_t reserved_364; - uint32_t reserved_368; - uint32_t reserved_36c; - uint32_t reserved_370; - uint32_t reserved_374; - uint32_t reserved_378; - uint32_t reserved_37c; - uint32_t reserved_380; - uint32_t reserved_384; - uint32_t reserved_388; - uint32_t reserved_38c; - uint32_t reserved_390; - uint32_t reserved_394; - uint32_t reserved_398; - uint32_t reserved_39c; - uint32_t reserved_3a0; - uint32_t reserved_3a4; - uint32_t reserved_3a8; - uint32_t reserved_3ac; - uint32_t reserved_3b0; - uint32_t reserved_3b4; - uint32_t reserved_3b8; - uint32_t reserved_3bc; - uint32_t reserved_3c0; - uint32_t reserved_3c4; - uint32_t reserved_3c8; - uint32_t reserved_3cc; - uint32_t reserved_3d0; - uint32_t reserved_3d4; - uint32_t reserved_3d8; - uint32_t reserved_3dc; - uint32_t reserved_3e0; - uint32_t reserved_3e4; - uint32_t reserved_3e8; - uint32_t reserved_3ec; - uint32_t reserved_3f0; - uint32_t reserved_3f4; - uint32_t reserved_3f8; + uint32_t reserved_150[171]; union { struct { uint32_t date: 28; /*SPI register version.*/ @@ -667,6 +497,7 @@ typedef volatile struct spi_dev_s { uint32_t val; } date; } spi_dev_t; + extern spi_dev_t SPI0; /* SPI0 IS FOR INTERNAL USE*/ extern spi_dev_t SPI1; extern spi_dev_t SPI2; diff --git a/components/soc/esp32/spi_periph.c b/components/soc/esp32/spi_periph.c index 934fcde61c99..5ff8450533cc 100644 --- a/components/soc/esp32/spi_periph.c +++ b/components/soc/esp32/spi_periph.c @@ -31,7 +31,6 @@ const spi_signal_conn_t spi_periph_signal[3] = { .spics0_iomux_pin = MSPI_IOMUX_PIN_NUM_CS0, .irq = ETS_SPI1_INTR_SOURCE, .irq_dma = ETS_SPI1_DMA_INTR_SOURCE, - .module = PERIPH_SPI_MODULE, .func = MSPI_FUNC_NUM, .hw = &SPI1 }, { @@ -55,7 +54,6 @@ const spi_signal_conn_t spi_periph_signal[3] = { .spics0_iomux_pin = HSPI_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = ETS_SPI2_DMA_INTR_SOURCE, - .module = PERIPH_HSPI_MODULE, .func = HSPI_FUNC_NUM, .hw = &SPI2 }, { @@ -79,7 +77,6 @@ const spi_signal_conn_t spi_periph_signal[3] = { .spics0_iomux_pin = VSPI_IOMUX_PIN_NUM_CS, .irq = ETS_SPI3_INTR_SOURCE, .irq_dma = ETS_SPI3_DMA_INTR_SOURCE, - .module = PERIPH_VSPI_MODULE, .func = VSPI_FUNC_NUM, .hw = &SPI3 } diff --git a/components/soc/esp32c2/spi_periph.c b/components/soc/esp32c2/spi_periph.c index 5ae7aed529fc..b270a925236d 100644 --- a/components/soc/esp32c2/spi_periph.c +++ b/components/soc/esp32c2/spi_periph.c @@ -33,7 +33,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = -1, .irq_dma = -1, - .module = -1, .hw = NULL, .func = -1, }, { @@ -57,7 +56,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, } diff --git a/components/soc/esp32c3/spi_periph.c b/components/soc/esp32c3/spi_periph.c index 5ae7aed529fc..b270a925236d 100644 --- a/components/soc/esp32c3/spi_periph.c +++ b/components/soc/esp32c3/spi_periph.c @@ -33,7 +33,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = -1, .irq_dma = -1, - .module = -1, .hw = NULL, .func = -1, }, { @@ -57,7 +56,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, } diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 9eb14ca201c5..e7456fe64701 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1023,6 +1023,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2 bool default y +config SOC_SPI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_SPI_SUPPORT_CLK_XTAL bool default y diff --git a/components/soc/esp32c5/include/soc/soc.h b/components/soc/esp32c5/include/soc/soc.h index d03396f3c68d..23fae74732fe 100644 --- a/components/soc/esp32c5/include/soc/soc.h +++ b/components/soc/esp32c5/include/soc/soc.h @@ -21,7 +21,7 @@ #define REG_I2S_BASE(i) (DR_REG_I2S_BASE) // only one I2S on C5 #define REG_TIMG_BASE(i) (DR_REG_TIMERG0_BASE + (i) * 0x1000) // TIMERG0 and TIMERG1 #define REG_SPI_MEM_BASE(i) (DR_REG_SPIMEM0_BASE + (i) * 0x1000) // SPIMEM0 and SPIMEM1 -#define REG_SPI_BASE(i) (DR_REG_GPSPI2_BASE) // only one GPSPI on C5 +#define REG_SPI_BASE(i) (DR_REG_SPI2_BASE) // only one GPSPI on C5 #define REG_I2C_BASE(i) (DR_REG_I2C_BASE) // only one I2C on C5 #define REG_MCPWM_BASE(i) (DR_REG_MCPWM_BASE) // only one MCPWM on C5 #define REG_TWAI_BASE(i) (DR_REG_TWAI0_BASE + (i) * 0x2000) // TWAI0 and TWAI1 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index f388e3191dc1..bf0f144012f8 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -424,6 +424,7 @@ #define SOC_SPI_SUPPORT_CD_SIG 1 #define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 +#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 #define SOC_SPI_SUPPORT_CLK_PLL_F160M 1 #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 diff --git a/components/soc/esp32c5/register/soc/reg_base.h b/components/soc/esp32c5/register/soc/reg_base.h index 6197746bbd7a..b2516ec71caa 100644 --- a/components/soc/esp32c5/register/soc/reg_base.h +++ b/components/soc/esp32c5/register/soc/reg_base.h @@ -40,7 +40,7 @@ * */ #define DR_REG_AHB_DMA_BASE 0x60080000 -#define DR_REG_GPSPI2_BASE 0x60081000 +#define DR_REG_SPI2_BASE 0x60081000 #define DR_REG_BITSCRAMBLER_BASE 0x60082000 #define DR_REG_KEYMNG_BASE 0x60087000 #define DR_REG_AES_BASE 0x60088000 diff --git a/components/soc/esp32c5/spi_periph.c b/components/soc/esp32c5/spi_periph.c index dc15ae60eaa1..67fa9fdcb95d 100644 --- a/components/soc/esp32c5/spi_periph.c +++ b/components/soc/esp32c5/spi_periph.c @@ -13,29 +13,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { { // MSPI has dedicated iomux pins - .spiclk_out = -1, - .spiclk_in = -1, - .spid_out = -1, - .spiq_out = -1, - .spiwp_out = -1, - .spihd_out = -1, - .spid_in = -1, - .spiq_in = -1, - .spiwp_in = -1, - .spihd_in = -1, - .spics_out = {-1}, - .spics_in = -1, - .spiclk_iomux_pin = -1, - .spid_iomux_pin = -1, - .spiq_iomux_pin = -1, - .spiwp_iomux_pin = -1, - .spihd_iomux_pin = -1, - .spics0_iomux_pin = -1, - .irq = -1, - .irq_dma = -1, - .module = -1, - .hw = NULL, - .func = -1, }, { .spiclk_out = FSPICLK_OUT_IDX, .spiclk_in = FSPICLK_IN_IDX, @@ -57,8 +34,50 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_GPSPI2_INTR_SOURCE, .irq_dma = -1, - .module = -1, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, }, }; + +/** + * Backup registers in Light sleep: (total cnt 12) + * + * cmd + * addr + * ctrl + * clock + * user + * user1 + * user2 + * ms_dlen + * misc + * dma_conf + * dma_int_ena + * slave + */ +#define SPI_RETENTION_REGS_CNT 12 +static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0}; +#define SPI_REG_RETENTION_ENTRIES(num) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \ + REG_SPI_BASE(num), REG_SPI_BASE(num), \ + SPI_RETENTION_REGS_CNT, 0, 0, \ + spi_regs_map[0], spi_regs_map[1], \ + spi_regs_map[2], spi_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + /* Additional interrupt setting is required by idf SPI drivers after register recovered */ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \ + SPI_DMA_INT_SET_REG(num), \ + SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \ + UINT32_MAX, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2 + +const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI2, + .entry_array = spi2_regs_retention, + .array_size = ARRAY_SIZE(spi2_regs_retention), + }, +}; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 4ef221be683d..84c3cd72b308 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1007,6 +1007,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2 bool default y +config SOC_SPI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_SPI_SUPPORT_CLK_XTAL bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 9ca435674b92..948c1cd0f682 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -399,6 +399,7 @@ #define SOC_SPI_SUPPORT_CD_SIG 1 #define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 +#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 #define SOC_SPI_SUPPORT_CLK_PLL_F80M 1 #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 diff --git a/components/soc/esp32c6/spi_periph.c b/components/soc/esp32c6/spi_periph.c index ea10937f582a..1a3696a27fd7 100644 --- a/components/soc/esp32c6/spi_periph.c +++ b/components/soc/esp32c6/spi_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,29 +13,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { { // MSPI has dedicated iomux pins - .spiclk_out = -1, - .spiclk_in = -1, - .spid_out = -1, - .spiq_out = -1, - .spiwp_out = -1, - .spihd_out = -1, - .spid_in = -1, - .spiq_in = -1, - .spiwp_in = -1, - .spihd_in = -1, - .spics_out = {-1}, - .spics_in = -1, - .spiclk_iomux_pin = -1, - .spid_iomux_pin = -1, - .spiq_iomux_pin = -1, - .spiwp_iomux_pin = -1, - .spihd_iomux_pin = -1, - .spics0_iomux_pin = -1, - .irq = -1, - .irq_dma = -1, - .module = -1, - .hw = NULL, - .func = -1, }, { .spiclk_out = FSPICLK_OUT_IDX, .spiclk_in = FSPICLK_IN_IDX, @@ -57,8 +34,51 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_GSPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, } }; + + +/** + * Backup registers in Light sleep: (total cnt 12) + * + * cmd + * addr + * ctrl + * clock + * user + * user1 + * user2 + * ms_dlen + * misc + * dma_conf + * dma_int_ena + * slave + */ +#define SPI_RETENTION_REGS_CNT 12 +static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0}; +#define SPI_REG_RETENTION_ENTRIES(num) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \ + REG_SPI_BASE(num), REG_SPI_BASE(num), \ + SPI_RETENTION_REGS_CNT, 0, 0, \ + spi_regs_map[0], spi_regs_map[1], \ + spi_regs_map[2], spi_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + /* Additional interrupt setting is required by idf SPI drivers after register recovered */ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \ + SPI_DMA_INT_SET_REG(num), \ + SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \ + UINT32_MAX, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2 + +const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI2, + .entry_array = spi2_regs_retention, + .array_size = ARRAY_SIZE(spi2_regs_retention), + }, +}; diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index f92804a99de9..719e9d777a30 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -583,6 +583,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2 bool default y +config SOC_SPI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_SPI_SUPPORT_CLK_XTAL bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 6d61c1a6e126..c17762e1236c 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -307,6 +307,7 @@ #define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 +#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 #define SOC_SPI_SUPPORT_CLK_PLL 1 #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 diff --git a/components/soc/esp32c61/register/soc/reg_base.h b/components/soc/esp32c61/register/soc/reg_base.h index e092f8726b69..e52fc35286ca 100644 --- a/components/soc/esp32c61/register/soc/reg_base.h +++ b/components/soc/esp32c61/register/soc/reg_base.h @@ -24,7 +24,7 @@ #define DR_REG_PVT_MONITOR_BASE 0x60019000 #define DR_REG_PSRAM_MEM_MONITOR_BASE 0x6001A000 #define DR_REG_AHB_DMA_BASE 0x60080000 -#define DR_REG_GPSPI_BASE 0x60081000 +#define DR_REG_SPI2_BASE 0x60081000 #define DR_REG_SHA_BASE 0x60089000 #define DR_REG_ECC_MULT_BASE 0x6008B000 #define DR_REG_ECDSA_BASE 0x6008E000 diff --git a/components/soc/esp32c61/register/soc/spi_reg.h b/components/soc/esp32c61/register/soc/spi_reg.h index a0e934fcc242..cce0834349ab 100644 --- a/components/soc/esp32c61/register/soc/spi_reg.h +++ b/components/soc/esp32c61/register/soc/spi_reg.h @@ -14,7 +14,7 @@ extern "C" { /** SPI_CMD_REG register * Command control register */ -#define SPI_CMD_REG (DR_REG_SPI_BASE + 0x0) +#define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0) /** SPI_CONF_BITLEN : R/W; bitpos: [17:0]; default: 0; * Configures the SPI_CLK cycles of SPI CONF state. * Measurement unit: SPI_CLK clock cycle.\\ @@ -50,7 +50,7 @@ extern "C" { /** SPI_ADDR_REG register * Address value register */ -#define SPI_ADDR_REG (DR_REG_SPI_BASE + 0x4) +#define SPI_ADDR_REG(i) (REG_SPI_BASE(i) + 0x4) /** SPI_USR_ADDR_VALUE : R/W; bitpos: [31:0]; default: 0; * Configures the address to slave. * Can be configured in CONF state. @@ -63,7 +63,7 @@ extern "C" { /** SPI_CTRL_REG register * SPI control register */ -#define SPI_CTRL_REG (DR_REG_SPI_BASE + 0x8) +#define SPI_CTRL_REG(i) (REG_SPI_BASE(i) + 0x8) /** SPI_DUMMY_OUT : R/W; bitpos: [3]; default: 0; * Configures whether or not to output the FSPI bus signals in DUMMY state. \\ * 0: Not output \\ @@ -232,7 +232,7 @@ extern "C" { /** SPI_CLOCK_REG register * SPI clock control register */ -#define SPI_CLOCK_REG (DR_REG_SPI_BASE + 0xc) +#define SPI_CLOCK_REG(i) (REG_SPI_BASE(i) + 0xc) /** SPI_CLKCNT_L : R/W; bitpos: [5:0]; default: 3; * In master transfer, this field must be equal to SPI_CLKCNT_N. In slave mode, it * must be 0. Can be configured in CONF state. @@ -284,7 +284,7 @@ extern "C" { /** SPI_USER_REG register * SPI USER control register */ -#define SPI_USER_REG (DR_REG_SPI_BASE + 0x10) +#define SPI_USER_REG(i) (REG_SPI_BASE(i) + 0x10) /** SPI_DOUTDIN : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable full-duplex communication. \\ * 0: Disable \\ @@ -501,7 +501,7 @@ extern "C" { /** SPI_USER1_REG register * SPI USER control register 1 */ -#define SPI_USER1_REG (DR_REG_SPI_BASE + 0x14) +#define SPI_USER1_REG(i) (REG_SPI_BASE(i) + 0x14) /** SPI_USR_DUMMY_CYCLELEN : R/W; bitpos: [7:0]; default: 7; * Configures the length of DUMMY state. * Measurement unit: SPI_CLK clock cycles.\\ @@ -552,7 +552,7 @@ extern "C" { /** SPI_USER2_REG register * SPI USER control register 2 */ -#define SPI_USER2_REG (DR_REG_SPI_BASE + 0x18) +#define SPI_USER2_REG(i) (REG_SPI_BASE(i) + 0x18) /** SPI_USR_COMMAND_VALUE : R/W; bitpos: [15:0]; default: 0; * Configures the command value. * Can be configured in CONF state. @@ -583,7 +583,7 @@ extern "C" { /** SPI_MS_DLEN_REG register * SPI data bit length control register */ -#define SPI_MS_DLEN_REG (DR_REG_SPI_BASE + 0x1c) +#define SPI_MS_DLEN_REG(i) (REG_SPI_BASE(i) + 0x1c) /** SPI_MS_DATA_BITLEN : R/W; bitpos: [17:0]; default: 0; * Configures the data bit length of SPI transfer in DMA-controlled master transfer or * in CPU-controlled master transfer. Or configures the bit length of SPI RX transfer @@ -598,7 +598,7 @@ extern "C" { /** SPI_MISC_REG register * SPI misc register */ -#define SPI_MISC_REG (DR_REG_SPI_BASE + 0x20) +#define SPI_MISC_REG(i) (REG_SPI_BASE(i) + 0x20) /** SPI_CS0_DIS : R/W; bitpos: [0]; default: 0; * Configures whether or not to disable SPI_CS$n pin.\\ * 0: SPI_CS$n signal is from/to SPI_CS$n pin.\\ @@ -763,7 +763,7 @@ extern "C" { /** SPI_DIN_MODE_REG register * SPI input delay mode configuration */ -#define SPI_DIN_MODE_REG (DR_REG_SPI_BASE + 0x24) +#define SPI_DIN_MODE_REG(i) (REG_SPI_BASE(i) + 0x24) /** SPI_DIN0_MODE : R/W; bitpos: [1:0]; default: 0; * Configures the input mode for FSPID signal.\\ * 0: Input without delay\\ @@ -872,7 +872,7 @@ extern "C" { /** SPI_DIN_NUM_REG register * SPI input delay number configuration */ -#define SPI_DIN_NUM_REG (DR_REG_SPI_BASE + 0x28) +#define SPI_DIN_NUM_REG(i) (REG_SPI_BASE(i) + 0x28) /** SPI_DIN0_NUM : R/W; bitpos: [1:0]; default: 0; * Configures the delays to input signal FSPID based on the setting of SPI_DIN0_MODE.\\ * 0: Delayed by 1 clock cycle\\ @@ -959,7 +959,7 @@ extern "C" { /** SPI_DOUT_MODE_REG register * SPI output delay mode configuration */ -#define SPI_DOUT_MODE_REG (DR_REG_SPI_BASE + 0x2c) +#define SPI_DOUT_MODE_REG(i) (REG_SPI_BASE(i) + 0x2c) /** SPI_DOUT0_MODE : R/W; bitpos: [0]; default: 0; * Configures the output mode for FSPID signal.\\ * 0: Output without delay\\ @@ -1049,7 +1049,7 @@ extern "C" { /** SPI_DMA_CONF_REG register * SPI DMA control register */ -#define SPI_DMA_CONF_REG (DR_REG_SPI_BASE + 0x30) +#define SPI_DMA_CONF_REG(i) (REG_SPI_BASE(i) + 0x30) /** SPI_DMA_OUTFIFO_EMPTY : RO; bitpos: [0]; default: 1; * Represents whether or not the DMA TX FIFO is ready for sending data.\\ * 0: Ready\\ @@ -1177,7 +1177,7 @@ extern "C" { /** SPI_DMA_INT_ENA_REG register * SPI interrupt enable register */ -#define SPI_DMA_INT_ENA_REG (DR_REG_SPI_BASE + 0x34) +#define SPI_DMA_INT_ENA_REG(i) (REG_SPI_BASE(i) + 0x34) /** SPI_DMA_INFIFO_FULL_ERR_INT_ENA : R/W; bitpos: [0]; default: 0; * Write 1 to enable SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1329,7 +1329,7 @@ extern "C" { /** SPI_DMA_INT_CLR_REG register * SPI interrupt clear register */ -#define SPI_DMA_INT_CLR_REG (DR_REG_SPI_BASE + 0x38) +#define SPI_DMA_INT_CLR_REG(i) (REG_SPI_BASE(i) + 0x38) /** SPI_DMA_INFIFO_FULL_ERR_INT_CLR : WT; bitpos: [0]; default: 0; * Write 1 to clear SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1481,7 +1481,7 @@ extern "C" { /** SPI_DMA_INT_RAW_REG register * SPI interrupt raw register */ -#define SPI_DMA_INT_RAW_REG (DR_REG_SPI_BASE + 0x3c) +#define SPI_DMA_INT_RAW_REG(i) (REG_SPI_BASE(i) + 0x3c) /** SPI_DMA_INFIFO_FULL_ERR_INT_RAW : R/WTC/SS; bitpos: [0]; default: 0; * The raw interrupt status of SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1637,7 +1637,7 @@ extern "C" { /** SPI_DMA_INT_ST_REG register * SPI interrupt status register */ -#define SPI_DMA_INT_ST_REG (DR_REG_SPI_BASE + 0x40) +#define SPI_DMA_INT_ST_REG(i) (REG_SPI_BASE(i) + 0x40) /** SPI_DMA_INFIFO_FULL_ERR_INT_ST : RO; bitpos: [0]; default: 0; * The interrupt status of SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1789,7 +1789,7 @@ extern "C" { /** SPI_DMA_INT_SET_REG register * SPI interrupt software set register */ -#define SPI_DMA_INT_SET_REG (DR_REG_SPI_BASE + 0x44) +#define SPI_DMA_INT_SET_REG(i) (REG_SPI_BASE(i) + 0x44) /** SPI_DMA_INFIFO_FULL_ERR_INT_SET : WT; bitpos: [0]; default: 0; * Write 1 to set SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1941,7 +1941,7 @@ extern "C" { /** SPI_W0_REG register * SPI CPU-controlled buffer0 */ -#define SPI_W0_REG (DR_REG_SPI_BASE + 0x98) +#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x98) /** SPI_BUF0 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -1953,7 +1953,7 @@ extern "C" { /** SPI_W1_REG register * SPI CPU-controlled buffer1 */ -#define SPI_W1_REG (DR_REG_SPI_BASE + 0x9c) +#define SPI_W1_REG(i) (REG_SPI_BASE(i) + 0x9c) /** SPI_BUF1 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -1965,7 +1965,7 @@ extern "C" { /** SPI_W2_REG register * SPI CPU-controlled buffer2 */ -#define SPI_W2_REG (DR_REG_SPI_BASE + 0xa0) +#define SPI_W2_REG(i) (REG_SPI_BASE(i) + 0xa0) /** SPI_BUF2 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -1977,7 +1977,7 @@ extern "C" { /** SPI_W3_REG register * SPI CPU-controlled buffer3 */ -#define SPI_W3_REG (DR_REG_SPI_BASE + 0xa4) +#define SPI_W3_REG(i) (REG_SPI_BASE(i) + 0xa4) /** SPI_BUF3 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -1989,7 +1989,7 @@ extern "C" { /** SPI_W4_REG register * SPI CPU-controlled buffer4 */ -#define SPI_W4_REG (DR_REG_SPI_BASE + 0xa8) +#define SPI_W4_REG(i) (REG_SPI_BASE(i) + 0xa8) /** SPI_BUF4 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2001,7 +2001,7 @@ extern "C" { /** SPI_W5_REG register * SPI CPU-controlled buffer5 */ -#define SPI_W5_REG (DR_REG_SPI_BASE + 0xac) +#define SPI_W5_REG(i) (REG_SPI_BASE(i) + 0xac) /** SPI_BUF5 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2013,7 +2013,7 @@ extern "C" { /** SPI_W6_REG register * SPI CPU-controlled buffer6 */ -#define SPI_W6_REG (DR_REG_SPI_BASE + 0xb0) +#define SPI_W6_REG(i) (REG_SPI_BASE(i) + 0xb0) /** SPI_BUF6 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2025,7 +2025,7 @@ extern "C" { /** SPI_W7_REG register * SPI CPU-controlled buffer7 */ -#define SPI_W7_REG (DR_REG_SPI_BASE + 0xb4) +#define SPI_W7_REG(i) (REG_SPI_BASE(i) + 0xb4) /** SPI_BUF7 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2037,7 +2037,7 @@ extern "C" { /** SPI_W8_REG register * SPI CPU-controlled buffer8 */ -#define SPI_W8_REG (DR_REG_SPI_BASE + 0xb8) +#define SPI_W8_REG(i) (REG_SPI_BASE(i) + 0xb8) /** SPI_BUF8 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2049,7 +2049,7 @@ extern "C" { /** SPI_W9_REG register * SPI CPU-controlled buffer9 */ -#define SPI_W9_REG (DR_REG_SPI_BASE + 0xbc) +#define SPI_W9_REG(i) (REG_SPI_BASE(i) + 0xbc) /** SPI_BUF9 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2061,7 +2061,7 @@ extern "C" { /** SPI_W10_REG register * SPI CPU-controlled buffer10 */ -#define SPI_W10_REG (DR_REG_SPI_BASE + 0xc0) +#define SPI_W10_REG(i) (REG_SPI_BASE(i) + 0xc0) /** SPI_BUF10 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2073,7 +2073,7 @@ extern "C" { /** SPI_W11_REG register * SPI CPU-controlled buffer11 */ -#define SPI_W11_REG (DR_REG_SPI_BASE + 0xc4) +#define SPI_W11_REG(i) (REG_SPI_BASE(i) + 0xc4) /** SPI_BUF11 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2085,7 +2085,7 @@ extern "C" { /** SPI_W12_REG register * SPI CPU-controlled buffer12 */ -#define SPI_W12_REG (DR_REG_SPI_BASE + 0xc8) +#define SPI_W12_REG(i) (REG_SPI_BASE(i) + 0xc8) /** SPI_BUF12 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2097,7 +2097,7 @@ extern "C" { /** SPI_W13_REG register * SPI CPU-controlled buffer13 */ -#define SPI_W13_REG (DR_REG_SPI_BASE + 0xcc) +#define SPI_W13_REG(i) (REG_SPI_BASE(i) + 0xcc) /** SPI_BUF13 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2109,7 +2109,7 @@ extern "C" { /** SPI_W14_REG register * SPI CPU-controlled buffer14 */ -#define SPI_W14_REG (DR_REG_SPI_BASE + 0xd0) +#define SPI_W14_REG(i) (REG_SPI_BASE(i) + 0xd0) /** SPI_BUF14 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2121,7 +2121,7 @@ extern "C" { /** SPI_W15_REG register * SPI CPU-controlled buffer15 */ -#define SPI_W15_REG (DR_REG_SPI_BASE + 0xd4) +#define SPI_W15_REG(i) (REG_SPI_BASE(i) + 0xd4) /** SPI_BUF15 : R/W/SS; bitpos: [31:0]; default: 0; * 32-bit data buffer $n. */ @@ -2133,7 +2133,7 @@ extern "C" { /** SPI_SLAVE_REG register * SPI slave control register */ -#define SPI_SLAVE_REG (DR_REG_SPI_BASE + 0xe0) +#define SPI_SLAVE_REG(i) (REG_SPI_BASE(i) + 0xe0) /** SPI_CLK_MODE : R/W; bitpos: [1:0]; default: 0; * Configures SPI clock mode.\\ * 0: SPI clock is off when CS becomes inactive.\\ @@ -2267,7 +2267,7 @@ extern "C" { /** SPI_SLAVE1_REG register * SPI slave control register 1 */ -#define SPI_SLAVE1_REG (DR_REG_SPI_BASE + 0xe4) +#define SPI_SLAVE1_REG(i) (REG_SPI_BASE(i) + 0xe4) /** SPI_SLV_DATA_BITLEN : R/W/SS; bitpos: [17:0]; default: 0; * Configures the transferred data bit length in SPI slave full-/half-duplex modes. */ @@ -2293,7 +2293,7 @@ extern "C" { /** SPI_CLK_GATE_REG register * SPI module clock and register clock control */ -#define SPI_CLK_GATE_REG (DR_REG_SPI_BASE + 0xe8) +#define SPI_CLK_GATE_REG(i) (REG_SPI_BASE(i) + 0xe8) /** SPI_CLK_EN : R/W; bitpos: [0]; default: 0; * Configures whether or not to enable clock gate.\\ * 0: Disable\\ @@ -2322,7 +2322,7 @@ extern "C" { /** SPI_DATE_REG register * Version control */ -#define SPI_DATE_REG (DR_REG_SPI_BASE + 0xf0) +#define SPI_DATE_REG(i) (REG_SPI_BASE(i) + 0xf0) /** SPI_DATE : R/W; bitpos: [27:0]; default: 36716931; * Version control register. */ diff --git a/components/soc/esp32c61/spi_periph.c b/components/soc/esp32c61/spi_periph.c index dc15ae60eaa1..67fa9fdcb95d 100644 --- a/components/soc/esp32c61/spi_periph.c +++ b/components/soc/esp32c61/spi_periph.c @@ -13,29 +13,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { { // MSPI has dedicated iomux pins - .spiclk_out = -1, - .spiclk_in = -1, - .spid_out = -1, - .spiq_out = -1, - .spiwp_out = -1, - .spihd_out = -1, - .spid_in = -1, - .spiq_in = -1, - .spiwp_in = -1, - .spihd_in = -1, - .spics_out = {-1}, - .spics_in = -1, - .spiclk_iomux_pin = -1, - .spid_iomux_pin = -1, - .spiq_iomux_pin = -1, - .spiwp_iomux_pin = -1, - .spihd_iomux_pin = -1, - .spics0_iomux_pin = -1, - .irq = -1, - .irq_dma = -1, - .module = -1, - .hw = NULL, - .func = -1, }, { .spiclk_out = FSPICLK_OUT_IDX, .spiclk_in = FSPICLK_IN_IDX, @@ -57,8 +34,50 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_GPSPI2_INTR_SOURCE, .irq_dma = -1, - .module = -1, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, }, }; + +/** + * Backup registers in Light sleep: (total cnt 12) + * + * cmd + * addr + * ctrl + * clock + * user + * user1 + * user2 + * ms_dlen + * misc + * dma_conf + * dma_int_ena + * slave + */ +#define SPI_RETENTION_REGS_CNT 12 +static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0}; +#define SPI_REG_RETENTION_ENTRIES(num) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \ + REG_SPI_BASE(num), REG_SPI_BASE(num), \ + SPI_RETENTION_REGS_CNT, 0, 0, \ + spi_regs_map[0], spi_regs_map[1], \ + spi_regs_map[2], spi_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + /* Additional interrupt setting is required by idf SPI drivers after register recovered */ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \ + SPI_DMA_INT_SET_REG(num), \ + SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \ + UINT32_MAX, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2 + +const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI2, + .entry_array = spi2_regs_retention, + .array_size = ARRAY_SIZE(spi2_regs_retention), + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 61475b1c57bd..72bfb1fa09c4 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1003,6 +1003,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2 bool default y +config SOC_SPI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_SPI_SUPPORT_CLK_XTAL bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 42682fe7455d..416f1106827a 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -395,6 +395,7 @@ #define SOC_SPI_SUPPORT_CD_SIG 1 #define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 +#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 #define SOC_SPI_SUPPORT_CLK_PLL_F48M 1 #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 diff --git a/components/soc/esp32h2/register/soc/spi_reg.h b/components/soc/esp32h2/register/soc/spi_reg.h index 44c7cf23dffe..d1326cea82a0 100644 --- a/components/soc/esp32h2/register/soc/spi_reg.h +++ b/components/soc/esp32h2/register/soc/spi_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ extern "C" { /** SPI_CMD_REG register * Command control register */ -#define SPI_CMD_REG (DR_REG_SPI_BASE + 0x0) +#define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0) /** SPI_CONF_BITLEN : R/W; bitpos: [17:0]; default: 0; * Define the APB cycles of SPI_CONF state. Can be configured in CONF state. */ @@ -43,7 +43,7 @@ extern "C" { /** SPI_ADDR_REG register * Address value register */ -#define SPI_ADDR_REG (DR_REG_SPI_BASE + 0x4) +#define SPI_ADDR_REG(i) (REG_SPI_BASE(i) + 0x4) /** SPI_USR_ADDR_VALUE : R/W; bitpos: [31:0]; default: 0; * Address to slave. Can be configured in CONF state. */ @@ -55,7 +55,7 @@ extern "C" { /** SPI_CTRL_REG register * SPI control register */ -#define SPI_CTRL_REG (DR_REG_SPI_BASE + 0x8) +#define SPI_CTRL_REG(i) (REG_SPI_BASE(i) + 0x8) /** SPI_DUMMY_OUT : R/W; bitpos: [3]; default: 0; * 0: In the dummy phase, the FSPI bus signals are not output. 1: In the dummy phase, * the FSPI bus signals are output. Can be configured in CONF state. @@ -188,7 +188,7 @@ extern "C" { /** SPI_CLOCK_REG register * SPI clock control register */ -#define SPI_CLOCK_REG (DR_REG_SPI_BASE + 0xc) +#define SPI_CLOCK_REG(i) (REG_SPI_BASE(i) + 0xc) /** SPI_CLKCNT_L : R/W; bitpos: [5:0]; default: 3; * In the master mode it must be equal to spi_clkcnt_N. In the slave mode it must be * 0. Can be configured in CONF state. @@ -232,7 +232,7 @@ extern "C" { /** SPI_USER_REG register * SPI USER control register */ -#define SPI_USER_REG (DR_REG_SPI_BASE + 0x10) +#define SPI_USER_REG(i) (REG_SPI_BASE(i) + 0x10) /** SPI_DOUTDIN : R/W; bitpos: [0]; default: 0; * Set the bit to enable full duplex communication. 1: enable 0: disable. Can be * configured in CONF state. @@ -403,7 +403,7 @@ extern "C" { /** SPI_USER1_REG register * SPI USER control register 1 */ -#define SPI_USER1_REG (DR_REG_SPI_BASE + 0x14) +#define SPI_USER1_REG(i) (REG_SPI_BASE(i) + 0x14) /** SPI_USR_DUMMY_CYCLELEN : R/W; bitpos: [7:0]; default: 7; * The length in spi_clk cycles of dummy phase. The register value shall be * (cycle_num-1). Can be configured in CONF state. @@ -449,7 +449,7 @@ extern "C" { /** SPI_USER2_REG register * SPI USER control register 2 */ -#define SPI_USER2_REG (DR_REG_SPI_BASE + 0x18) +#define SPI_USER2_REG(i) (REG_SPI_BASE(i) + 0x18) /** SPI_USR_COMMAND_VALUE : R/W; bitpos: [15:0]; default: 0; * The value of command. Can be configured in CONF state. */ @@ -478,7 +478,7 @@ extern "C" { /** SPI_MS_DLEN_REG register * SPI data bit length control register */ -#define SPI_MS_DLEN_REG (DR_REG_SPI_BASE + 0x1c) +#define SPI_MS_DLEN_REG(i) (REG_SPI_BASE(i) + 0x1c) /** SPI_MS_DATA_BITLEN : R/W; bitpos: [17:0]; default: 0; * The value of these bits is the configured SPI transmission data bit length in * master mode DMA controlled transfer or CPU controlled transfer. The value is also @@ -493,7 +493,7 @@ extern "C" { /** SPI_MISC_REG register * SPI misc register */ -#define SPI_MISC_REG (DR_REG_SPI_BASE + 0x20) +#define SPI_MISC_REG(i) (REG_SPI_BASE(i) + 0x20) /** SPI_CS0_DIS : R/W; bitpos: [0]; default: 0; * SPI CS$n pin enable, 1: disable CS$n, 0: spi_cs$n signal is from/to CS$n pin. Can * be configured in CONF state. @@ -634,7 +634,7 @@ extern "C" { /** SPI_DIN_MODE_REG register * SPI input delay mode configuration */ -#define SPI_DIN_MODE_REG (DR_REG_SPI_BASE + 0x24) +#define SPI_DIN_MODE_REG(i) (REG_SPI_BASE(i) + 0x24) /** SPI_DIN0_MODE : R/W; bitpos: [1:0]; default: 0; * the input signals are delayed by SPI module clock cycles, 0: input without delayed, * 1: input with the posedge of clk_apb,2 input with the negedge of clk_apb, 3: input @@ -725,7 +725,7 @@ extern "C" { /** SPI_DIN_NUM_REG register * SPI input delay number configuration */ -#define SPI_DIN_NUM_REG (DR_REG_SPI_BASE + 0x28) +#define SPI_DIN_NUM_REG(i) (REG_SPI_BASE(i) + 0x28) /** SPI_DIN0_NUM : R/W; bitpos: [1:0]; default: 0; * the input signals are delayed by SPI module clock cycles, 0: delayed by 1 cycle, 1: * delayed by 2 cycles,... Can be configured in CONF state. @@ -794,7 +794,7 @@ extern "C" { /** SPI_DOUT_MODE_REG register * SPI output delay mode configuration */ -#define SPI_DOUT_MODE_REG (DR_REG_SPI_BASE + 0x2c) +#define SPI_DOUT_MODE_REG(i) (REG_SPI_BASE(i) + 0x2c) /** SPI_DOUT0_MODE : R/W; bitpos: [0]; default: 0; * The output signal $n is delayed by the SPI module clock, 0: output without delayed, * 1: output delay for a SPI module clock cycle at its negative edge. Can be @@ -880,7 +880,7 @@ extern "C" { /** SPI_DMA_CONF_REG register * SPI DMA control register */ -#define SPI_DMA_CONF_REG (DR_REG_SPI_BASE + 0x30) +#define SPI_DMA_CONF_REG(i) (REG_SPI_BASE(i) + 0x30) /** SPI_DMA_OUTFIFO_EMPTY : RO; bitpos: [0]; default: 1; * Records the status of DMA TX FIFO. 1: DMA TX FIFO is not ready for sending data. 0: * DMA TX FIFO is ready for sending data. @@ -972,7 +972,7 @@ extern "C" { /** SPI_DMA_INT_ENA_REG register * SPI interrupt enable register */ -#define SPI_DMA_INT_ENA_REG (DR_REG_SPI_BASE + 0x34) +#define SPI_DMA_INT_ENA_REG(i) (REG_SPI_BASE(i) + 0x34) /** SPI_DMA_INFIFO_FULL_ERR_INT_ENA : R/W; bitpos: [0]; default: 0; * The enable bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1124,7 +1124,7 @@ extern "C" { /** SPI_DMA_INT_CLR_REG register * SPI interrupt clear register */ -#define SPI_DMA_INT_CLR_REG (DR_REG_SPI_BASE + 0x38) +#define SPI_DMA_INT_CLR_REG(i) (REG_SPI_BASE(i) + 0x38) /** SPI_DMA_INFIFO_FULL_ERR_INT_CLR : WT; bitpos: [0]; default: 0; * The clear bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1276,7 +1276,7 @@ extern "C" { /** SPI_DMA_INT_RAW_REG register * SPI interrupt raw register */ -#define SPI_DMA_INT_RAW_REG (DR_REG_SPI_BASE + 0x3c) +#define SPI_DMA_INT_RAW_REG(i) (REG_SPI_BASE(i) + 0x3c) /** SPI_DMA_INFIFO_FULL_ERR_INT_RAW : R/WTC/SS; bitpos: [0]; default: 0; * 1: The current data rate of DMA Rx is smaller than that of SPI, which will lose the * receive data. 0: Others. @@ -1450,7 +1450,7 @@ extern "C" { /** SPI_DMA_INT_ST_REG register * SPI interrupt status register */ -#define SPI_DMA_INT_ST_REG (DR_REG_SPI_BASE + 0x40) +#define SPI_DMA_INT_ST_REG(i) (REG_SPI_BASE(i) + 0x40) /** SPI_DMA_INFIFO_FULL_ERR_INT_ST : RO; bitpos: [0]; default: 0; * The status bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1602,7 +1602,7 @@ extern "C" { /** SPI_DMA_INT_SET_REG register * SPI interrupt software set register */ -#define SPI_DMA_INT_SET_REG (DR_REG_SPI_BASE + 0x44) +#define SPI_DMA_INT_SET_REG(i) (REG_SPI_BASE(i) + 0x44) /** SPI_DMA_INFIFO_FULL_ERR_INT_SET : WT; bitpos: [0]; default: 0; * The software set bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. */ @@ -1754,7 +1754,7 @@ extern "C" { /** SPI_W0_REG register * SPI CPU-controlled buffer0 */ -#define SPI_W0_REG (DR_REG_SPI_BASE + 0x98) +#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x98) /** SPI_BUF0 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1766,7 +1766,7 @@ extern "C" { /** SPI_W1_REG register * SPI CPU-controlled buffer1 */ -#define SPI_W1_REG (DR_REG_SPI_BASE + 0x9c) +#define SPI_W1_REG(i) (REG_SPI_BASE(i) + 0x9c) /** SPI_BUF1 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1778,7 +1778,7 @@ extern "C" { /** SPI_W2_REG register * SPI CPU-controlled buffer2 */ -#define SPI_W2_REG (DR_REG_SPI_BASE + 0xa0) +#define SPI_W2_REG(i) (REG_SPI_BASE(i) + 0xa0) /** SPI_BUF2 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1790,7 +1790,7 @@ extern "C" { /** SPI_W3_REG register * SPI CPU-controlled buffer3 */ -#define SPI_W3_REG (DR_REG_SPI_BASE + 0xa4) +#define SPI_W3_REG(i) (REG_SPI_BASE(i) + 0xa4) /** SPI_BUF3 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1802,7 +1802,7 @@ extern "C" { /** SPI_W4_REG register * SPI CPU-controlled buffer4 */ -#define SPI_W4_REG (DR_REG_SPI_BASE + 0xa8) +#define SPI_W4_REG(i) (REG_SPI_BASE(i) + 0xa8) /** SPI_BUF4 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1814,7 +1814,7 @@ extern "C" { /** SPI_W5_REG register * SPI CPU-controlled buffer5 */ -#define SPI_W5_REG (DR_REG_SPI_BASE + 0xac) +#define SPI_W5_REG(i) (REG_SPI_BASE(i) + 0xac) /** SPI_BUF5 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1826,7 +1826,7 @@ extern "C" { /** SPI_W6_REG register * SPI CPU-controlled buffer6 */ -#define SPI_W6_REG (DR_REG_SPI_BASE + 0xb0) +#define SPI_W6_REG(i) (REG_SPI_BASE(i) + 0xb0) /** SPI_BUF6 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1838,7 +1838,7 @@ extern "C" { /** SPI_W7_REG register * SPI CPU-controlled buffer7 */ -#define SPI_W7_REG (DR_REG_SPI_BASE + 0xb4) +#define SPI_W7_REG(i) (REG_SPI_BASE(i) + 0xb4) /** SPI_BUF7 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1850,7 +1850,7 @@ extern "C" { /** SPI_W8_REG register * SPI CPU-controlled buffer8 */ -#define SPI_W8_REG (DR_REG_SPI_BASE + 0xb8) +#define SPI_W8_REG(i) (REG_SPI_BASE(i) + 0xb8) /** SPI_BUF8 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1862,7 +1862,7 @@ extern "C" { /** SPI_W9_REG register * SPI CPU-controlled buffer9 */ -#define SPI_W9_REG (DR_REG_SPI_BASE + 0xbc) +#define SPI_W9_REG(i) (REG_SPI_BASE(i) + 0xbc) /** SPI_BUF9 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1874,7 +1874,7 @@ extern "C" { /** SPI_W10_REG register * SPI CPU-controlled buffer10 */ -#define SPI_W10_REG (DR_REG_SPI_BASE + 0xc0) +#define SPI_W10_REG(i) (REG_SPI_BASE(i) + 0xc0) /** SPI_BUF10 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1886,7 +1886,7 @@ extern "C" { /** SPI_W11_REG register * SPI CPU-controlled buffer11 */ -#define SPI_W11_REG (DR_REG_SPI_BASE + 0xc4) +#define SPI_W11_REG(i) (REG_SPI_BASE(i) + 0xc4) /** SPI_BUF11 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1898,7 +1898,7 @@ extern "C" { /** SPI_W12_REG register * SPI CPU-controlled buffer12 */ -#define SPI_W12_REG (DR_REG_SPI_BASE + 0xc8) +#define SPI_W12_REG(i) (REG_SPI_BASE(i) + 0xc8) /** SPI_BUF12 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1910,7 +1910,7 @@ extern "C" { /** SPI_W13_REG register * SPI CPU-controlled buffer13 */ -#define SPI_W13_REG (DR_REG_SPI_BASE + 0xcc) +#define SPI_W13_REG(i) (REG_SPI_BASE(i) + 0xcc) /** SPI_BUF13 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1922,7 +1922,7 @@ extern "C" { /** SPI_W14_REG register * SPI CPU-controlled buffer14 */ -#define SPI_W14_REG (DR_REG_SPI_BASE + 0xd0) +#define SPI_W14_REG(i) (REG_SPI_BASE(i) + 0xd0) /** SPI_BUF14 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1934,7 +1934,7 @@ extern "C" { /** SPI_W15_REG register * SPI CPU-controlled buffer15 */ -#define SPI_W15_REG (DR_REG_SPI_BASE + 0xd4) +#define SPI_W15_REG(i) (REG_SPI_BASE(i) + 0xd4) /** SPI_BUF15 : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ @@ -1946,7 +1946,7 @@ extern "C" { /** SPI_SLAVE_REG register * SPI slave control register */ -#define SPI_SLAVE_REG (DR_REG_SPI_BASE + 0xe0) +#define SPI_SLAVE_REG(i) (REG_SPI_BASE(i) + 0xe0) /** SPI_CLK_MODE : R/W; bitpos: [1:0]; default: 0; * SPI clock mode bits. 0: SPI clock is off when CS inactive 1: SPI clock is delayed * one cycle after CS inactive 2: SPI clock is delayed two cycles after CS inactive 3: @@ -2047,7 +2047,7 @@ extern "C" { /** SPI_SLAVE1_REG register * SPI slave control register 1 */ -#define SPI_SLAVE1_REG (DR_REG_SPI_BASE + 0xe4) +#define SPI_SLAVE1_REG(i) (REG_SPI_BASE(i) + 0xe4) /** SPI_SLV_DATA_BITLEN : R/W/SS; bitpos: [17:0]; default: 0; * The transferred data bit length in SPI slave FD and HD mode. */ @@ -2073,7 +2073,7 @@ extern "C" { /** SPI_CLK_GATE_REG register * SPI module clock and register clock control */ -#define SPI_CLK_GATE_REG (DR_REG_SPI_BASE + 0xe8) +#define SPI_CLK_GATE_REG(i) (REG_SPI_BASE(i) + 0xe8) /** SPI_CLK_EN : R/W; bitpos: [0]; default: 0; * Set this bit to enable clk gate */ @@ -2100,7 +2100,7 @@ extern "C" { /** SPI_DATE_REG register * Version control */ -#define SPI_DATE_REG (DR_REG_SPI_BASE + 0xf0) +#define SPI_DATE_REG(i) (REG_SPI_BASE(i) + 0xf0) /** SPI_DATE : R/W; bitpos: [27:0]; default: 35656448; * SPI register version. */ diff --git a/components/soc/esp32h2/spi_periph.c b/components/soc/esp32h2/spi_periph.c index 213bed6def4c..1ac5f7e40cb4 100644 --- a/components/soc/esp32h2/spi_periph.c +++ b/components/soc/esp32h2/spi_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,29 +13,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { { // MSPI has dedicated iomux pins - .spiclk_out = -1, - .spiclk_in = -1, - .spid_out = -1, - .spiq_out = -1, - .spiwp_out = -1, - .spihd_out = -1, - .spid_in = -1, - .spiq_in = -1, - .spiwp_in = -1, - .spihd_in = -1, - .spics_out = {-1}, - .spics_in = -1, - .spiclk_iomux_pin = -1, - .spid_iomux_pin = -1, - .spiq_iomux_pin = -1, - .spiwp_iomux_pin = -1, - .spihd_iomux_pin = -1, - .spics0_iomux_pin = -1, - .irq = -1, - .irq_dma = -1, - .module = -1, - .hw = NULL, - .func = -1, }, { .spiclk_out = FSPICLK_OUT_IDX, .spiclk_in = FSPICLK_IN_IDX, @@ -57,8 +34,50 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_GSPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, } }; + +/** + * Backup registers in Light sleep: (total cnt 12) + * + * cmd + * addr + * ctrl + * clock + * user + * user1 + * user2 + * ms_dlen + * misc + * dma_conf + * dma_int_ena + * slave + */ +#define SPI_RETENTION_REGS_CNT 12 +static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0}; +#define SPI_REG_RETENTION_ENTRIES(num) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \ + REG_SPI_BASE(num), REG_SPI_BASE(num), \ + SPI_RETENTION_REGS_CNT, 0, 0, \ + spi_regs_map[0], spi_regs_map[1], \ + spi_regs_map[2], spi_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + /* Additional interrupt setting is required by idf SPI drivers after register recovered */ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \ + SPI_DMA_INT_SET_REG(num), \ + SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \ + UINT32_MAX, 1, 0), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2 + +const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI2, + .entry_array = spi2_regs_retention, + .array_size = ARRAY_SIZE(spi2_regs_retention), + }, +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index d07687afd413..ff5402ee4c7b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1439,6 +1439,10 @@ config SOC_SPI_MAXIMUM_BUFFER_SIZE int default 64 +config SOC_SPI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_SPI_SUPPORT_SLAVE_HD_VER2 bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 1feadd9d1157..2828ff6d7d28 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -535,6 +535,7 @@ #define SOC_SPI_MAX_CS_NUM 6 #define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 +#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1 #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 #define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1 #define SOC_SPI_SUPPORT_DDRCLK 1 diff --git a/components/soc/esp32p4/spi_periph.c b/components/soc/esp32p4/spi_periph.c index 8d88638166e4..db30a6bf6893 100644 --- a/components/soc/esp32p4/spi_periph.c +++ b/components/soc/esp32p4/spi_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,29 +13,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { { // MSPI on P4 has dedicated iomux pins - .spiclk_out = -1, - .spiclk_in = -1, - .spid_out = -1, - .spiq_out = -1, - .spiwp_out = -1, - .spihd_out = -1, - .spid_in = -1, - .spiq_in = -1, - .spiwp_in = -1, - .spihd_in = -1, - .spics_out = {-1}, - .spics_in = -1, - .spiclk_iomux_pin = -1, - .spid_iomux_pin = -1, - .spiq_iomux_pin = -1, - .spiwp_iomux_pin = -1, - .spihd_iomux_pin = -1, - .spics0_iomux_pin = -1, - .irq = -1, - .irq_dma = -1, - .module = -1, - .hw = NULL, - .func = -1, }, { .spiclk_out = SPI2_CK_PAD_OUT_IDX, .spiclk_in = SPI2_CK_PAD_IN_IDX, @@ -65,7 +42,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_GPSPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, }, { @@ -90,8 +66,56 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = ETS_SPI3_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_GPSPI3_MODULE, .hw = &GPSPI3, .func = -1, } }; + +/** + * Backup registers in Light sleep: (total cnt 12) + * + * cmd + * addr + * ctrl + * clock + * user + * user1 + * user2 + * ms_dlen + * misc + * dma_conf + * dma_int_ena + * slave + */ +#define SPI_RETENTION_REGS_CNT 12 +static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0}; +#define SPI_REG_RETENTION_ENTRIES(num) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \ + REG_SPI_BASE(num), REG_SPI_BASE(num), \ + SPI_RETENTION_REGS_CNT, 0, 0, \ + spi_regs_map[0], spi_regs_map[1], \ + spi_regs_map[2], spi_regs_map[3]), \ + .owner = ENTRY(0) }, \ + /* Additional interrupt setting is required by idf SPI drivers after register recovered */ \ + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \ + SPI_DMA_INT_SET_REG(num), \ + SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \ + UINT32_MAX, 1, 0), \ + .owner = ENTRY(0) }, \ +} + +static const regdma_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2 +static const regdma_entries_config_t spi3_regs_retention[] = SPI_REG_RETENTION_ENTRIES(3); + +const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI2, + .entry_array = spi2_regs_retention, + .array_size = ARRAY_SIZE(spi2_regs_retention), + }, + { + .module_id = SLEEP_RETENTION_MODULE_GPSPI3, + .entry_array = spi3_regs_retention, + .array_size = ARRAY_SIZE(spi3_regs_retention), + }, +}; diff --git a/components/soc/esp32s2/spi_periph.c b/components/soc/esp32s2/spi_periph.c index 2dfcdfb20bc1..c1ed623608ce 100644 --- a/components/soc/esp32s2/spi_periph.c +++ b/components/soc/esp32s2/spi_periph.c @@ -32,7 +32,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = MSPI_IOMUX_PIN_NUM_CS0, .irq = ETS_SPI1_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI_MODULE, .hw = (spi_dev_t *) &SPIMEM1, .func = MSPI_FUNC_NUM, @@ -65,7 +64,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = FSPI_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = ETS_SPI2_DMA_INTR_SOURCE, - .module = PERIPH_FSPI_MODULE, .hw = &GPSPI2, .func = FSPI_FUNC_NUM, }, { @@ -91,7 +89,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = ETS_SPI3_INTR_SOURCE, .irq_dma = ETS_SPI3_DMA_INTR_SOURCE, - .module = PERIPH_HSPI_MODULE, .hw = &GPSPI3, .func = -1, } diff --git a/components/soc/esp32s3/spi_periph.c b/components/soc/esp32s3/spi_periph.c index 91fdc8735517..3675131a9b93 100644 --- a/components/soc/esp32s3/spi_periph.c +++ b/components/soc/esp32s3/spi_periph.c @@ -33,7 +33,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = -1, .irq_dma = -1, - .module = -1, .hw = NULL, .func = -1, }, { @@ -65,7 +64,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, .irq = ETS_SPI2_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI2_MODULE, .hw = &GPSPI2, .func = SPI2_FUNC_NUM, }, { @@ -91,7 +89,6 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { .spics0_iomux_pin = -1, .irq = ETS_SPI3_INTR_SOURCE, .irq_dma = -1, - .module = PERIPH_SPI3_MODULE, .hw = &GPSPI3, .func = -1, } diff --git a/components/soc/include/soc/spi_periph.h b/components/soc/include/soc/spi_periph.h index 7a85aafa6502..8e653edf0c36 100644 --- a/components/soc/include/soc/spi_periph.h +++ b/components/soc/include/soc/spi_periph.h @@ -9,13 +9,17 @@ #include #include "sdkconfig.h" #include "soc/soc.h" -#include "soc/periph_defs.h" +#include "soc/soc_caps.h" +#include "soc/spi_pins.h" +#if SOC_PAU_SUPPORTED +#include "soc/regdma.h" +#include "soc/retention_periph_defs.h" +#endif //include soc related (generated) definitions -#include "soc/soc_caps.h" +#include "soc/interrupts.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" -#include "soc/spi_pins.h" #include "soc/gpio_sig_map.h" #if SOC_MEMSPI_IS_INDEPENDENT #include "soc/spi_mem_struct.h" @@ -71,13 +75,22 @@ typedef struct { const uint8_t spics0_iomux_pin; const uint8_t irq; //irq source for interrupt mux const uint8_t irq_dma; //dma irq source for interrupt mux - const periph_module_t module; //peripheral module, for enabling clock etc - const int func; //function number for IOMUX - spi_dev_t *hw; //Pointer to the hardware registers + const int func; //function number for IOMUX + spi_dev_t *hw; //Pointer to the hardware registers } spi_signal_conn_t; extern const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM]; +#if SOC_PAU_SUPPORTED +typedef struct { + const periph_retention_module_t module_id; + const regdma_entries_config_t *entry_array; + uint32_t array_size; +} spi_reg_retention_info_t; + +extern const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1]; // -1 to except mspi +#endif // SOC_PAU_SUPPORTED + #ifdef __cplusplus } #endif diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index 71ef262c433d..7932212719e0 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -305,6 +305,14 @@ Bus Acquiring Sometimes you might want to send SPI transactions exclusively and continuously so that it takes as little time as possible. For this, you can use bus acquiring, which helps to suspend transactions (both polling or interrupt) to other Devices until the bus is released. To acquire and release a bus, use the functions :cpp:func:`spi_device_acquire_bus` and :cpp:func:`spi_device_release_bus`. +.. only:: SOC_SPI_SUPPORT_SLEEP_RETENTION + + Sleep Retention + ^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} supports to retain the SPI register context before entering **light sleep** and restore them after waking up. This means you don't have to re-init the SPI driver after the light sleep. + + This feature can be enabled by setting the flag :c:macro:`SPICOMMON_BUSFLAG_SLP_ALLOW_PD`. It will allow the system to power down the SPI in light sleep, meanwhile save the register context. It can help to save more power consumption with some extra cost of the memory. Driver Usage ------------ diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index aab8a9c96afa..f7994e992526 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -148,7 +148,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - INT_MTX - TEE/APM - IO_MUX / GPIO - - SPI0/1 + - MSPI (SPI0/1) - SYSTIMER :SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT @@ -160,6 +160,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO + :SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs The following peripherals are not yet supported: @@ -168,7 +169,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - ASSIST_DEBUG - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA - - SPI2 - PCNT - USB-Serial-JTAG - MCPWM diff --git a/docs/zh_CN/api-reference/peripherals/spi_master.rst b/docs/zh_CN/api-reference/peripherals/spi_master.rst index 9868ee66baef..764f7bc82a1a 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_master.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_master.rst @@ -305,6 +305,14 @@ SPI 总线传输事务由五个阶段构成,详见下表(任意阶段均可 若需连续发送专门的 SPI 传输事务以提高效率,可采用获取总线的方式。获取总线后,与其他设备间的传输事务(包括轮询传输事务或中断传输事务)将处于待处理状态,直到总线被释放。要获取和释放总线,请调用函数 :cpp:func:`spi_device_acquire_bus` 和 :cpp:func:`spi_device_release_bus`。 +.. only:: SOC_SPI_SUPPORT_SLEEP_RETENTION + + 睡眠保留 + ^^^^^^^^ + + {IDF_TARGET_NAME} 支持在进入 **Light Sleep** 之前保留 SPI 寄存器中的内容,并在唤醒后恢复。即程序不需要在 **Light Sleep** 唤醒后重新配置 SPI。 + + 该特性可以通过置位配置中的 :c:macro:`SPICOMMON_BUSFLAG_SLP_ALLOW_PD` 标志位启用。启用后驱动允许系统在 Light Sleep 时对 SPI 掉电,同时保存寄存器配置。它可以帮助降低轻度睡眠时的功耗,但需要花费一些额外的存储来保存寄存器的配置。 使用驱动程序 ----------------- diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index a61bd248456b..fd569a9821b4 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -148,7 +148,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - INT_MTX - TEE/APM - IO_MUX / GPIO - - SPI0/1 + - MSPI (SPI0/1) - SYSTIMER :SOC_TIMER_SUPPORT_SLEEP_RETENTION: - GPTimer :SOC_RMT_SUPPORT_SLEEP_RETENTION: - RMT @@ -160,6 +160,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO + :SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs 以下外设尚未支持: @@ -168,7 +169,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - ASSIST_DEBUG - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA - - SPI2 - PCNT - USB-Serial-JTAG - MCPWM From 2f9456bf511855f5033a625156eed14d3f9ee379 Mon Sep 17 00:00:00 2001 From: wanckl Date: Tue, 22 Oct 2024 15:07:17 +0800 Subject: [PATCH 2/2] fix(esp_timer): fix isr safe when CONFIG_FREERTOS_USE_TICKLESS_IDLE and PM_ENABLE --- components/esp_driver_spi/src/gpspi/spi_common.c | 1 + components/esp_timer/src/esp_timer_impl_lac.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 7e2ed7cc5287..1b51593d5728 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -979,6 +979,7 @@ esp_err_t spi_bus_free(spi_host_device_t host_id) sleep_retention_module_deinit(retention_id); } _lock_release(&ctx->mutex); + _lock_close(&ctx->mutex); #endif #ifdef CONFIG_PM_ENABLE diff --git a/components/esp_timer/src/esp_timer_impl_lac.c b/components/esp_timer/src/esp_timer_impl_lac.c index d557716e659f..79503303af56 100644 --- a/components/esp_timer/src/esp_timer_impl_lac.c +++ b/components/esp_timer/src/esp_timer_impl_lac.c @@ -222,11 +222,11 @@ static void IRAM_ATTR timer_alarm_isr(void *arg) void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) { - portENTER_CRITICAL(&s_time_update_lock); + portENTER_CRITICAL_SAFE(&s_time_update_lock); assert(apb_ticks_per_us >= 3 && "divider value too low"); assert(apb_ticks_per_us % TICKS_PER_US == 0 && "APB frequency (in MHz) should be divisible by TICK_PER_US"); REG_SET_FIELD(CONFIG_REG, TIMG_LACT_DIVIDER, apb_ticks_per_us / TICKS_PER_US); - portEXIT_CRITICAL(&s_time_update_lock); + portEXIT_CRITICAL_SAFE(&s_time_update_lock); } void esp_timer_impl_set(uint64_t new_us)