1 /*
2 * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <string.h>
9 #include <sys/lock.h>
10 #include <sys/param.h>
11
12 #include "esp_log.h"
13 #include "esp_attr.h"
14 #include "esp_sleep.h"
15 #include "soc/soc_caps.h"
16 #include "esp_private/pm_impl.h"
17 #include "esp_private/sleep_modem.h"
18 #include "esp_private/sleep_retention.h"
19 #include "sdkconfig.h"
20
21 #if SOC_PM_MODEM_RETENTION_BY_REGDMA
22 #include "modem/modem_syscon_reg.h"
23 #include "modem/modem_lpcon_reg.h"
24 #include "soc/i2c_ana_mst_reg.h"
25 #include "esp_pau.h"
26 #endif
27
28 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
29 #include "soc/pmu_reg.h"
30 #include "esp_private/esp_pau.h"
31 #include "esp_private/esp_pmu.h"
32 #endif
33
34 static __attribute__((unused)) const char *TAG = "sleep_modem";
35
36 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
37 static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz);
38 #endif
39
40 #if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD
41 static bool s_modem_sleep = false;
42 static uint8_t s_modem_prepare_ref = 0;
43 static _lock_t s_modem_prepare_lock;
44 #endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD
45
46 #if CONFIG_MAC_BB_PD
47 #define MAC_BB_POWER_DOWN_CB_NO (3)
48 #define MAC_BB_POWER_UP_CB_NO (3)
49
50 static DRAM_ATTR mac_bb_power_down_cb_t s_mac_bb_power_down_cb[MAC_BB_POWER_DOWN_CB_NO];
51 static DRAM_ATTR mac_bb_power_up_cb_t s_mac_bb_power_up_cb[MAC_BB_POWER_UP_CB_NO];
52
esp_register_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)53 esp_err_t esp_register_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
54 {
55 int index = MAC_BB_POWER_DOWN_CB_NO;
56 for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
57 if (s_mac_bb_power_down_cb[i] == cb) {
58 return ESP_OK;
59 }
60
61 if (s_mac_bb_power_down_cb[i] == NULL) {
62 index = i;
63 }
64 }
65
66 if (index < MAC_BB_POWER_DOWN_CB_NO) {
67 s_mac_bb_power_down_cb[index] = cb;
68 return ESP_OK;
69 }
70
71 return ESP_ERR_NO_MEM;
72 }
73
esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)74 esp_err_t esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
75 {
76 for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
77 if (s_mac_bb_power_down_cb[i] == cb) {
78 s_mac_bb_power_down_cb[i] = NULL;
79 return ESP_OK;
80 }
81 }
82 return ESP_ERR_INVALID_STATE;
83 }
84
mac_bb_power_down_cb_execute(void)85 void IRAM_ATTR mac_bb_power_down_cb_execute(void)
86 {
87 for (int i = 0; i < MAC_BB_POWER_DOWN_CB_NO; i++) {
88 if (s_mac_bb_power_down_cb[i]) {
89 s_mac_bb_power_down_cb[i]();
90 }
91 }
92 }
93
esp_register_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)94 esp_err_t esp_register_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
95 {
96 int index = MAC_BB_POWER_UP_CB_NO;
97 for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
98 if (s_mac_bb_power_up_cb[i] == cb) {
99 return ESP_OK;
100 }
101
102 if (s_mac_bb_power_up_cb[i] == NULL) {
103 index = i;
104 }
105 }
106
107 if (index < MAC_BB_POWER_UP_CB_NO) {
108 s_mac_bb_power_up_cb[index] = cb;
109 return ESP_OK;
110 }
111
112 return ESP_ERR_NO_MEM;
113 }
114
esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)115 esp_err_t esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
116 {
117 for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
118 if (s_mac_bb_power_up_cb[i] == cb) {
119 s_mac_bb_power_up_cb[i] = NULL;
120 return ESP_OK;
121 }
122 }
123 return ESP_ERR_INVALID_STATE;
124 }
125
mac_bb_power_up_cb_execute(void)126 void IRAM_ATTR mac_bb_power_up_cb_execute(void)
127 {
128 for (int i = 0; i < MAC_BB_POWER_UP_CB_NO; i++) {
129 if (s_mac_bb_power_up_cb[i]) {
130 s_mac_bb_power_up_cb[i]();
131 }
132 }
133 }
134
135 #endif ///CONFIG_MAC_BB_PD
136
137 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
138
139 #define PMU_RF_PWR_REG (0x600b0154)
140 #define SARADC_TSENS_REG (0x6000e058)
141 #define SARADC_TSENS_PU (BIT(22))
142 #define FECOEX_SET_FREQ_SET_CHAN_REG (0x600a00c0)
143 #define FECOEX_SET_CHAN_EN (BIT(14))
144 #define FECOEX_SET_FREQ_SET_CHAN_ST_REG (0x600a00cc)
145 #define FECOEX_SET_CHAN_DONE (BIT(8))
146 #define FECOEX_AGC_CONF_REG (0x600a7030)
147 #define FECOEX_AGC_DIS (BIT(29))
148 #define WDEVTXQ_BLOCK (0x600A4ca8)
149 #define WDEV_RXBLOCK (BIT(12))
150 #define MODEM_FE_DATA_BASE (0x600a0400)
151 #define MODEM_FE_CTRL_BASE (0x600a0800)
152
153 #define I2C_BURST_VAL(host, start, end) (((host) << 31) | ((end) << 22) | ((start) << 16))
154
155 typedef struct {
156 struct {
157 uint8_t start, end; /* the start and end index of phy i2c master command memory */
158 uint8_t host_id; /* phy i2c master host id */
159 } config[2];
160 } phy_i2c_master_command_attribute_t;
161
162 typedef struct sleep_modem_config {
163 struct {
164 void *phy_link;
165 union {
166 struct {
167 uint32_t modem_state_phy_done: 1;
168 uint32_t reserved: 31;
169 };
170 uint32_t flags;
171 };
172 } wifi;
173 } sleep_modem_config_t;
174
175 static sleep_modem_config_t s_sleep_modem = { .wifi.phy_link = NULL, .wifi.flags = 0 };
176
sleep_modem_wifi_modem_state_init(void)177 esp_err_t sleep_modem_wifi_modem_state_init(void)
178 {
179 esp_err_t err = ESP_OK;
180 phy_i2c_master_command_attribute_t cmd;
181
182 /* get RF on or off configuration info of i2c master command memory */
183 extern void phy_i2c_master_mem_cfg(phy_i2c_master_command_attribute_t *);
184 phy_i2c_master_mem_cfg(&cmd);
185
186 ESP_LOGD(TAG, "Modem link i2c master configuration: (%d,%d,%d), (%d,%d,%d)", cmd.config[0].host_id, cmd.config[0].start,
187 cmd.config[0].end, cmd.config[1].host_id, cmd.config[1].start, cmd.config[1].end);
188
189 static regdma_link_config_t wifi_modem_config[] = {
190 [0] = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_FE_LINK(0), MODEM_FE_DATA_BASE, MODEM_FE_DATA_BASE, 41, 0, 0),
191 [1] = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_FE_LINK(1), MODEM_FE_CTRL_BASE, MODEM_FE_CTRL_BASE, 87, 0, 0),
192
193 [2] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x00), MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN, MODEM_LPCON_CLK_I2C_MST_EN_M, 1, 0), /* I2C MST enable */
194 [3] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x01), MODEM_LPCON_I2C_MST_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_SEL_160M, MODEM_LPCON_CLK_I2C_MST_SEL_160M_M, 1, 0), /* I2C MST sel 160m enable */
195
196 /* PMU or software to trigger enable RF PHY */
197 [4] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x02), I2C_ANA_MST_ANA_CONF0_REG, 0x8, 0xc, 1, 0), /* BBPLL calibration enable */
198 [5] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x03), PMU_RF_PWR_REG, 0xf0000000, 0xf0000000, 1, 0),
199 [6] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x04), SARADC_TSENS_REG, SARADC_TSENS_PU, 0x400000, 1, 0),
200 [7] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x05), I2C_ANA_MST_I2C_BURST_CONF_REG, 0, 0xffffffff, 1, 0),
201 [8] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x06), I2C_ANA_MST_I2C_BURST_STATUS_REG, I2C_ANA_MST_BURST_DONE, 0x1, 1, 0),
202 [9] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x07), FECOEX_SET_FREQ_SET_CHAN_REG, FECOEX_SET_CHAN_EN, 0x4000, 1, 0),
203 [10] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x08), FECOEX_SET_FREQ_SET_CHAN_REG, 0, 0x4000, 1, 0),
204 [11] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x09), FECOEX_SET_FREQ_SET_CHAN_ST_REG, FECOEX_SET_CHAN_DONE, 0x100, 1, 0),
205 [12] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0a), MODEM_SYSCON_WIFI_BB_CFG_REG, BIT(1), 0x2, 1, 0),
206 [13] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0b), FECOEX_AGC_CONF_REG, 0, 0x20000000, 1, 0),
207
208 /* PMU to trigger enable RXBLOCK */
209 [14] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0c), WDEVTXQ_BLOCK, 0, 0x1000, 1, 0),
210
211 /* PMU or software to trigger disable RF PHY */
212 [15] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0d), FECOEX_AGC_CONF_REG, FECOEX_AGC_DIS, 0x20000000, 0, 1),
213 [16] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0e), MODEM_SYSCON_WIFI_BB_CFG_REG, 0, 0x2, 0, 1),
214 [17] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0f), FECOEX_SET_FREQ_SET_CHAN_REG, 0, 0x4000, 0, 1),
215 [18] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x10), I2C_ANA_MST_I2C_BURST_CONF_REG, 0, 0xffffffff, 0, 1),
216 [19] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x11), I2C_ANA_MST_I2C_BURST_STATUS_REG, I2C_ANA_MST_BURST_DONE, 0x1, 0, 1),
217 [20] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x12), SARADC_TSENS_REG, 0, 0x400000, 0, 1),
218 [21] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x13), PMU_RF_PWR_REG, 0, 0xf0000000, 0, 1),
219 [22] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x14), I2C_ANA_MST_ANA_CONF0_REG, 0x4, 0xc, 0, 1), /* BBPLL calibration disable */
220
221 [23] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x15), MODEM_LPCON_CLK_CONF_REG, 0, MODEM_LPCON_CLK_I2C_MST_EN_M, 0, 1), /* I2C MST disable */
222
223 /* PMU to trigger disable RXBLOCK */
224 [24] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x17), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1),
225 [25] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x18), WDEVTXQ_BLOCK, WDEV_RXBLOCK, 0x1000, 0, 1),
226 [26] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x19), WDEVTXQ_BLOCK, 0, 0x6000, 0, 1),
227
228 [27] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1a), PMU_SLP_WAKEUP_CNTL7_REG, 0x200000, 0xffff0000, 1, 0),
229 [28] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1b), PMU_SLP_WAKEUP_CNTL7_REG, 0x9730000, 0xffff0000, 0, 1)
230 };
231 wifi_modem_config[7].write_wait.value = I2C_BURST_VAL(cmd.config[1].host_id, cmd.config[1].start, cmd.config[1].end);
232 wifi_modem_config[18].write_wait.value = I2C_BURST_VAL(cmd.config[0].host_id, cmd.config[0].start, cmd.config[0].end);
233
234 void *link = NULL;
235 if (s_sleep_modem.wifi.phy_link == NULL) {
236 for (int i = ARRAY_SIZE(wifi_modem_config) - 1; (err == ESP_OK) && (i >= 0); i--) {
237 void *next = regdma_link_init_safe(&wifi_modem_config[i], false, 0, link);
238 if (next) {
239 link = next;
240 } else {
241 regdma_link_destroy(link, 0);
242 err = ESP_ERR_NO_MEM;
243 }
244 }
245 if (err == ESP_OK) {
246 pau_regdma_set_modem_link_addr(link);
247 s_sleep_modem.wifi.phy_link = link;
248 s_sleep_modem.wifi.flags = 0;
249 }
250 }
251 return err;
252 }
253
sleep_modem_wifi_modem_state_deinit(void)254 __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void)
255 {
256 if (s_sleep_modem.wifi.phy_link) {
257 regdma_link_destroy(s_sleep_modem.wifi.phy_link, 0);
258 s_sleep_modem.wifi.phy_link = NULL;
259 s_sleep_modem.wifi.flags = 0;
260 }
261 }
262
sleep_modem_wifi_do_phy_retention(bool restore)263 void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore)
264 {
265 if (restore) {
266 pau_regdma_trigger_modem_link_restore();
267 } else {
268 pau_regdma_trigger_modem_link_backup();
269 s_sleep_modem.wifi.modem_state_phy_done = 1;
270 }
271 }
272
sleep_modem_wifi_modem_state_enabled(void)273 inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_state_enabled(void)
274 {
275 return (s_sleep_modem.wifi.phy_link != NULL);
276 }
277
sleep_modem_wifi_modem_link_done(void)278 inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_link_done(void)
279 {
280 return (s_sleep_modem.wifi.modem_state_phy_done == 1);
281 }
282
283 #endif /* SOC_PM_SUPPORT_PMU_MODEM_STATE */
284
modem_domain_pd_allowed(void)285 bool IRAM_ATTR modem_domain_pd_allowed(void)
286 {
287 #if SOC_PM_MODEM_RETENTION_BY_REGDMA
288 const uint32_t inited_modules = sleep_retention_get_inited_modules();
289 const uint32_t created_modules = sleep_retention_get_created_modules();
290
291 uint32_t mask = 0;
292 #if SOC_WIFI_SUPPORTED
293 mask |= BIT(SLEEP_RETENTION_MODULE_WIFI_MAC) | BIT(SLEEP_RETENTION_MODULE_WIFI_BB);
294 #endif
295 #if SOC_BT_SUPPORTED
296 mask |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC) | BIT(SLEEP_RETENTION_MODULE_BT_BB);
297 #endif
298 #if SOC_IEEE802154_SUPPORTED
299 mask |= BIT(SLEEP_RETENTION_MODULE_802154_MAC) | BIT(SLEEP_RETENTION_MODULE_BT_BB);
300 #endif
301 return ((inited_modules & mask) == (created_modules & mask));
302 #else
303 return false; /* MODEM power domain is controlled by each module (WiFi, Bluetooth or 15.4) of modem */
304 #endif
305 }
306
sleep_modem_reject_triggers(void)307 uint32_t IRAM_ATTR sleep_modem_reject_triggers(void)
308 {
309 uint32_t reject_triggers = 0;
310 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
311 reject_triggers = (s_sleep_modem.wifi.phy_link != NULL) ? BIT(16) : 0;
312 #endif
313 return reject_triggers;
314 }
315
sleep_modem_wifi_modem_state_skip_light_sleep(void)316 bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_light_sleep(void)
317 {
318 bool skip = false;
319 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
320 /* To block the system from entering sleep before modem link done. In light
321 * sleep mode, the system may switch to modem state, which will cause
322 * hardware to fail to enable RF */
323 skip = sleep_modem_wifi_modem_state_enabled() && !sleep_modem_wifi_modem_link_done();
324 #endif
325 return skip;
326 }
327
sleep_modem_configure(int max_freq_mhz,int min_freq_mhz,bool light_sleep_enable)328 esp_err_t sleep_modem_configure(int max_freq_mhz, int min_freq_mhz, bool light_sleep_enable)
329 {
330 #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP
331 extern int esp_wifi_internal_light_sleep_configure(bool);
332 esp_wifi_internal_light_sleep_configure(light_sleep_enable);
333 #endif
334 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
335 if (light_sleep_enable) {
336 esp_pm_light_sleep_default_params_config(min_freq_mhz, max_freq_mhz);
337 }
338 #endif
339 return ESP_OK;
340 }
341
342 #define PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO 2
343
344 /* Inform peripherals of light sleep wakeup overhead time */
345 static inform_out_light_sleep_overhead_cb_t s_periph_inform_out_light_sleep_overhead_cb[PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO];
346
esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)347 esp_err_t esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
348 {
349 for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
350 if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
351 return ESP_OK;
352 } else if (s_periph_inform_out_light_sleep_overhead_cb[i] == NULL) {
353 s_periph_inform_out_light_sleep_overhead_cb[i] = cb;
354 return ESP_OK;
355 }
356 }
357 return ESP_ERR_NO_MEM;
358 }
359
esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)360 esp_err_t esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
361 {
362 for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
363 if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
364 s_periph_inform_out_light_sleep_overhead_cb[i] = NULL;
365 return ESP_OK;
366 }
367 }
368 return ESP_ERR_INVALID_STATE;
369 }
370
periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)371 void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)
372 {
373 for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
374 if (s_periph_inform_out_light_sleep_overhead_cb[i]) {
375 s_periph_inform_out_light_sleep_overhead_cb[i](out_light_sleep_time);
376 }
377 }
378 }
379
380 static update_light_sleep_default_params_config_cb_t s_light_sleep_default_params_config_cb = NULL;
381
esp_pm_register_light_sleep_default_params_config_callback(update_light_sleep_default_params_config_cb_t cb)382 void esp_pm_register_light_sleep_default_params_config_callback(update_light_sleep_default_params_config_cb_t cb)
383 {
384 if (s_light_sleep_default_params_config_cb == NULL) {
385 s_light_sleep_default_params_config_cb = cb;
386 }
387 }
388
esp_pm_unregister_light_sleep_default_params_config_callback(void)389 void esp_pm_unregister_light_sleep_default_params_config_callback(void)
390 {
391 if (s_light_sleep_default_params_config_cb) {
392 s_light_sleep_default_params_config_cb = NULL;
393 }
394 }
395
396 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
esp_pm_light_sleep_default_params_config(int min_freq_mhz,int max_freq_mhz)397 static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz)
398 {
399 if (s_light_sleep_default_params_config_cb) {
400 (*s_light_sleep_default_params_config_cb)(min_freq_mhz, max_freq_mhz);
401 }
402 }
403 #endif
404
405 #if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD
sleep_modem_register_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,mac_bb_power_up_cb_t pu_cb)406 void sleep_modem_register_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,
407 mac_bb_power_up_cb_t pu_cb)
408 {
409 _lock_acquire(&s_modem_prepare_lock);
410 if (s_modem_prepare_ref++ == 0) {
411 esp_register_mac_bb_pd_callback(pd_cb);
412 esp_register_mac_bb_pu_callback(pu_cb);
413 }
414 _lock_release(&s_modem_prepare_lock);
415 }
416
sleep_modem_unregister_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,mac_bb_power_up_cb_t pu_cb)417 void sleep_modem_unregister_mac_bb_module_prepare_callback(mac_bb_power_down_cb_t pd_cb,
418 mac_bb_power_up_cb_t pu_cb)
419 {
420 _lock_acquire(&s_modem_prepare_lock);
421 assert(s_modem_prepare_ref);
422 if (--s_modem_prepare_ref == 0) {
423 esp_unregister_mac_bb_pd_callback(pd_cb);
424 esp_unregister_mac_bb_pu_callback(pu_cb);
425 }
426 _lock_release(&s_modem_prepare_lock);
427
428 }
429
430 /**
431 * @brief Switch root clock source to PLL do retention and switch back
432 *
433 * This function is used when Bluetooth/IEEE802154 module requires register backup/restore, this function
434 * is called ONLY when SOC_PM_RETENTION_HAS_CLOCK_BUG is set.
435 * @param backup true for backup, false for restore
436 * @param cpu_freq_mhz cpu frequency to do retention
437 * @param do_retention function for retention
438 */
rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(bool backup,int cpu_freq_mhz,void (* do_retention)(bool))439 static void IRAM_ATTR rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(bool backup, int cpu_freq_mhz, void (*do_retention)(bool))
440 {
441 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
442 if (pmu_sleep_pll_already_enabled()) {
443 return;
444 }
445 #endif
446 rtc_cpu_freq_config_t config, pll_config;
447 rtc_clk_cpu_freq_get_config(&config);
448
449 rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &pll_config);
450 rtc_clk_cpu_freq_set_config(&pll_config);
451
452 if (do_retention) {
453 (*do_retention)(backup);
454 }
455
456 rtc_clk_cpu_freq_set_config(&config);
457 }
458
sleep_modem_mac_bb_power_down_prepare(void)459 void IRAM_ATTR sleep_modem_mac_bb_power_down_prepare(void)
460 {
461 if (s_modem_sleep == false) {
462 rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(true,
463 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
464 sleep_retention_do_extra_retention);
465 s_modem_sleep = true;
466 }
467 }
468
sleep_modem_mac_bb_power_up_prepare(void)469 void IRAM_ATTR sleep_modem_mac_bb_power_up_prepare(void)
470 {
471 if (s_modem_sleep) {
472 rtc_clk_cpu_freq_to_pll_mhz_and_do_retention(false,
473 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
474 sleep_retention_do_extra_retention);
475 s_modem_sleep = false;
476 }
477 }
478 #endif /* SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD */
479