Refactor Bluetooth sleep mechanism

Refactor bluetooth hardware PowerUp/PowerDown functions

component/bt: fix use of a deprecated MACRO "CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE"

component/bt: fix sleep wakeup in controller disable procedure

remove use of s_pm_lock_sem

1. Modified the waking up approach from async to sync: post a message to controller task upon vhci downstream packets or controller disable, and in response, controller task goes through the wake-up procedure
2. Added Controller status check for the esp_vhci APIs
3. Adjust the procedure during controller_init, check the validity of arguments first

Some minor modifications for bluetooth sleep control and configuration

1. use variable flag s_btdm_allow_light_sleep to control the use of s_light_sleep_pm_lock
2. use variable btdm_lpclk_sel to choose bluetooth sleep clock, support only for external 32kHz crystal temporarily

component/bt: improve async_wakeup function

1. check power state first and then decide if wakeup needs to be performed
2. change the meaning of the return value, if wakeup request is posted to controller task, then return true, otherwise return false

put sleep control logics in controller init/deinit/enable/disable together

Use s_lp_cntl struct: replace bool-typed variable sleep_backup_en with s_lp_cntl.mac_bb_pd

Use s_lp_cntl struct: replace bool-typed variable s_btdm_allow_light_sleep with s_lp_cntl.no_light_sleep

Use s_lp_cntl struct: replace global variable btdm_lpclk_sel with s_lp_cntl.lpclk_sel

create semaphore s_wakeup_req_sem only when low power mode is required

Use s_lp_cntl struct: use s_lp_cntl.wakeup_timer_required to control the wakeup timer

use s_lp_stat to replace original state variable sleep_backup_done and s_pm_lock_acquired

one minor change for mac_bb_pd settings init: return error status if memeory allocation failed
This commit is contained in:
wangmengyang 2020-12-25 11:53:08 +08:00 committed by baohongde
parent 9742aa6f05
commit 086b36d737

View File

