-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/esp32c61_light_sleep_support_stage_3' into 'mas…
…ter' feat(esp_hw_support): esp32c61 sleep support (Stage 3: support system peripheral sleep retention) Closes IDF-10384, IDF-10382, and IDF-11004 See merge request espressif/esp-idf!33298
- Loading branch information
Showing
33 changed files
with
982 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
components/esp_hw_support/lowpower/port/esp32c61/sleep_clock.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include "esp_private/sleep_clock.h" | ||
#include "soc/pcr_reg.h" | ||
#include "modem/modem_syscon_reg.h" | ||
|
||
static const char *TAG = "sleep_clock"; | ||
|
||
esp_err_t sleep_clock_system_retention_init(void *arg) | ||
{ | ||
const static sleep_retention_entries_config_t pcr_regs_retention[] = { | ||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PCR_LINK(0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, 63, 0, 0, 0xfd73ffff, 0xfdffffff, 0xe001, 0x0), .owner = ENTRY(0) | ENTRY(1) }, | ||
}; | ||
|
||
esp_err_t err = sleep_retention_entries_create(pcr_regs_retention, ARRAY_SIZE(pcr_regs_retention), REGDMA_LINK_PRI_SYS_CLK, SLEEP_RETENTION_MODULE_CLOCK_SYSTEM); | ||
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for system (PCR) retention"); | ||
ESP_LOGI(TAG, "System Power, Clock and Reset sleep retention initialization"); | ||
return ESP_OK; | ||
} | ||
|
||
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE | ||
esp_err_t sleep_clock_modem_retention_init(void *arg) | ||
{ | ||
#define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) | ||
|
||
const static sleep_retention_entries_config_t modem_regs_retention[] = { | ||
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ | ||
}; | ||
|
||
esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); | ||
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for modem (SYSCON) retention, 1 level priority"); | ||
ESP_LOGI(TAG, "Modem Power, Clock and Reset sleep retention initialization"); | ||
return ESP_OK; | ||
} | ||
#endif | ||
|
||
bool clock_domain_pd_allowed(void) | ||
{ | ||
const uint32_t inited_modules = sleep_retention_get_inited_modules(); | ||
const uint32_t created_modules = sleep_retention_get_created_modules(); | ||
const uint32_t sys_clk_dep_modules = (const uint32_t) (BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH)); | ||
|
||
/* The clock and reset of MODEM (WiFi, BLE and 15.4) modules are managed | ||
* through MODEM_SYSCON, when one or more MODEMs are initialized, it is | ||
* necessary to check the state of CLOCK_MODEM to determine MODEM domain on | ||
* or off. The clock and reset of digital peripherals are managed through | ||
* PCR, with TOP domain similar to MODEM domain. */ | ||
uint32_t modem_clk_dep_modules = 0; | ||
#if SOC_WIFI_SUPPORTED | ||
modem_clk_dep_modules |= BIT(SLEEP_RETENTION_MODULE_WIFI_MAC) | BIT(SLEEP_RETENTION_MODULE_WIFI_BB); | ||
#endif | ||
#if SOC_BT_SUPPORTED | ||
modem_clk_dep_modules |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC) | BIT(SLEEP_RETENTION_MODULE_BT_BB); | ||
#endif | ||
#if SOC_IEEE802154_SUPPORTED | ||
modem_clk_dep_modules |= BIT(SLEEP_RETENTION_MODULE_802154_MAC) | BIT(SLEEP_RETENTION_MODULE_BT_BB); | ||
#endif | ||
|
||
uint32_t mask = 0; | ||
if (inited_modules & sys_clk_dep_modules) { | ||
mask |= BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM); | ||
} | ||
if (inited_modules & modem_clk_dep_modules) { | ||
#if SOC_WIFI_SUPPORTED || SOC_BT_SUPPORTED || SOC_IEEE802154_SUPPORTED | ||
mask |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM); | ||
#endif | ||
} | ||
return ((inited_modules & mask) == (created_modules & mask)); | ||
} | ||
|
||
ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, SECONDARY, BIT(0), 106) | ||
{ | ||
sleep_retention_module_init_param_t init_param = { | ||
.cbs = { .create = { .handle = sleep_clock_system_retention_init, .arg = NULL } }, | ||
.attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE | ||
}; | ||
sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM, &init_param); | ||
|
||
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE | ||
init_param = (sleep_retention_module_init_param_t) { | ||
.cbs = { .create = { .handle = sleep_clock_modem_retention_init, .arg = NULL } }, | ||
.attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE | ||
}; | ||
sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_MODEM, &init_param); | ||
#endif | ||
return ESP_OK; | ||
} |
162 changes: 162 additions & 0 deletions
162
components/esp_hw_support/lowpower/port/esp32c61/sleep_mmu.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <string.h> | ||
#include <inttypes.h> | ||
|
||
#include "esp_attr.h" | ||
#include "esp_check.h" | ||
#include "esp_sleep.h" | ||
#include "esp_log.h" | ||
#include "esp_heap_caps.h" | ||
#include "soc/soc_caps.h" | ||
#include "sdkconfig.h" | ||
#include "soc/spi_mem_reg.h" | ||
#include "esp_private/startup_internal.h" | ||
|
||
static const char *TAG = "sleep_mmu"; | ||
|
||
typedef struct { | ||
uint32_t start; | ||
uint32_t end; | ||
} mmu_domain_dev_regs_region_t; | ||
|
||
typedef struct { | ||
mmu_domain_dev_regs_region_t *region; | ||
int region_num; | ||
uint32_t *regs_frame; | ||
} mmu_domain_dev_sleep_frame_t; | ||
|
||
/** | ||
* Internal structure which holds all requested light sleep mmu retention parameters | ||
*/ | ||
typedef struct { | ||
struct { | ||
mmu_domain_dev_sleep_frame_t *mmu_table_frame; | ||
} retent; | ||
} sleep_mmu_retention_t; | ||
|
||
static DRAM_ATTR __attribute__((unused)) sleep_mmu_retention_t s_mmu_retention; | ||
|
||
static void * mmu_domain_dev_sleep_frame_alloc_and_init(const mmu_domain_dev_regs_region_t *regions, const int region_num) | ||
{ | ||
const int region_sz = sizeof(mmu_domain_dev_regs_region_t) * region_num; | ||
int regs_frame_sz = 0; | ||
for (int num = 0; num < region_num; num++) { | ||
regs_frame_sz += regions[num].end - regions[num].start; | ||
} | ||
void *frame = heap_caps_malloc(sizeof(mmu_domain_dev_sleep_frame_t) + region_sz + regs_frame_sz, MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL); | ||
if (frame) { | ||
mmu_domain_dev_regs_region_t *region = (mmu_domain_dev_regs_region_t *)(frame + sizeof(mmu_domain_dev_sleep_frame_t)); | ||
memcpy(region, regions, region_num * sizeof(mmu_domain_dev_regs_region_t)); | ||
void *regs_frame = frame + sizeof(mmu_domain_dev_sleep_frame_t) + region_sz; | ||
memset(regs_frame, 0, regs_frame_sz); | ||
*(mmu_domain_dev_sleep_frame_t *)frame = (mmu_domain_dev_sleep_frame_t) { | ||
.region = region, | ||
.region_num = region_num, | ||
.regs_frame = (uint32_t *)regs_frame | ||
}; | ||
} | ||
return frame; | ||
} | ||
|
||
static inline void * mmu_domain_mmu_table_sleep_frame_alloc_and_init(void) | ||
{ | ||
#define MMU_TABLE_SIZE (512 * 4) | ||
const static mmu_domain_dev_regs_region_t regions[] = { | ||
{ .start = SPI_MEM_MMU_ITEM_CONTENT_REG(0), .end = SPI_MEM_MMU_ITEM_CONTENT_REG(0) + MMU_TABLE_SIZE} | ||
}; | ||
return mmu_domain_dev_sleep_frame_alloc_and_init(regions, sizeof(regions) / sizeof(regions[0])); | ||
} | ||
|
||
static IRAM_ATTR void mmu_domain_dev_regs_save(mmu_domain_dev_sleep_frame_t *frame) | ||
{ | ||
assert(frame); | ||
mmu_domain_dev_regs_region_t *region = frame->region; | ||
uint32_t *regs_frame = frame->regs_frame; | ||
|
||
int offset = 0; | ||
for (int i = 0; i < frame->region_num; i++) { | ||
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) { | ||
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset); | ||
regs_frame[offset++] = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); | ||
} | ||
} | ||
} | ||
|
||
static IRAM_ATTR void mmu_domain_dev_regs_restore(mmu_domain_dev_sleep_frame_t *frame) | ||
{ | ||
assert(frame); | ||
mmu_domain_dev_regs_region_t *region = frame->region; | ||
uint32_t *regs_frame = frame->regs_frame; | ||
|
||
int offset = 0; | ||
for (int i = 0; i < frame->region_num; i++) { | ||
for (uint32_t addr = region[i].start; addr < region[i].end; addr+=4) { | ||
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), offset); | ||
REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0),regs_frame[offset++]); | ||
} | ||
} | ||
} | ||
|
||
IRAM_ATTR void esp_sleep_mmu_retention(bool backup_or_restore) | ||
{ | ||
if (backup_or_restore) { | ||
mmu_domain_dev_regs_save(s_mmu_retention.retent.mmu_table_frame); | ||
} else { | ||
mmu_domain_dev_regs_restore(s_mmu_retention.retent.mmu_table_frame); | ||
} | ||
} | ||
|
||
static esp_err_t esp_sleep_mmu_retention_deinit_impl(void) | ||
{ | ||
if (s_mmu_retention.retent.mmu_table_frame) { | ||
heap_caps_free((void *)s_mmu_retention.retent.mmu_table_frame); | ||
s_mmu_retention.retent.mmu_table_frame = NULL; | ||
} | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t esp_sleep_mmu_retention_init_impl(void) | ||
{ | ||
if (s_mmu_retention.retent.mmu_table_frame == NULL) { | ||
void *frame = mmu_domain_mmu_table_sleep_frame_alloc_and_init(); | ||
if (frame == NULL) { | ||
goto err; | ||
} | ||
s_mmu_retention.retent.mmu_table_frame = (mmu_domain_dev_sleep_frame_t *)frame; | ||
} | ||
return ESP_OK; | ||
err: | ||
esp_sleep_mmu_retention_deinit(); | ||
return ESP_ERR_NO_MEM; | ||
} | ||
|
||
esp_err_t esp_sleep_mmu_retention_init(void) | ||
{ | ||
return esp_sleep_mmu_retention_init_impl(); | ||
} | ||
|
||
esp_err_t esp_sleep_mmu_retention_deinit(void) | ||
{ | ||
return esp_sleep_mmu_retention_deinit_impl(); | ||
} | ||
|
||
bool mmu_domain_pd_allowed(void) | ||
{ | ||
return (s_mmu_retention.retent.mmu_table_frame != NULL); | ||
} | ||
|
||
ESP_SYSTEM_INIT_FN(sleep_mmu_startup_init, SECONDARY, BIT(0), 108) | ||
{ | ||
esp_err_t ret; | ||
ret = esp_sleep_mmu_retention_init(); | ||
if (ret != ESP_OK) { | ||
ESP_EARLY_LOGW(TAG, "Failed to enable TOP power down during light sleep."); | ||
} | ||
return ESP_OK; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.