Skip to content

Commit

Permalink
sleep retention: implement the extra linked list retention for module…
Browse files Browse the repository at this point in the history
…s with retention clock bugs
  • Loading branch information
esp-lis committed Jun 13, 2023
1 parent ef4c0a7 commit ccd4ff2
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
10 changes: 10 additions & 0 deletions components/esp_hw_support/include/esp_private/sleep_retention.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ void * sleep_retention_find_link_by_id(int id);
*/
void sleep_retention_entries_get(sleep_retention_entries_t *entries);

#if SOC_PM_RETENTION_HAS_CLOCK_BUG
/**
* @brief Software trigger REGDMA to do extra linked list retention
*
* @param backup_or_restore true for backup register context to memory
* or false for restore to register from memory
*/
void sleep_retention_do_extra_retention(bool backup_or_restore);
#endif

/**
* @brief Get all registered modules that require sleep retention
*
Expand Down
82 changes: 74 additions & 8 deletions components/esp_hw_support/sleep_retention.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,44 @@ typedef struct {
* The PMU module triggers REGDMA to use the corresponding linked list when
* swtiching between different power states. For example:
*
* Current power state Next power state This entry will be used by REGDMA
* PMU_HP_ACTIVE PMU_HP_SLEEP entry0
* PMU_HP_SLEEP PMU_HP_ACTIVE entry0
* PMU_HP_MODEM PMU_HP_SLEEP entry1
* PMU_HP_SLEEP PMU_HP_MODEM entry1
* PMU_HP_MODEM PMU_HP_ACTIVE entry2
* +---------------+---------------+-------------------+-----------+
* | Current | The next | The entry will be | Retention |
* | PMU state | PMU state | used by REGDMA | clock |
* +---------------+---------------+-------------------+-----------+
* | PMU_HP_ACTIVE | PMU_HP_SLEEP | entry0 | XTAL |
* | PMU_HP_SLEEP | PMU_HP_ACTIVE | entry0 | XTAL |
* | PMU_HP_MODEM | PMU_HP_SLEEP | ------ | XTAL |
* | PMU_HP_SLEEP | PMU_HP_MODEM | entry1 | XTAL |
* | PMU_HP_MODEM | PMU_HP_ACTIVE | entry2 | PLL |
* |---------------------------------------------------------------|
* | PMU_HP_ACTIVE | PMU_HP_ACTIVE | entry3 | PLL | (Clock BUG)
* +---------------+---------------+-------------------+-----------+
*
* +--------+ +-------------------------+ +-------------+ +-----------+ +--------+ +-----+
* entry2 -> | | -> | WiFi MAC Minimum System | -> | | -------------------------> | | -> | | -> | End |
* entry2 -> | | -> | WiFi MAC Minimum System | -> | | -------------------------> | ######### | -> | ###### | -> | End |
* | SOC | +-------------------------+ | Digital | | Bluetooth | | Zigbee | +-----+
* | System | +--------+ | Peripherals | +------+ +------+ | / BLE | | | +-----+
* entry0 -> | | ----------> | | ---------> | | -> | | -> | | -> | | -> | | -> | End |
* +--------+ | Modem | +-------------+ | WiFi | | WiFi | +-----------+ +--------+ +-----+
* | System | | MAC | | BB | +-----+
* entry1 ------------------------> | |-----------------------------> | | -> | | -> | End |
* +--------+ +------+ +------+ +-----+
*
* The entry3 (alias: extra linked list) is used for backup and restore of
* modules (such as BLE or 15.4 modules) with retention clock bugs.
*
* +---------+ +----------+ +-------------+ +-----+
* entry3 -> | BLE MAC | -> | 15.4 MAC | -> | BLE/15.4 BB | -> | End |
* +---------+ +----------+ +-------------+ +-----+
*
* Using it (extra linked list) for retention has the following constraints:
* 1. The PLL clock must be enabled (can be done with esp_pm_lock_acquire()
* interface to acquire a pm lock of type ESP_PM_APB_FREQ_MAX.
* 2. When using the sleep_retention_entries_create() interface to create an
* extra linked list, the node owner must be equal to BIT(3).
* 3. Use the sleep_retention_do_extra_retention() interface to backup or
* restore the register context, which ensures only one backup or restore
* when multiple modules (BLE and 15.4) exists.
*/
#define SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES (8u)
#define SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY (0)
Expand All @@ -71,9 +93,18 @@ typedef struct {
_lock_t lock;
regdma_link_priority_t highpri;
uint32_t modules;
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
#define EXTRA_LINK_NUM (REGDMA_LINK_ENTRY_NUM - 1)
int extra_refs;
#endif
} sleep_retention_t;

