1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
39
40
41
42
43
44
45
46
47
48
68
69
79
80
88
89
90
91
92
101
102
106
107
108
109
110
120
121
129
130
131
132
133
134
146
147
148
149
150
151
152
153
154
155
162
163
164
165
173
174
183
184
188
189
193
194
195
196
197
198
199
200
201
202
203
204
206
207
208
210
211
212
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
241
242
243
244
245
246
247
248
250
251
252
256
257
258
259
260
261
262
263
264
276
277
287
288
296
297
298
299
305
306
312
313
314
321
322
323
324
333
334
335
336
337
338
339
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
363
364
365
366
367
368
369
372
373
374
375
376
385
386
395
/* ... */
#include <stddef.h>
#include <string.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "esp_check.h"
#include "soc/soc_caps.h"
#include "esp_private/pm_impl.h"
#include "esp_private/sleep_modem.h"
#include "esp_private/sleep_retention.h"
#include "sdkconfig.h"13 includes
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
#include "esp_private/esp_pmu.h"
#endif
#if SOC_PM_MODEM_RETENTION_BY_REGDMA
#include "esp_pau.h"
#endif
static __attribute__((unused)) const char *TAG = "sleep_modem";
#if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz);
#endif
#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD
static bool s_modem_sleep = false;
static uint8_t s_modem_prepare_ref = 0;
static _lock_t s_modem_prepare_lock;/* ... */
#endif
#if CONFIG_MAC_BB_PD
#define MAC_BB_POWER_DOWN_CB_NO (3)
#define MAC_BB_POWER_UP_CB_NO (3)
static DRAM_ATTR mac_bb_power_down_cb_t s_mac_bb_power_down_cb[MAC_BB_POWER_DOWN_CB_NO];
static DRAM_ATTR mac_bb_power_up_cb_t s_mac_bb_power_up_cb[MAC_BB_POWER_UP_CB_NO];
esp_err_t esp_register_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
{
int index = MAC_BB_POWER_DOWN_CB_NO;
for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
if (s_mac_bb_power_down_cb[i] == cb) {
return ESP_OK;
}{...}
if (s_mac_bb_power_down_cb[i] == NULL) {
index = i;
}{...}
}{...}
if (index < MAC_BB_POWER_DOWN_CB_NO) {
s_mac_bb_power_down_cb[index] = cb;
return ESP_OK;
}{...}
return ESP_ERR_NO_MEM;
}{...}
esp_err_t esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
{
for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
if (s_mac_bb_power_down_cb[i] == cb) {
s_mac_bb_power_down_cb[i] = NULL;
return ESP_OK;
}{...}
}{...}
return ESP_ERR_INVALID_STATE;
}{...}
void IRAM_ATTR mac_bb_power_down_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_DOWN_CB_NO; i++) {
if (s_mac_bb_power_down_cb[i]) {
s_mac_bb_power_down_cb[i]();
}{...}
}{...}
}{...}
esp_err_t esp_register_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
{
int index = MAC_BB_POWER_UP_CB_NO;
for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
if (s_mac_bb_power_up_cb[i] == cb) {
return ESP_OK;
}{...}
if (s_mac_bb_power_up_cb[i] == NULL) {
index = i;
}{...}
}{...}
if (index < MAC_BB_POWER_UP_CB_NO) {
s_mac_bb_power_up_cb[index] = cb;
return ESP_OK;
}{...}
return ESP_ERR_NO_MEM;
}{...}
esp_err_t esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
{
for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
if (s_mac_bb_power_up_cb[i] == cb) {
s_mac_bb_power_up_cb[i] = NULL;
return ESP_OK;
}{...}
}{...}
return ESP_ERR_INVALID_STATE;
}{...}
void IRAM_ATTR mac_bb_power_up_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_UP_CB_NO; i++) {
if (s_mac_bb_power_up_cb[i]) {
s_mac_bb_power_up_cb[i]();
}{...}
}{...}
}{...}
/* ... */
#endif
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
typedef struct sleep_modem_config {
struct {
void *phy_link;
union {
struct {
uint32_t modem_state_phy_done: 1;
uint32_t reserved: 31;
}{...};
uint32_t flags;
}{...};
}{...} wifi;
}{...} sleep_modem_config_t;
static sleep_modem_config_t s_sleep_modem = { .wifi.phy_link = NULL, .wifi.flags = 0 };
esp_err_t sleep_modem_wifi_modem_state_init(void)
{
esp_err_t err = ESP_OK;
void *link = NULL;
if (s_sleep_modem.wifi.phy_link == NULL) {
err = sleep_modem_state_phy_link_init(&link);
if (err == ESP_OK) {
s_sleep_modem.wifi.phy_link = link;
s_sleep_modem.wifi.flags = 0;
}{...}
}{...}
return err;
}{...}
__attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void)
{
if (s_sleep_modem.wifi.phy_link) {
sleep_modem_state_phy_link_deinit(s_sleep_modem.wifi.phy_link);
s_sleep_modem.wifi.phy_link = NULL;
s_sleep_modem.wifi.flags = 0;
}{...}
}{...}
void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore)
{
if (restore) {
pau_regdma_trigger_modem_link_restore();
}{...} else {
pau_regdma_trigger_modem_link_backup();
s_sleep_modem.wifi.modem_state_phy_done = 1;
}{...}
}{...}
inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_state_enabled(void)
{
return (s_sleep_modem.wifi.phy_link != NULL);
}{...}
inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_link_done(void)
{
return (s_sleep_modem.wifi.modem_state_phy_done == 1);
}{...}
/* ... */
#endif
bool modem_domain_pd_allowed(void)
{
#if SOC_PM_MODEM_RETENTION_BY_REGDMA
const sleep_retention_module_bitmap_t inited_modules = sleep_retention_get_inited_modules();
const sleep_retention_module_bitmap_t created_modules = sleep_retention_get_created_modules();
sleep_retention_module_bitmap_t mask = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } };
#if SOC_WIFI_SUPPORTED
mask.bitmap[SLEEP_RETENTION_MODULE_WIFI_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_WIFI_MAC % 32);
mask.bitmap[SLEEP_RETENTION_MODULE_WIFI_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_WIFI_BB % 32);/* ... */
#endif
#if SOC_BT_SUPPORTED
mask.bitmap[SLEEP_RETENTION_MODULE_BLE_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC % 32);
mask.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32);/* ... */
#endif
#if SOC_IEEE802154_SUPPORTED
mask.bitmap[SLEEP_RETENTION_MODULE_802154_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_802154_MAC % 32);
mask.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32);/* ... */
#endif
const sleep_retention_module_bitmap_t modem_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask);
const sleep_retention_module_bitmap_t modem_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask);
return sleep_retention_module_bitmap_eq(modem_domain_inited_modules, modem_domain_created_modules);/* ... */
#else
return false;
#endif
}{ ... }
uint32_t IRAM_ATTR sleep_modem_reject_triggers(void)
{
uint32_t reject_triggers = 0;
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
reject_triggers = (s_sleep_modem.wifi.phy_link != NULL) ? BIT(16) : 0;
#endif
return reject_triggers;
}{ ... }
bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_light_sleep(void)
{
bool skip = false;
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
/* ... */
skip = sleep_modem_wifi_modem_state_enabled() && !sleep_modem_wifi_modem_link_done();/* ... */
#endif
return skip;
}{ ... }
esp_err_t sleep_modem_configure(int max_freq_mhz, int min_freq_mhz, bool light_sleep_enable)
{
#if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP
extern int esp_wifi_internal_light_sleep_configure(bool);
esp_wifi_internal_light_sleep_configure(light_sleep_enable);/* ... */
#endif
#if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
if (light_sleep_enable) {
esp_pm_light_sleep_default_params_config(min_freq_mhz, max_freq_mhz);
}{...}
#endif/* ... */
return ESP_OK;
}{ ... }
#define PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO 2
static inform_out_light_sleep_overhead_cb_t s_periph_inform_out_light_sleep_overhead_cb[PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO];
esp_err_t esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
{
for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
return ESP_OK;
}{...} else if (s_periph_inform_out_light_sleep_overhead_cb[i] == NULL) {
s_periph_inform_out_light_sleep_overhead_cb[i] = cb;
return ESP_OK;
}{...}
}{...}
return ESP_ERR_NO_MEM;
}{ ... }
esp_err_t esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
{
for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
s_periph_inform_out_light_sleep_overhead_cb[i] = NULL;
return ESP_OK;
}{...}
}{...}
return ESP_ERR_INVALID_STATE;
}{ ... }
void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)
{
for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
if (s_periph_inform_out_light_sleep_overhead_cb[i]) {
s_periph_inform_out_light_sleep_overhead_cb[i](out_light_sleep_time);
}{...}
}{...}
}{ ... }
static update_light_sleep_default_params_config_cb_t s_light_sleep_default_params_config_cb = NULL;
void esp_pm_register_light_sleep_default_params_config_callback(update_light_sleep_default_params_config_cb_t cb)
{
if (s_light_sleep_default_params_config_cb == NULL) {
s_light_sleep_default_params_config_cb = cb;
}{...}
}{ ... }
void esp_pm_unregister_light_sleep_default_params_config_callback(void)
{
if (s_light_sleep_default_params_config_cb) {
s_light_sleep_default_params_config_cb = NULL;
}{...}
}{ ... }
#if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz)
{
if (s_light_sleep_default_params_config_cb) {
(*s_light_sleep_default_params_config_cb)(min_freq_mhz, max_freq_mhz);
}{...}
}{...}
/* ... */#endif
#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD
void sleep_modem_register_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,
mac_bb_power_up_cb_t pu_cb)
{
_lock_acquire(&s_modem_prepare_lock);
if (s_modem_prepare_ref++ == 0) {
esp_register_mac_bb_pd_callback(pd_cb);
esp_register_mac_bb_pu_callback(pu_cb);
}{...}
_lock_release(&s_modem_prepare_lock);
}{...}
void sleep_modem_unregister_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,
mac_bb_power_up_cb_t pu_cb)
{
_lock_acquire(&s_modem_prepare_lock);
assert(s_modem_prepare_ref);
if (--s_modem_prepare_ref == 0) {
esp_unregister_mac_bb_pd_callback(pd_cb);
esp_unregister_mac_bb_pu_callback(pu_cb);
}{...}
_lock_release(&s_modem_prepare_lock);
}{...}
/* ... */
static void IRAM_ATTR rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(bool backup, int cpu_freq_mhz, void (*do_retention)(bool))
{
#if SOC_PM_SUPPORT_PMU_MODEM_STATE
if (pmu_sleep_pll_already_enabled()) {
return;
}{...}
/* ... */#endif
rtc_cpu_freq_config_t config, pll_config;
rtc_clk_cpu_freq_get_config(&config);
rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &pll_config);
rtc_clk_cpu_freq_set_config(&pll_config);
if (do_retention) {
(*do_retention)(backup);
}{...}
rtc_clk_cpu_freq_set_config(&config);
}{...}
void IRAM_ATTR sleep_modem_mac_bb_power_down_prepare(void)
{
if (s_modem_sleep == false) {
rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(true,
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
sleep_retention_do_extra_retention);
s_modem_sleep = true;
}{...}
}{...}
void IRAM_ATTR sleep_modem_mac_bb_power_up_prepare(void)
{
if (s_modem_sleep) {
rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(false,
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
sleep_retention_do_extra_retention);
s_modem_sleep = false;
}{...}
}{...}
/* ... */#endif