1 /*
2  * SPDX-FileCopyrightText: 2015-2021 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 #endif
32 
33 static __attribute__((unused)) const char *TAG = "sleep_modem";
34 
35 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
36 static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz);
37 #endif
38 
39 #if CONFIG_MAC_BB_PD
40 #define MAC_BB_POWER_DOWN_CB_NO     (2)
41 #define MAC_BB_POWER_UP_CB_NO       (2)
42 
43 static DRAM_ATTR mac_bb_power_down_cb_t s_mac_bb_power_down_cb[MAC_BB_POWER_DOWN_CB_NO];
44 static DRAM_ATTR mac_bb_power_up_cb_t   s_mac_bb_power_up_cb[MAC_BB_POWER_UP_CB_NO];
45 
esp_register_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)46 esp_err_t esp_register_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
47 {
48     int index = MAC_BB_POWER_DOWN_CB_NO;
49     for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
50         if (s_mac_bb_power_down_cb[i] == cb) {
51             return ESP_OK;
52         }
53 
54         if (s_mac_bb_power_down_cb[i] == NULL) {
55             index = i;
56         }
57     }
58 
59     if (index < MAC_BB_POWER_DOWN_CB_NO) {
60         s_mac_bb_power_down_cb[index] = cb;
61         return ESP_OK;
62     }
63 
64     return ESP_ERR_NO_MEM;
65 }
66 
esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)67 esp_err_t esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
68 {
69     for (int i = MAC_BB_POWER_DOWN_CB_NO - 1; i >= 0; i--) {
70         if (s_mac_bb_power_down_cb[i] == cb) {
71             s_mac_bb_power_down_cb[i] = NULL;
72             return ESP_OK;
73         }
74     }
75     return ESP_ERR_INVALID_STATE;
76 }
77 
mac_bb_power_down_cb_execute(void)78 void IRAM_ATTR mac_bb_power_down_cb_execute(void)
79 {
80     for (int i = 0; i < MAC_BB_POWER_DOWN_CB_NO; i++) {
81         if (s_mac_bb_power_down_cb[i]) {
82             s_mac_bb_power_down_cb[i]();
83         }
84     }
85 }
86 
esp_register_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)87 esp_err_t esp_register_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
88 {
89     int index = MAC_BB_POWER_UP_CB_NO;
90     for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
91         if (s_mac_bb_power_up_cb[i] == cb) {
92             return ESP_OK;
93         }
94 
95         if (s_mac_bb_power_up_cb[i] == NULL) {
96             index = i;
97         }
98     }
99 
100     if (index < MAC_BB_POWER_UP_CB_NO) {
101         s_mac_bb_power_up_cb[index] = cb;
102         return ESP_OK;
103     }
104 
105     return ESP_ERR_NO_MEM;
106 }
107 
esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)108 esp_err_t esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
109 {
110     for (int i = MAC_BB_POWER_UP_CB_NO - 1; i >= 0; i--) {
111         if (s_mac_bb_power_up_cb[i] == cb) {
112             s_mac_bb_power_up_cb[i] = NULL;
113             return ESP_OK;
114         }
115     }
116     return ESP_ERR_INVALID_STATE;
117 }
118 
mac_bb_power_up_cb_execute(void)119 void IRAM_ATTR mac_bb_power_up_cb_execute(void)
120 {
121     for (int i = 0; i < MAC_BB_POWER_UP_CB_NO; i++) {
122         if (s_mac_bb_power_up_cb[i]) {
123             s_mac_bb_power_up_cb[i]();
124         }
125     }
126 }
127 
128 #endif ///CONFIG_MAC_BB_PD
129 
130 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
131 
132 #define PMU_RF_PWR_REG                  (0x600b0154)
133 #define SARADC_TSENS_REG                (0x6000e058)
134 #define SARADC_TSENS_PU                 (BIT(22))
135 #define FECOEX_SET_FREQ_SET_CHAN_REG    (0x600a00c0)
136 #define FECOEX_SET_CHAN_EN              (BIT(14))
137 #define FECOEX_SET_FREQ_SET_CHAN_ST_REG (0x600a00cc)
138 #define FECOEX_SET_CHAN_DONE            (BIT(8))
139 #define FECOEX_AGC_CONF_REG             (0x600a7030)
140 #define FECOEX_AGC_DIS                  (BIT(29))
141 #define WDEVTXQ_BLOCK                   (0x600A4ca8)
142 #define WDEV_RXBLOCK                    (BIT(12))
143 #define MODEM_FE_DATA_BASE              (0x600a0400)
144 #define MODEM_FE_CTRL_BASE              (0x600a0800)
145 
146 #define I2C_BURST_VAL(host, start, end) (((host) << 31) | ((end) << 22) | ((start) << 16))
147 
148 typedef struct {
149     struct {
150         uint8_t start, end; /* the start and end index of phy i2c master command memory */
151         uint8_t host_id;    /* phy i2c master host id */
152     } config[2];
153 } phy_i2c_master_command_attribute_t;
154 
155 typedef struct sleep_modem_config {
156     struct {
157         void    *phy_link;
158         union {
159             struct {
160                 uint32_t modem_state_phy_done: 1;
161                 uint32_t reserved: 31;
162             };
163             uint32_t flags;
164         };
165     } wifi;
166 } sleep_modem_config_t;
167 
168 static sleep_modem_config_t s_sleep_modem = { .wifi.phy_link = NULL, .wifi.flags = 0 };
169 
sleep_modem_wifi_modem_state_init(void)170 static __attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void)
171 {
172     esp_err_t err = ESP_OK;
173     phy_i2c_master_command_attribute_t cmd;
174 
175     /* get RF on or off configuration info of i2c master command memory */
176     extern void phy_i2c_master_mem_cfg(phy_i2c_master_command_attribute_t *);
177     phy_i2c_master_mem_cfg(&cmd);
178 
179     ESP_LOGD(TAG, "Modem link i2c master configuration: (%d,%d,%d), (%d,%d,%d)", cmd.config[0].host_id, cmd.config[0].start,
180             cmd.config[0].end, cmd.config[1].host_id, cmd.config[1].start, cmd.config[1].end);
181 
182     static regdma_link_config_t wifi_modem_config[] = {
183         [0] = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_FE_LINK(0), MODEM_FE_DATA_BASE, MODEM_FE_DATA_BASE, 41, 0, 0),
184         [1] = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_FE_LINK(1), MODEM_FE_CTRL_BASE, MODEM_FE_CTRL_BASE, 87, 0, 0),
185 
186         [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 */
187         [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 */
188 
189         /* PMU or software to trigger enable RF PHY */
190         [4]  = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x02), I2C_ANA_MST_ANA_CONF0_REG,        0x8,                       0xc,        1, 0), /* BBPLL calibration enable */
191         [5]  = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x03), PMU_RF_PWR_REG,                   0xf0000000,                0xf0000000, 1, 0),
192         [6]  = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x04), SARADC_TSENS_REG,                 SARADC_TSENS_PU,           0x400000,   1, 0),
193         [7]  = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x05), I2C_ANA_MST_I2C_BURST_CONF_REG,   0,                         0xffffffff, 1, 0),
194         [8]  = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x06), I2C_ANA_MST_I2C_BURST_STATUS_REG, I2C_ANA_MST_BURST_DONE,    0x1,        1, 0),
195         [9]  = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x07), FECOEX_SET_FREQ_SET_CHAN_REG,     FECOEX_SET_CHAN_EN,        0x4000,     1, 0),
196         [10] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x08), FECOEX_SET_FREQ_SET_CHAN_REG,     0,                         0x4000,     1, 0),
197         [11] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x09), FECOEX_SET_FREQ_SET_CHAN_ST_REG,  FECOEX_SET_CHAN_DONE,      0x100,      1, 0),
198         [12] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0a), MODEM_SYSCON_WIFI_BB_CFG_REG,     BIT(1),                    0x2,        1, 0),
199         [13] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0b), FECOEX_AGC_CONF_REG,              0,                         0x20000000, 1, 0),
200 
201         /* PMU to trigger enable RXBLOCK */
202         [14] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0c), WDEVTXQ_BLOCK,                    0,                         0x1000,     1, 0),
203 
204         /* PMU or software to trigger disable RF PHY */
205         [15] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0d), FECOEX_AGC_CONF_REG,              FECOEX_AGC_DIS,            0x20000000, 0, 1),
206         [16] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0e), MODEM_SYSCON_WIFI_BB_CFG_REG,     0,                         0x2,        0, 1),
207         [17] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x0f), FECOEX_SET_FREQ_SET_CHAN_REG,     0,                         0x4000,     0, 1),
208         [18] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x10), I2C_ANA_MST_I2C_BURST_CONF_REG,   0,                         0xffffffff, 0, 1),
209         [19] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x11), I2C_ANA_MST_I2C_BURST_STATUS_REG, I2C_ANA_MST_BURST_DONE,    0x1,        0, 1),
210         [20] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x12), SARADC_TSENS_REG,                 0,                         0x400000,   0, 1),
211         [21] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x13), PMU_RF_PWR_REG,                   0,                         0xf0000000, 0, 1),
212         [22] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x14), I2C_ANA_MST_ANA_CONF0_REG,        0x4,                       0xc,        0, 1), /* BBPLL calibration disable */
213 
214         [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 */
215 
216         /* PMU to trigger disable RXBLOCK */
217         [24] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x17), WDEVTXQ_BLOCK,                    0,                         0x6000,     0, 1),
218         [25] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x18), WDEVTXQ_BLOCK,                    WDEV_RXBLOCK,              0x1000,     0, 1),
219         [26] = REGDMA_LINK_WAIT_INIT (REGDMA_PHY_LINK(0x19), WDEVTXQ_BLOCK,                    0,                         0x6000,     0, 1),
220 
221         [27] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1a), PMU_SLP_WAKEUP_CNTL7_REG,         0x200000,                  0xffff0000, 1, 0),
222         [28] = REGDMA_LINK_WRITE_INIT(REGDMA_PHY_LINK(0x1b), PMU_SLP_WAKEUP_CNTL7_REG,         0x9730000,                 0xffff0000, 0, 1)
223     };
224     wifi_modem_config[7].write_wait.value  = I2C_BURST_VAL(cmd.config[1].host_id, cmd.config[1].start, cmd.config[1].end);
225     wifi_modem_config[18].write_wait.value = I2C_BURST_VAL(cmd.config[0].host_id, cmd.config[0].start, cmd.config[0].end);
226 
227     void *link = NULL;
228     if (s_sleep_modem.wifi.phy_link == NULL) {
229         for (int i = ARRAY_SIZE(wifi_modem_config) - 1; (err == ESP_OK) && (i >= 0); i--) {
230             void *next = regdma_link_init_safe(&wifi_modem_config[i], false, 0, link);
231             if (next) {
232                 link = next;
233             } else {
234                 regdma_link_destroy(link, 0);
235                 err = ESP_ERR_NO_MEM;
236             }
237         }
238         if (err == ESP_OK) {
239             pau_regdma_set_modem_link_addr(link);
240             s_sleep_modem.wifi.phy_link = link;
241             s_sleep_modem.wifi.flags = 0;
242         }
243     }
244     return err;
245 }
246 
sleep_modem_wifi_modem_state_deinit(void)247 static __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void)
248 {
249     if (s_sleep_modem.wifi.phy_link) {
250         regdma_link_destroy(s_sleep_modem.wifi.phy_link, 0);
251         s_sleep_modem.wifi.phy_link = NULL;
252         s_sleep_modem.wifi.flags = 0;
253     }
254 }
255 
sleep_modem_wifi_do_phy_retention(bool restore)256 void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore)
257 {
258     if (restore) {
259         pau_regdma_trigger_modem_link_restore();
260     } else {
261         pau_regdma_trigger_modem_link_backup();
262         s_sleep_modem.wifi.modem_state_phy_done = 1;
263     }
264 }
265 
sleep_modem_wifi_modem_state_enabled(void)266 inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_state_enabled(void)
267 {
268     return (s_sleep_modem.wifi.phy_link != NULL);
269 }
270 
sleep_modem_wifi_modem_link_done(void)271 inline __attribute__((always_inline)) bool sleep_modem_wifi_modem_link_done(void)
272 {
273     return (s_sleep_modem.wifi.modem_state_phy_done == 1);
274 }
275 
276 #endif /* SOC_PM_SUPPORT_PMU_MODEM_STATE */
277 
modem_domain_pd_allowed(void)278 bool IRAM_ATTR modem_domain_pd_allowed(void)
279 {
280 #if SOC_PM_MODEM_RETENTION_BY_REGDMA
281     const uint32_t modules = sleep_retention_get_modules();
282     const uint32_t mask_wifi = (const uint32_t) (SLEEP_RETENTION_MODULE_WIFI_MAC |
283                                                  SLEEP_RETENTION_MODULE_WIFI_BB);
284     const uint32_t mask_ble = (const uint32_t) (SLEEP_RETENTION_MODULE_BLE_MAC |
285                                                 SLEEP_RETENTION_MODULE_BT_BB);
286     const uint32_t mask_154 = (const uint32_t) (SLEEP_RETENTION_MODULE_802154_MAC |
287                                                 SLEEP_RETENTION_MODULE_BT_BB);
288     return (((modules & mask_wifi) == mask_wifi) ||
289             ((modules & mask_ble)  == mask_ble) ||
290             ((modules & mask_154)  == mask_154));
291 #else
292     return false; /* MODEM power domain is controlled by each module (WiFi, Bluetooth or 15.4) of modem */
293 #endif
294 }
295 
sleep_modem_reject_triggers(void)296 uint32_t IRAM_ATTR sleep_modem_reject_triggers(void)
297 {
298     uint32_t reject_triggers = 0;
299 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
300     reject_triggers = (s_sleep_modem.wifi.phy_link != NULL) ? BIT(16) : 0;
301 #endif
302     return reject_triggers;
303 }
304 
sleep_modem_wifi_modem_state_skip_light_sleep(void)305 static __attribute__((unused)) bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_light_sleep(void)
306 {
307     bool skip = false;
308 #if SOC_PM_SUPPORT_PMU_MODEM_STATE
309     /* To block the system from entering sleep before modem link done. In light
310      * sleep mode, the system may switch to modem state, which will cause
311      * hardware to fail to enable RF */
312     skip = sleep_modem_wifi_modem_state_enabled() && !sleep_modem_wifi_modem_link_done();
313 #endif
314     return skip;
315 }
316 
sleep_modem_configure(int max_freq_mhz,int min_freq_mhz,bool light_sleep_enable)317 esp_err_t sleep_modem_configure(int max_freq_mhz, int min_freq_mhz, bool light_sleep_enable)
318 {
319 #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP
320     extern int esp_wifi_internal_mac_sleep_configure(bool, bool);
321     if (light_sleep_enable) {
322         if (sleep_modem_wifi_modem_state_init() == ESP_OK) {
323             esp_pm_register_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep);
324             esp_wifi_internal_mac_sleep_configure(light_sleep_enable, true); /* require WiFi to enable automatically receives the beacon */
325         }
326     } else {
327         esp_wifi_internal_mac_sleep_configure(light_sleep_enable, false); /* require WiFi to disable automatically receives the beacon */
328         esp_pm_unregister_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep);
329         sleep_modem_wifi_modem_state_deinit();
330     }
331 #endif
332 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
333     if (light_sleep_enable) {
334         esp_pm_light_sleep_default_params_config(min_freq_mhz, max_freq_mhz);
335     }
336 #endif
337     return ESP_OK;
338 }
339 
340 #define PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO 1
341 
342 /* Inform peripherals of light sleep wakeup overhead time */
343 static inform_out_light_sleep_overhead_cb_t s_periph_inform_out_light_sleep_overhead_cb[PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO];
344 
esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)345 esp_err_t esp_pm_register_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
346 {
347     for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
348         if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
349             return ESP_OK;
350         } else if (s_periph_inform_out_light_sleep_overhead_cb[i] == NULL) {
351             s_periph_inform_out_light_sleep_overhead_cb[i] = cb;
352             return ESP_OK;
353         }
354     }
355     return ESP_ERR_NO_MEM;
356 }
357 
esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)358 esp_err_t esp_pm_unregister_inform_out_light_sleep_overhead_callback(inform_out_light_sleep_overhead_cb_t cb)
359 {
360     for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
361         if (s_periph_inform_out_light_sleep_overhead_cb[i] == cb) {
362             s_periph_inform_out_light_sleep_overhead_cb[i] = NULL;
363             return ESP_OK;
364         }
365     }
366     return ESP_ERR_INVALID_STATE;
367 }
368 
periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)369 void periph_inform_out_light_sleep_overhead(uint32_t out_light_sleep_time)
370 {
371     for (int i = 0; i < PERIPH_INFORM_OUT_LIGHT_SLEEP_OVERHEAD_NO; i++) {
372         if (s_periph_inform_out_light_sleep_overhead_cb[i]) {
373             s_periph_inform_out_light_sleep_overhead_cb[i](out_light_sleep_time);
374         }
375     }
376 }
377 
378 static update_light_sleep_default_params_config_cb_t s_light_sleep_default_params_config_cb = NULL;
379 
esp_pm_register_light_sleep_default_params_config_callback(update_light_sleep_default_params_config_cb_t cb)380 void esp_pm_register_light_sleep_default_params_config_callback(update_light_sleep_default_params_config_cb_t cb)
381 {
382     if (s_light_sleep_default_params_config_cb == NULL) {
383         s_light_sleep_default_params_config_cb = cb;
384     }
385 }
386 
esp_pm_unregister_light_sleep_default_params_config_callback(void)387 void esp_pm_unregister_light_sleep_default_params_config_callback(void)
388 {
389     if (s_light_sleep_default_params_config_cb) {
390         s_light_sleep_default_params_config_cb = NULL;
391     }
392 }
393 
394 #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT
esp_pm_light_sleep_default_params_config(int min_freq_mhz,int max_freq_mhz)395 static void esp_pm_light_sleep_default_params_config(int min_freq_mhz, int max_freq_mhz)
396 {
397     if (s_light_sleep_default_params_config_cb) {
398         (*s_light_sleep_default_params_config_cb)(min_freq_mhz, max_freq_mhz);
399     }
400 }
401 #endif
402