static DRAM_ATTR __attribute__((unused)) sleep_retention_t s_retention = { .highpri = (uint8_t)-1, .modules = 0 };
static DRAM_ATTR __attribute__((unused)) sleep_retention_t s_retention = {
.highpri = (uint8_t)-1, .modules = 0
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
, .extra_refs = 0
#endif
};

#define SLEEP_RETENTION_ENTRY_BITMAP_MASK (BIT(REGDMA_LINK_ENTRY_NUM) - 1)
#define SLEEP_RETENTION_ENTRY_BITMAP(bitmap) ((bitmap) & SLEEP_RETENTION_ENTRY_BITMAP_MASK)
Expand Down Expand Up @@ -358,6 +389,13 @@ static esp_err_t sleep_retention_entries_create_impl(const sleep_retention_entri
{
_lock_acquire_recursive(&s_retention.lock);
for (int i = num - 1; i >= 0; i--) {
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
if ((retent[i].owner > BIT(EXTRA_LINK_NUM)) && (retent[i].config.id != 0xffff)) {
_lock_release_recursive(&s_retention.lock);
sleep_retention_entries_do_destroy(module);
return ESP_ERR_NOT_SUPPORTED;
}
#endif
void *link = sleep_retention_entries_try_create(&retent[i].config, retent[i].owner, priority, module);
if (link == NULL) {
_lock_release_recursive(&s_retention.lock);
Expand Down Expand Up @@ -464,3 +502,31 @@ uint32_t IRAM_ATTR sleep_retention_get_modules(void)
{
return s_retention.modules;
}

#if SOC_PM_RETENTION_HAS_CLOCK_BUG
void sleep_retention_do_extra_retention(bool backup_or_restore)
{
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.highpri < SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY ||
s_retention.highpri > SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
_lock_release_recursive(&s_retention.lock);
return;
}
const uint32_t clk_bug_modules = SLEEP_RETENTION_MODULE_BLE_MAC | SLEEP_RETENTION_MODULE_802154_MAC;
const int cnt_modules = __builtin_popcount(clk_bug_modules & s_retention.modules);
// Set extra linked list head pointer to hardware
pau_regdma_set_extra_link_addr(s_retention.lists[s_retention.highpri].entries[EXTRA_LINK_NUM]);
if (backup_or_restore) {
if (s_retention.extra_refs++ == (cnt_modules - 1)) {
pau_regdma_trigger_extra_link_backup();
}
} else {
if (--s_retention.extra_refs == (cnt_modules - 1)) {
pau_regdma_trigger_extra_link_restore();
}
}
int refs = s_retention.extra_refs;
_lock_release_recursive(&s_retention.lock);
assert(refs >= 0 && refs <= cnt_modules);
}
#endif
4 changes: 4 additions & 0 deletions components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,10 @@ config SOC_PM_MODEM_RETENTION_BY_REGDMA
bool
default y

config SOC_PM_RETENTION_HAS_CLOCK_BUG
bool
default y

config SOC_PM_PAU_LINK_NUM
int
default 4
Expand Down
1 change: 1 addition & 0 deletions components/soc/esp32c6/include/soc/soc_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@

#define SOC_PM_CPU_RETENTION_BY_SW (1)
#define SOC_PM_MODEM_RETENTION_BY_REGDMA (1)
#define SOC_PM_RETENTION_HAS_CLOCK_BUG (1)

#define SOC_PM_PAU_LINK_NUM (4)

Expand Down

0 comments on commit ccd4ff2

Please sign in to comment.