@ -61,6 +61,36 @@
#define BTDM_LPCLK_SEL_RTC_SLOW (2) #define BTDM_LPCLK_SEL_RTC_SLOW (2)
#define BTDM_LPCLK_SEL_8M (3) #define BTDM_LPCLK_SEL_8M (3)
// wakeup request sources
enum {
BTDM_ASYNC_WAKEUP_SRC_VHCI = 0,
BTDM_ASYNC_WAKEUP_SRC_DISA,
BTDM_ASYNC_WAKEUP_SRC_MAX,
};
// low power control struct
typedef union {
struct {
uint32_t enable : 1; // whether low power mode is required
uint32_t lpclk_sel : 2; // low power clock source
uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) force-power-down is required during sleep
uint32_t wakeup_timer_required : 1; // whether system timer is needed
uint32_t no_light_sleep : 1; // do not allow system to enter light sleep after bluetooth is enabled
uint32_t reserved : 26; // reserved
};
uint32_t val;
} btdm_lpcntl_t;
// low power control status
typedef union {
struct {
uint32_t pm_lock_released : 1; // whether power management lock is released
uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) is powered down
uint32_t reserved : 30; // reserved
};
uint32_t val;
} btdm_lpstat_t;
/* Sleep and wakeup interval control */ /* Sleep and wakeup interval control */
#define BTDM_MIN_SLEEP_DURATION (24) // threshold of interval in half slots to allow to fall into modem sleep #define BTDM_MIN_SLEEP_DURATION (24) // threshold of interval in half slots to allow to fall into modem sleep
#define BTDM_MODEM_WAKE_UP_DELAY (8) // delay in half slots of modem wake up procedure, including re-enable PHY/RF #define BTDM_MODEM_WAKE_UP_DELAY (8) // delay in half slots of modem wake up procedure, including re-enable PHY/RF
@ -200,8 +230,7 @@ extern void btdm_controller_enable_sleep(bool enable);
extern uint8_t btdm_controller_get_sleep_mode(void); extern uint8_t btdm_controller_get_sleep_mode(void);
extern bool btdm_power_state_active(void); extern bool btdm_power_state_active(void);
extern void btdm_wakeup_request(void); extern void btdm_wakeup_request(void);
extern void btdm_wakeup_request_start(void); extern void btdm_in_wakeup_requesting_set(bool in_wakeup_requesting);
extern void btdm_wakeup_request_end(void);
/* vendor dependent tasks to be posted and handled by controller task*/ /* vendor dependent tasks to be posted and handled by controller task*/
extern int btdm_vnd_offload_task_register(btdm_vnd_ol_sig_t sig, btdm_vnd_ol_task_func_t func); extern int btdm_vnd_offload_task_register(btdm_vnd_ol_sig_t sig, btdm_vnd_ol_task_func_t func);
@ -296,7 +325,6 @@ static uint32_t IRAM_ATTR btdm_hus_2_lpcycles(uint32_t hus);
static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *slot_cnt); static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *slot_cnt);
static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles); static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles);
static void btdm_sleep_enter_phase2_wrapper(void); static void btdm_sleep_enter_phase2_wrapper(void);
static void IRAM_ATTR btdm_sleep_exit_phase1_wrapper(void);
static void btdm_sleep_exit_phase3_wrapper(void); static void btdm_sleep_exit_phase3_wrapper(void);
static void coex_wifi_sleep_set_hook(bool sleep); static void coex_wifi_sleep_set_hook(bool sleep);
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status);
@ -351,7 +379,7 @@ static const struct osi_funcs_t osi_funcs_ro = {
._btdm_sleep_check_duration = btdm_sleep_check_duration, ._btdm_sleep_check_duration = btdm_sleep_check_duration,
._btdm_sleep_enter_phase1 = btdm_sleep_enter_phase1_wrapper, ._btdm_sleep_enter_phase1 = btdm_sleep_enter_phase1_wrapper,
._btdm_sleep_enter_phase2 = btdm_sleep_enter_phase2_wrapper, ._btdm_sleep_enter_phase2 = btdm_sleep_enter_phase2_wrapper,
._btdm_sleep_exit_phase1 = btdm_sleep_exit_phase1_wrapper, ._btdm_sleep_exit_phase1 = NULL,
._btdm_sleep_exit_phase2 = NULL, ._btdm_sleep_exit_phase2 = NULL,
._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper,
//._coex_bt_request = coex_bt_request_wrapper, //._coex_bt_request = coex_bt_request_wrapper,
@ -388,21 +416,21 @@ static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
static DRAM_ATTR uint32_t btdm_lpcycle_us = 0; static DRAM_ATTR uint32_t btdm_lpcycle_us = 0;
static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us
// low power control struct
static DRAM_ATTR btdm_lpcntl_t s_lp_cntl;
static DRAM_ATTR btdm_lpstat_t s_lp_stat;
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock;
static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; // pm_lock to prevent light sleep due to incompatibility currently static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; // pm_lock to prevent light sleep due to incompatibility currently
static DRAM_ATTR QueueHandle_t s_pm_lock_sem = NULL;
#endif #endif
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) // used low power clock
static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL;
// wakeup timer
static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr; static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr;
static void btdm_slp_tmr_callback(void *arg);
#endif
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB static void btdm_slp_tmr_callback(void *arg);
static bool sleep_backup_en = false;
static bool sleep_backup_done = false;
#endif
static inline void btdm_check_and_init_bb(void) static inline void btdm_check_and_init_bb(void)
{ {
@ -413,6 +441,10 @@ static inline void btdm_check_and_init_bb(void)
void btdm_hw_mac_power_down_wrapper(void) void btdm_hw_mac_power_down_wrapper(void)
{ {
#if CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #if CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
// le module power down
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO);
SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD);
esp_mac_bb_power_down(); esp_mac_bb_power_down();
#endif #endif
} }
@ -420,6 +452,10 @@ void btdm_hw_mac_power_down_wrapper(void)
void btdm_hw_mac_power_up_wrapper(void) void btdm_hw_mac_power_up_wrapper(void)
{ {
#if CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #if CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
// le module power up
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD);
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO);
esp_mac_bb_power_up(); esp_mac_bb_power_up();
#endif #endif
} }
@ -822,17 +858,6 @@ static int IRAM_ATTR rand_wrapper(void)
return (int)esp_random(); return (int)esp_random();
} }
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles)
{
// The number of lp cycles should not lead to overflow. Thrs: 100s
// clock measurement is conducted
uint64_t us = (uint64_t)btdm_lpcycle_us * cycles;
us = (us + (1 << (btdm_lpcycle_us_frac - 1))) >> btdm_lpcycle_us_frac;
return (uint32_t)us;
}
#endif
static uint32_t IRAM_ATTR btdm_lpcycles_2_hus(uint32_t cycles, uint32_t *error_corr) static uint32_t IRAM_ATTR btdm_lpcycles_2_hus(uint32_t cycles, uint32_t *error_corr)
{ {
uint64_t local_error_corr = (error_corr == NULL) ? 0 : (uint64_t)(*error_corr); uint64_t local_error_corr = (error_corr == NULL) ? 0 : (uint64_t)(*error_corr);
@ -872,9 +897,12 @@ static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *half_slot_cnt)
static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles) static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
{ {
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) if (s_lp_cntl.wakeup_timer_required == 0) {
return;
}
// start a timer to wake up and acquire the pm_lock before modem_sleep awakes // start a timer to wake up and acquire the pm_lock before modem_sleep awakes
uint32_t us_to_sleep = btdm_lpcycles_2_us(lpcycles); uint32_t us_to_sleep = btdm_lpcycles_2_hus(lpcycles, NULL) >> 1;
#define BTDM_MIN_TIMER_UNCERTAINTY_US (1800) #define BTDM_MIN_TIMER_UNCERTAINTY_US (1800)
assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US); assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US);
@ -888,7 +916,6 @@ static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) != ESP_OK) { if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) != ESP_OK) {
ESP_LOGW(BTDM_LOG_TAG, "timer start failed"); ESP_LOGW(BTDM_LOG_TAG, "timer start failed");
} }
#endif
} }
static void btdm_sleep_enter_phase2_wrapper(void) static void btdm_sleep_enter_phase2_wrapper(void)
@ -898,29 +925,22 @@ static void btdm_sleep_enter_phase2_wrapper(void)
esp_phy_disable(); esp_phy_disable();
#endif /* BTDM_MODEM_SLEEP_IN_EFFECT */ #endif /* BTDM_MODEM_SLEEP_IN_EFFECT */
if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd == 0) {
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) #if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
if(sleep_backup_en) { btdm_ble_power_down_dma_copy(true);
btdm_ble_power_down_dma_copy(true);
sleep_backup_done = true;
}
#endif #endif
s_lp_stat.mac_bb_pd = 1;
}
if (s_lp_stat.pm_lock_released == 0) {
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock); esp_pm_lock_release(s_pm_lock);
semphr_give_wrapper(s_pm_lock_sem);
#endif #endif
s_lp_stat.pm_lock_released = 1;
}
} }
} }
static void IRAM_ATTR btdm_sleep_exit_phase1_wrapper(void)
{
#ifdef CONFIG_PM_ENABLE
if (semphr_take_from_isr_wrapper(s_pm_lock_sem, NULL) == pdTRUE) {
esp_pm_lock_acquire(s_pm_lock);
}
#endif
}
static void btdm_sleep_exit_phase3_wrapper(void) static void btdm_sleep_exit_phase3_wrapper(void)
{ {
if(btdm_sleep_clock_sync()) { if(btdm_sleep_clock_sync()) {
@ -932,35 +952,94 @@ static void btdm_sleep_exit_phase3_wrapper(void)
esp_phy_enable(); esp_phy_enable();
#endif /* BTDM_MODEM_SLEEP_IN_EFFECT */ #endif /* BTDM_MODEM_SLEEP_IN_EFFECT */
btdm_check_and_init_bb(); btdm_check_and_init_bb();
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
esp_timer_stop(s_btdm_slp_tmr); if (s_lp_cntl.wakeup_timer_required) {
#endif esp_timer_stop(s_btdm_slp_tmr);
}
} }
} }
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
static void IRAM_ATTR btdm_sleep_exit_phase0(void *param) static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
{ {
assert(s_lp_cntl.enable == 1);
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if (semphr_take_wrapper(s_pm_lock_sem, 0) == pdTRUE) { if (s_lp_stat.pm_lock_released) {
esp_pm_lock_acquire(s_pm_lock); esp_pm_lock_acquire(s_pm_lock);
s_lp_stat.pm_lock_released = 0;
} }
#endif #endif
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
if (sleep_backup_en && sleep_backup_done) { if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd) {
btdm_ble_power_down_dma_copy(false); btdm_ble_power_down_dma_copy(false);
sleep_backup_done = false; s_lp_stat.mac_bb_pd = 0;
} }
#endif #endif
btdm_wakeup_request();
int event = (int) param;
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
semphr_give_wrapper(s_wakeup_req_sem);
}
} }
static void IRAM_ATTR btdm_slp_tmr_callback(void *arg) static void IRAM_ATTR btdm_slp_tmr_callback(void *arg)
{ {
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
btdm_vnd_offload_post_from_isr(BTDM_VND_OL_SIG_WAKEUP_TMR, NULL, false); btdm_vnd_offload_post_from_isr(BTDM_VND_OL_SIG_WAKEUP_TMR, NULL, false);
esp_timer_isr_dispatch_need_yield(); esp_timer_isr_dispatch_need_yield();
}
#endif #endif
}
static bool async_wakeup_request(int event)
{
if (s_lp_cntl.enable == 0) {
return false;
}
bool do_wakeup_request = false;
switch (event) {
case BTDM_ASYNC_WAKEUP_SRC_VHCI:
case BTDM_ASYNC_WAKEUP_SRC_DISA:
btdm_in_wakeup_requesting_set(true);
if (!btdm_power_state_active()) {
btdm_vnd_offload_post(BTDM_VND_OL_SIG_WAKEUP_TMR, (void *)event);
do_wakeup_request = true;
semphr_take_wrapper(s_wakeup_req_sem, OSI_FUNCS_TIME_BLOCKING);
}
break;
default:
break;
}
return do_wakeup_request;
}
static void async_wakeup_request_end(int event)
{
if (s_lp_cntl.enable == 0) {
return;
}
bool allow_to_sleep;
switch (event) {
case BTDM_ASYNC_WAKEUP_SRC_VHCI:
case BTDM_ASYNC_WAKEUP_SRC_DISA:
allow_to_sleep = true;
break;
default:
allow_to_sleep = true;
break;
}
if (allow_to_sleep) {
btdm_in_wakeup_requesting_set(false);
}
return;
}
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status)
{ {
@ -978,38 +1057,29 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
bool esp_vhci_host_check_send_available(void) bool esp_vhci_host_check_send_available(void)
{ {
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return false;
}
return API_vhci_host_check_send_available(); return API_vhci_host_check_send_available();
} }
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{ {
btdm_wakeup_request_start(); if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
if (!btdm_power_state_active()) {
#if CONFIG_PM_ENABLE
if (semphr_take_wrapper(s_pm_lock_sem, 0)) {
esp_pm_lock_acquire(s_pm_lock);
}
#endif
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
esp_timer_stop(s_btdm_slp_tmr);
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
if (sleep_backup_en && sleep_backup_done) {
btdm_ble_power_down_dma_copy(false);
sleep_backup_done = false;
} }
#endif // CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_VHCI);
#endif
btdm_wakeup_request();
}
API_vhci_host_send_packet(data, len); API_vhci_host_send_packet(data, len);
btdm_wakeup_request_end(); async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_VHCI);
} }
esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{ {
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
return API_vhci_host_register_callback((const vhci_host_callback_t *)callback) == 0 ? ESP_OK : ESP_FAIL; return API_vhci_host_register_callback((const vhci_host_callback_t *)callback) == 0 ? ESP_OK : ESP_FAIL;
} }
@ -1054,45 +1124,18 @@ void esp_release_wifi_and_coex_mem(void)
esp_err_t esp_bluetooth_stop(void) esp_err_t esp_bluetooth_stop(void)
{ {
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
if (sleep_backup_en && sleep_backup_done) { if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd) {
btdm_hw_mac_power_up_wrapper(); btdm_hw_mac_power_up_wrapper();
// le module power up s_lp_stat.mac_bb_pd = 0;
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD);
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO);
sleep_backup_done = false;
} }
#endif #endif
return ESP_OK;
return 0;
} }
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
{ {
esp_err_t err; esp_err_t err;
btdm_controller_mem_init();
if (esp_register_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop) != 0) {
return ESP_ERR_INVALID_ARG;
}
osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t));
if (osi_funcs_p == NULL) {
return ESP_ERR_NO_MEM;
}
memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t));
if (btdm_osi_funcs_register(osi_funcs_p) != 0) {
return ESP_ERR_INVALID_ARG;
}
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
bool try_alloc = btdm_deep_sleep_mem_init();
if(try_alloc) {
sleep_backup_en = true;
}
#endif
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
@ -1107,9 +1150,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
//overwrite some parameters
cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL;
if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) {
ESP_LOGE(BTDM_LOG_TAG, "%s controller only support BLE only mode", __func__); ESP_LOGE(BTDM_LOG_TAG, "%s controller only support BLE only mode", __func__);
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
@ -1129,6 +1169,25 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
} }
} }
//overwrite some parameters
cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL;
btdm_controller_mem_init();
if (esp_register_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop) != 0) {
return ESP_ERR_INVALID_ARG;
}
osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t));
if (osi_funcs_p == NULL) {
return ESP_ERR_NO_MEM;
}
memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t));
if (btdm_osi_funcs_register(osi_funcs_p) != 0) {
return ESP_ERR_INVALID_ARG;
}
read_mac_wrapper(own_bda); read_mac_wrapper(own_bda);
ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version());
@ -1136,75 +1195,98 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
#if CONFIG_SPIRAM_USE_MALLOC #if CONFIG_SPIRAM_USE_MALLOC
btdm_queue_table_mux = xSemaphoreCreateMutex(); btdm_queue_table_mux = xSemaphoreCreateMutex();
if (btdm_queue_table_mux == NULL) { if (btdm_queue_table_mux == NULL) {
return ESP_ERR_NO_MEM; err = ESP_ERR_NO_MEM;
goto error;
} }
memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM); memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM);
#endif #endif
if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { // init low-power control resources
do {
// set default values for global states or resources
s_lp_stat.val = 0;
s_lp_cntl.val = 0;
s_wakeup_req_sem = NULL;
s_btdm_slp_tmr = NULL;
// configure and initialize resources
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
s_lp_cntl.no_light_sleep = 1;
if (s_lp_cntl.enable) {
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
if (!btdm_deep_sleep_mem_init()) {
goto error;
}
s_lp_cntl.mac_bb_pd = 1;
#endif
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
s_lp_cntl.wakeup_timer_required = 1;
#endif
// async wakeup semaphore for VHCI
s_wakeup_req_sem = semphr_create_wrapper(1, 0);
if (s_wakeup_req_sem == NULL) {
err = ESP_ERR_NO_MEM;
goto error;
}
btdm_vnd_offload_task_register(BTDM_VND_OL_SIG_WAKEUP_TMR, btdm_sleep_exit_phase0);
}
if (s_lp_cntl.wakeup_timer_required) {
esp_timer_create_args_t create_args = {
.callback = btdm_slp_tmr_callback,
.arg = NULL,
.dispatch_method = ESP_TIMER_ISR,
.name = "btSlp",
};
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
goto error;
}
}
// set default bluetooth sleep clock cycle and its fractional bits
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
// set default bluetooth sleep clock source
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
bool select_src_ret, set_div_ret;
if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) {
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
set_div_ret = btdm_lpclk_set_div(rtc_clk_xtal_freq_get() * 2);
assert(select_src_ret && set_div_ret);
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
} else {
ESP_LOGW(BTDM_LOG_TAG, "%s sleep clock not supported", __func__);
assert(0);
}
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { if (s_lp_cntl.no_light_sleep) {
goto error; if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) {
goto error;
}
} }
if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) {
goto error; goto error;
} } else {
s_pm_lock_sem = semphr_create_wrapper(1, 0); s_lp_stat.pm_lock_released = 1;
if (s_pm_lock_sem == NULL) {
err = ESP_ERR_NO_MEM;
goto error;
} }
#endif #endif
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) } while (0);
esp_timer_create_args_t create_args = {
.callback = btdm_slp_tmr_callback,
.arg = NULL,
.dispatch_method = ESP_TIMER_ISR,
.name = "btSlp",
};
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
goto error;
}
btdm_vnd_offload_task_register(BTDM_VND_OL_SIG_WAKEUP_TMR, btdm_sleep_exit_phase0);
#endif
do {// todo: rewrite this block of code for chip
#if CONFIG_IDF_ENV_FPGA
// overwrite the sleep clock for FPGA
cfg->sleep_clock = ESP_BT_SLEEP_CLOCK_FPGA_32K;
ESP_LOGW(BTDM_LOG_TAG, "%s sleep clock overwrite on FPGA", __func__);
#endif
bool select_src_ret = false;
bool set_div_ret = false;
if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) {
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
set_div_ret = btdm_lpclk_set_div(rtc_clk_xtal_freq_get() * 2);
assert(select_src_ret && set_div_ret);
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
} else if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) {
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K);
set_div_ret = btdm_lpclk_set_div(0);
assert(select_src_ret && set_div_ret);
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = esp_clk_slowclk_cal_get();
assert(btdm_lpcycle_us != 0);
} else if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_FPGA_32K) {
// on FPGA, the low power clock is hard-wired to a 32kHz(clock cycle 31.25us) oscillator
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 125 << (btdm_lpcycle_us_frac - 2);
}
} while (0);
}
#if CONFIG_SW_COEXIST_ENABLE #if CONFIG_SW_COEXIST_ENABLE
coex_init(); coex_init();
#endif #endif
periph_module_enable(PERIPH_BT_MODULE); periph_module_enable(PERIPH_BT_MODULE);
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
btdm_hw_mac_power_up_wrapper(); btdm_hw_mac_power_up_wrapper();
#endif #endif
// must do fpga_init and phy init before controller init
esp_phy_enable(); esp_phy_enable();
if (btdm_controller_init(cfg) != 0) { if (btdm_controller_init(cfg) != 0) {
@ -1217,33 +1299,42 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_OK; return ESP_OK;
error: error:
do {
// deinit low power control resources
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if (s_light_sleep_pm_lock != NULL) { if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_delete(s_light_sleep_pm_lock); if (s_light_sleep_pm_lock != NULL) {
s_light_sleep_pm_lock = NULL; esp_pm_lock_delete(s_light_sleep_pm_lock);
} s_light_sleep_pm_lock = NULL;
if (s_pm_lock != NULL) { }
esp_pm_lock_delete(s_pm_lock); }
s_pm_lock = NULL; if (s_pm_lock != NULL) {
} esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
s_lp_stat.pm_lock_released = 0;
}
if (s_pm_lock_sem) {
semphr_delete_wrapper(s_pm_lock_sem);
s_pm_lock_sem = NULL;
}
#endif
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
if (s_btdm_slp_tmr != NULL) {
esp_timer_delete(s_btdm_slp_tmr);
s_btdm_slp_tmr = NULL;
}
btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR);
#endif #endif
if (s_lp_cntl.wakeup_timer_required && s_btdm_slp_tmr != NULL) {
esp_timer_delete(s_btdm_slp_tmr);
s_btdm_slp_tmr = NULL;
}
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) #if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
btdm_deep_sleep_mem_deinit(); if (s_lp_cntl.mac_bb_pd) {
sleep_backup_en = false; btdm_deep_sleep_mem_deinit();
s_lp_cntl.mac_bb_pd = 0;
}
#endif #endif
if (s_lp_cntl.enable) {
btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR);
if (s_wakeup_req_sem != NULL) {
semphr_delete_wrapper(s_wakeup_req_sem);
s_wakeup_req_sem = NULL;
}
}
} while (0);
esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop); esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop);
return err; return err;
} }
@ -1255,30 +1346,44 @@ esp_err_t esp_bt_controller_deinit(void)
} }
btdm_controller_deinit(); btdm_controller_deinit();
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
btdm_deep_sleep_mem_deinit();
#endif
esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop);
periph_module_disable(PERIPH_BT_MODULE); periph_module_disable(PERIPH_BT_MODULE);
esp_phy_disable(); esp_phy_disable();
// deinit low power control resources
do {
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
btdm_deep_sleep_mem_deinit();
#endif
#ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB #ifdef CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB
btdm_hw_mac_power_down_wrapper(); btdm_hw_mac_power_down_wrapper();
#endif #endif
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(s_light_sleep_pm_lock); if (s_lp_cntl.no_light_sleep) {
s_light_sleep_pm_lock = NULL; esp_pm_lock_delete(s_light_sleep_pm_lock);
esp_pm_lock_delete(s_pm_lock); s_light_sleep_pm_lock = NULL;
s_pm_lock = NULL; }
semphr_delete_wrapper(s_pm_lock_sem);
s_pm_lock_sem = NULL; esp_pm_lock_delete(s_pm_lock);
#endif s_pm_lock = NULL;
#if ( defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) s_lp_stat.pm_lock_released = 0;
esp_timer_stop(s_btdm_slp_tmr);
esp_timer_delete(s_btdm_slp_tmr);
s_btdm_slp_tmr = NULL;
btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR);
#endif #endif
if (s_lp_cntl.wakeup_timer_required) {
esp_timer_stop(s_btdm_slp_tmr);
esp_timer_delete(s_btdm_slp_tmr);
s_btdm_slp_tmr = NULL;
}
if (s_lp_cntl.enable) {
btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR);
semphr_delete_wrapper(s_wakeup_req_sem);
s_wakeup_req_sem = NULL;
}
} while (0);
esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop);
#if CONFIG_SPIRAM_USE_MALLOC #if CONFIG_SPIRAM_USE_MALLOC
vSemaphoreDelete(btdm_queue_table_mux); vSemaphoreDelete(btdm_queue_table_mux);
btdm_queue_table_mux = NULL; btdm_queue_table_mux = NULL;
@ -1306,30 +1411,44 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
ESP_LOGE(BTDM_LOG_TAG, "invalid mode %d, controller support mode is %d", mode, btdm_controller_get_mode()); ESP_LOGE(BTDM_LOG_TAG, "invalid mode %d, controller support mode is %d", mode, btdm_controller_get_mode());
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_light_sleep_pm_lock);
esp_pm_lock_acquire(s_pm_lock);
#endif
// esp_phy_enable();
#if CONFIG_SW_COEXIST_ENABLE #if CONFIG_SW_COEXIST_ENABLE
coex_enable(); coex_enable();
#endif #endif
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { // enable low power mode
btdm_controller_enable_sleep(true); do {
} #ifdef CONFIG_PM_ENABLE
if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_acquire(s_light_sleep_pm_lock);
}
esp_pm_lock_acquire(s_pm_lock);
s_lp_stat.pm_lock_released = 0;
#endif
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) {
btdm_controller_enable_sleep(true);
}
} while (0);
// inititalize bluetooth baseband // inititalize bluetooth baseband
btdm_check_and_init_bb(); btdm_check_and_init_bb();
ret = btdm_controller_enable(mode); ret = btdm_controller_enable(mode);
if (ret) { if (ret) {
// esp_phy_disable(); // disable low power mode
do {
btdm_controller_enable_sleep(false);
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_light_sleep_pm_lock); if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_release(s_pm_lock); esp_pm_lock_release(s_light_sleep_pm_lock);
}
if (s_lp_stat.pm_lock_released == 0) {
esp_pm_lock_release(s_pm_lock);
s_lp_stat.pm_lock_released = 1;
}
#endif #endif
} while (0);
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
@ -1343,28 +1462,36 @@ esp_err_t esp_bt_controller_disable(void)
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
// disable modem sleep and wake up from sleep mode
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_DISA);
btdm_controller_enable_sleep(false);
if (!btdm_power_state_active()) {
btdm_wakeup_request();
}
while (!btdm_power_state_active()) {
esp_rom_delay_us(1000);
}
}
btdm_controller_disable(); btdm_controller_disable();
async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_DISA);
#if CONFIG_SW_COEXIST_ENABLE #if CONFIG_SW_COEXIST_ENABLE
coex_disable(); coex_disable();
#endif #endif
// esp_phy_disable(); // esp_phy_disable();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
// disable low power mode
do {
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_light_sleep_pm_lock); if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_release(s_pm_lock); esp_pm_lock_release(s_light_sleep_pm_lock);
}
if (s_lp_stat.pm_lock_released == 0) {
esp_pm_lock_release(s_pm_lock);
s_lp_stat.pm_lock_released = 1;
} else {
assert(0);
}
#endif #endif
} while (0);
return ESP_OK; return ESP_OK;
} }
@ -1449,18 +1576,6 @@ int IRAM_ATTR esp_bt_h4tl_eif_io_event_notify(int event)
return btdm_hci_tl_io_event_post(event); return btdm_hci_tl_io_event_post(event);
} }
void force_wifi_mode(int arg)
{
}
void unforce_wifi_mode(void)
{
}
void bt_bb_init_cmplx_reg(void)
{
}
uint16_t esp_bt_get_tx_buf_num(void) uint16_t esp_bt_get_tx_buf_num(void)
{ {
return l2c_ble_link_get_tx_buf_num(); return l2c_ble_link_get_tx_buf_num();