sleep_modem.c 15 KB

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