diff options
Diffstat (limited to 'lib/bt/controller/esp32c3/bt.c')
| -rw-r--r-- | lib/bt/controller/esp32c3/bt.c | 724 |
1 files changed, 436 insertions, 288 deletions
diff --git a/lib/bt/controller/esp32c3/bt.c b/lib/bt/controller/esp32c3/bt.c index f1e045d3..e053cfdf 100644 --- a/lib/bt/controller/esp32c3/bt.c +++ b/lib/bt/controller/esp32c3/bt.c @@ -22,7 +22,10 @@ #include "esp_random.h" #include "esp_task.h" #include "esp_attr.h" +#ifdef CONFIG_ESP_PHY_ENABLED #include "esp_phy_init.h" +#include "esp_private/phy.h" +#endif #include "esp_bt.h" #include "esp_err.h" #include "esp_log.h" @@ -34,11 +37,12 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/soc_memory_layout.h" +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" +#endif #include "esp_timer.h" #include "esp_sleep.h" #include "esp_rom_sys.h" -#include "esp_private/phy.h" #if CONFIG_IDF_TARGET_ESP32C3 #include "riscv/interrupt.h" #include "esp32c3/rom/rom_layout.h" @@ -64,6 +68,7 @@ // wakeup request sources enum { BTDM_ASYNC_WAKEUP_SRC_VHCI = 0, + BTDM_ASYNC_WAKEUP_REQ_COEX, BTDM_ASYNC_WAKEUP_SRC_DISA, BTDM_ASYNC_WAKEUP_SRC_TMR, BTDM_ASYNC_WAKEUP_SRC_MAX, @@ -73,12 +78,12 @@ enum { typedef union { struct { uint32_t enable : 1; // whether low power mode is required - uint32_t lpclk_sel : 2; // low power clock source + uint32_t lpclk_sel : 3; // 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 main_xtal_pu : 1; // power up main XTAL - uint32_t reserved : 25; // reserved + uint32_t reserved : 24; // reserved }; uint32_t val; } btdm_lpcntl_t; @@ -110,7 +115,7 @@ do{\ } while(0) #define OSI_FUNCS_TIME_BLOCKING 0xffffffff -#define OSI_VERSION 0x00010007 +#define OSI_VERSION 0x00010008 #define OSI_MAGIC_VALUE 0xFADEBEAD /* Types definition @@ -184,8 +189,12 @@ struct osi_funcs_t { void (* _btdm_sleep_exit_phase3)(void); /* called from task */ void (* _coex_wifi_sleep_set)(bool sleep); int (* _coex_core_ble_conn_dyn_prio_get)(bool *low, bool *high); + int (* _coex_schm_register_btdm_callback)(void *callback); void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status); void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status); + uint32_t (* _coex_schm_interval_get)(void); + uint8_t (* _coex_schm_curr_period_get)(void); + void *(* _coex_schm_curr_phase_get)(void); void (* _interrupt_on)(int intr_num); void (* _interrupt_off)(int intr_num); void (* _esp_hw_power_down)(void); @@ -193,6 +202,8 @@ struct osi_funcs_t { void (* _ets_backup_dma_copy)(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_rem); void (* _ets_delay_us)(uint32_t us); void (* _btdm_rom_table_ready)(void); + bool (* _coex_bt_wakeup_request)(void); + void (* _coex_bt_wakeup_request_end)(void); }; @@ -256,16 +267,12 @@ extern void btdm_cca_feature_enable(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; -extern uint32_t _btdm_bss_start; -extern uint32_t _btdm_bss_end; -extern uint32_t _nimble_bss_start; -extern uint32_t _nimble_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; extern uint32_t _bt_data_start; extern uint32_t _bt_data_end; -extern uint32_t _btdm_data_start; -extern uint32_t _btdm_data_end; -extern uint32_t _nimble_data_start; -extern uint32_t _nimble_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; /* Local Function Declare ********************************************************************* @@ -306,14 +313,20 @@ static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles); static void btdm_sleep_enter_phase2_wrapper(void); static void btdm_sleep_exit_phase3_wrapper(void); static void coex_wifi_sleep_set_hook(bool sleep); +static int coex_schm_register_btdm_callback_wrapper(void *callback); static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); +static uint32_t coex_schm_interval_get_wrapper(void); +static uint8_t coex_schm_curr_period_get_wrapper(void); +static void * coex_schm_curr_phase_get_wrapper(void); static void interrupt_on_wrapper(int intr_num); static void interrupt_off_wrapper(int intr_num); static void btdm_hw_mac_power_up_wrapper(void); static void btdm_hw_mac_power_down_wrapper(void); static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); static void btdm_funcs_table_ready_wrapper(void); +static bool coex_bt_wakeup_request(void); +static void coex_bt_wakeup_request_end(void); static void btdm_slp_tmr_callback(void *arg); @@ -371,8 +384,12 @@ static const struct osi_funcs_t osi_funcs_ro = { ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, ._coex_wifi_sleep_set = coex_wifi_sleep_set_hook, ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_register_btdm_callback = coex_schm_register_btdm_callback_wrapper, ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, + ._coex_schm_interval_get = coex_schm_interval_get_wrapper, + ._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper, + ._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper, ._interrupt_on = interrupt_on_wrapper, ._interrupt_off = interrupt_off_wrapper, ._esp_hw_power_down = btdm_hw_mac_power_down_wrapper, @@ -380,6 +397,8 @@ static const struct osi_funcs_t osi_funcs_ro = { ._ets_backup_dma_copy = btdm_backup_dma_copy_wrapper, ._ets_delay_us = esp_rom_delay_us, ._btdm_rom_table_ready = btdm_funcs_table_ready_wrapper, + ._coex_bt_wakeup_request = coex_bt_wakeup_request, + ._coex_bt_wakeup_request_end = coex_bt_wakeup_request_end, }; static DRAM_ATTR struct osi_funcs_t *osi_funcs_p; @@ -400,7 +419,7 @@ static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // semaphore used for blocking VHCI API to wait for controller to wake up 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 = NULL; #ifdef CONFIG_PM_ENABLE static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; @@ -463,9 +482,8 @@ static void interrupt_set_wrapper(int cpu_no, int intr_source, int intr_num, int { esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num); #if __riscv - esprv_intc_int_set_priority(intr_num, intr_prio); - //esprv_intc_int_enable_level(1 << intr_num); - esprv_intc_int_set_type(intr_num, 0); + esprv_int_set_priority(intr_num, intr_prio); + esprv_int_set_type(intr_num, 0); #endif } @@ -637,7 +655,7 @@ static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void * static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { - return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -853,6 +871,22 @@ static bool async_wakeup_request(int event) semphr_take_wrapper(s_wakeup_req_sem, OSI_FUNCS_TIME_BLOCKING); } break; + case BTDM_ASYNC_WAKEUP_REQ_COEX: + if (!btdm_power_state_active()) { + do_wakeup_request = true; +#if CONFIG_PM_ENABLE + if (s_lp_stat.pm_lock_released) { + esp_pm_lock_acquire(s_pm_lock); + s_lp_stat.pm_lock_released = 0; + } +#endif + btdm_wakeup_request(); + + if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); + s_lp_stat.wakeup_timer_started = 0; + } + } default: break; } @@ -872,6 +906,9 @@ static void async_wakeup_request_end(int event) case BTDM_ASYNC_WAKEUP_SRC_DISA: allow_to_sleep = true; break; + case BTDM_ASYNC_WAKEUP_REQ_COEX: + allow_to_sleep = false; + break; default: allow_to_sleep = true; break; @@ -891,18 +928,25 @@ static void btdm_funcs_table_ready_wrapper(void) #endif } -static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +bool bt_async_wakeup_request(void) { -#if CONFIG_SW_COEXIST_ENABLE - coex_schm_status_bit_set(type, status); -#endif + return async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_VHCI); } -static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +void bt_wakeup_request_end(void) { -#if CONFIG_SW_COEXIST_ENABLE - coex_schm_status_bit_clear(type, status); -#endif + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_VHCI); +} + +static bool coex_bt_wakeup_request(void) +{ + return async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_COEX); +} + +static void coex_bt_wakeup_request_end(void) +{ + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_REQ_COEX); + return; } bool esp_vhci_host_check_send_available(void) @@ -939,145 +983,175 @@ static void btdm_controller_mem_init(void) btdm_controller_rom_data_init(); } -esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +/** + * Release two memory areas to the heap. If both areas are consecutive, they will be released as + * a single area. + */ +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) { - intptr_t mem_start=(intptr_t) NULL, mem_end=(intptr_t) NULL; + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + +esp_err_t esp_bt_controller_rom_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { return ESP_ERR_INVALID_STATE; } - if (mode & ESP_BT_MODE_BLE) { - /* if the addresses of rom btdm .data and .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(ets_rom_layout_p->data_end_btdm == ets_rom_layout_p->bss_start_btdm) { - mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)ets_rom_layout_p->bss_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t rom_btdm_data = { + .start = (intptr_t) ets_rom_layout_p->data_start_btdm, + .end = (intptr_t) ets_rom_layout_p->data_end_btdm, + .name = "ROM btdm data", + }; + bt_area_t rom_btdm_bss = { + .start = (intptr_t)ets_rom_layout_p->bss_start_btdm, + .end = (intptr_t)ets_rom_layout_p->bss_end_btdm, + .name = "ROM btdm BSS", + }; + bt_area_t rom_btdm_inter_data = { + .start = (intptr_t) ets_rom_layout_p->data_start_interface_btdm, + .end = (intptr_t) ets_rom_layout_p->data_end_interface_btdm, + .name = "ROM interface btdm data", + }; + bt_area_t rom_btdm_inter_bss = { + .start = (intptr_t)ets_rom_layout_p->bss_start_interface_btdm, + .end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm, + .name = "ROM interface btdm BSS", + }; - mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->data_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ret = ESP_ERR_INVALID_STATE; + } + + if (mode & ESP_BT_MODE_BLE) { + /* Free BTDM memory used by the ROM */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&rom_btdm_data, &rom_btdm_bss); } - /* if the addresses of rom interface btdm .data and .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(ets_rom_layout_p->data_end_interface_btdm == ets_rom_layout_p->bss_start_interface_btdm) { - mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->data_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)ets_rom_layout_p->bss_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&rom_btdm_inter_data, &rom_btdm_inter_bss); } + } + + return ret; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; } - return ESP_OK; + + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + if (mode & ESP_BT_MODE_BLE) { + /* free data and BSS section for libbtdm_app.a */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&cont_data, &cont_bss); + } + /* free data and BSS section for Bluetooth controller ROM code */ + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); + } + } + + return ret; } esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - int ret; - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; - ret = esp_bt_controller_mem_release(mode); - if (ret != ESP_OK) { - return ret; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; } - if (mode & ESP_BT_MODE_BLE) { - /* if the addresses of btdm .bss and bt .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(_bt_bss_end == _btdm_bss_start) { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_btdm_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; - mem_start = (intptr_t)&_btdm_bss_start; - mem_end = (intptr_t)&_btdm_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (mode & ESP_BT_MODE_BLE) { + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - /* if the addresses of btdm .data and bt .data are consecutive, - they are registered in the system heap as a piece of memory - */ - if(_bt_data_end == _btdm_data_start) { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_btdm_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_btdm_data_start; - mem_end = (intptr_t)&_btdm_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); } - mem_start = (intptr_t)&_nimble_bss_start; - mem_end = (intptr_t)&_nimble_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_nimble_data_start; - mem_end = (intptr_t)&_nimble_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + /* free data and BSS section for Bluetooth controller ROM code */ + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); } } - return ESP_OK; + + return ret; } static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) @@ -1112,67 +1186,11 @@ static void IRAM_ATTR btdm_mac_bb_power_up_cb(void) } #endif -esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +// init low-power control resources +static esp_err_t btdm_low_power_mode_init(esp_bt_controller_config_t *cfg) { - esp_err_t err = ESP_FAIL; - - if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { - return ESP_ERR_INVALID_STATE; - } - - if (cfg == NULL) { - return ESP_ERR_INVALID_ARG; - } - - if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO - || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { - ESP_LOGE(BT_LOG_TAG, "Invalid controller task prioriy or stack size"); - return ESP_ERR_INVALID_ARG; - } - - if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { - ESP_LOGE(BT_LOG_TAG, "%s controller only support BLE only mode", __func__); - return ESP_ERR_NOT_SUPPORTED; - } - - if (cfg->bluetooth_mode & ESP_BT_MODE_BLE) { - if ((cfg->ble_max_act <= 0) || (cfg->ble_max_act > BT_CTRL_BLE_MAX_ACT_LIMIT)) { - ESP_LOGE(BT_LOG_TAG, "Invalid value of ble_max_act"); - return ESP_ERR_INVALID_ARG; - } - } - - if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { - if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_NONE) { - ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 enabled but sleep clock not configured"); - return ESP_ERR_INVALID_ARG; - } - } - - // overwrite some parameters - cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; - -#if CONFIG_MAC_BB_PD - esp_mac_bb_pd_mem_init(); -#endif - esp_phy_modem_init(); - esp_bt_power_domain_on(); - - btdm_controller_mem_init(); - - 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; - } + esp_err_t err = ESP_OK; - ESP_LOGI(BT_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); - - // init low-power control resources do { // set default values for global states or resources s_lp_stat.val = 0; @@ -1183,13 +1201,14 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) // configure and initialize resources s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0; + s_lp_cntl.lpclk_sel = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? cfg->sleep_clock : ESP_BT_SLEEP_CLOCK_MAIN_XTAL; s_lp_cntl.no_light_sleep = 0; if (s_lp_cntl.enable) { #if CONFIG_MAC_BB_PD if (!btdm_deep_sleep_mem_init()) { err = ESP_ERR_NO_MEM; - goto error; + break; } s_lp_cntl.mac_bb_pd = 1; #endif @@ -1200,58 +1219,55 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) s_wakeup_req_sem = semphr_create_wrapper(1, 0); if (s_wakeup_req_sem == NULL) { err = ESP_ERR_NO_MEM; - goto error; + break; } 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, - .name = "btSlp", - }; - if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { - goto error; + if (s_lp_cntl.wakeup_timer_required) { + esp_timer_create_args_t create_args = { + .callback = btdm_slp_tmr_callback, + .arg = NULL, + .name = "btSlp", + }; + if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { + break; + } } - } - // 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 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; // set default value -#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL - // check whether or not EXT_CRYS is working - if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { - s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL - } else { - ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) { // External 32 kHz XTAL + // check whether or not EXT_CRYS is working + if (rtc_clk_slow_src_get() != SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + s_lp_cntl.lpclk_sel = ESP_BT_SLEEP_CLOCK_MAIN_XTAL; #if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - s_lp_cntl.no_light_sleep = 1; + s_lp_cntl.no_light_sleep = 1; #endif - } -#elif (CONFIG_BT_CTRL_LPCLK_SEL_MAIN_XTAL) - ESP_LOGI(BT_LOG_TAG, "Bluetooth will use main XTAL as Bluetooth sleep clock."); + } + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_RTC_SLOW) { // Internal 136kHz RC oscillator + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { + ESP_LOGW(BT_LOG_TAG, "Internal 136kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is " + "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state."); + } else { + ESP_LOGW(BT_LOG_TAG, "Internal 136kHz RC oscillator not detected."); + assert(0); + } + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { + ESP_LOGI(BT_LOG_TAG, "Bluetooth will use main XTAL as Bluetooth sleep clock."); #if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - s_lp_cntl.no_light_sleep = 1; + s_lp_cntl.no_light_sleep = 1; #endif -#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW) - // check whether or not internal 150 kHz RC oscillator is working - if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { - s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator - ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is " - "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state."); + } } else { - ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected."); - assert(0); + s_lp_cntl.no_light_sleep = 1; } -#endif bool select_src_ret __attribute__((unused)); bool set_div_ret __attribute__((unused)); - if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { #ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON)); s_lp_cntl.main_xtal_pu = 1; @@ -1261,7 +1277,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) assert(select_src_ret && set_div_ret); btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; btdm_lpcycle_us = 1 << (btdm_lpcycle_us_frac); - } else if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL32K) { + } else if (s_lp_cntl.lpclk_sel == 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); @@ -1269,7 +1285,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) : (1000000 >> (15 - RTC_CLK_CAL_FRACT)); assert(btdm_lpcycle_us != 0); - } else if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_RTC_SLOW) { + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_RTC_SLOW) { select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); set_div_ret = btdm_lpclk_set_div(0); assert(select_src_ret && set_div_ret); @@ -1277,7 +1293,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) btdm_lpcycle_us = esp_clk_slowclk_cal_get(); } else { err = ESP_ERR_INVALID_ARG; - goto error; + break; } #if CONFIG_SW_COEXIST_ENABLE coex_update_lpclk_interval(); @@ -1286,20 +1302,100 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #ifdef CONFIG_PM_ENABLE if (s_lp_cntl.no_light_sleep) { if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { - err = ESP_ERR_NO_MEM; - goto error; + break; } ESP_LOGW(BT_LOG_TAG, "light sleep mode will not be able to apply when bluetooth is enabled."); } if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { - err = ESP_ERR_NO_MEM; - goto error; + break; } else { s_lp_stat.pm_lock_released = 1; } #endif } while (0); + return err; +} + +esp_bt_sleep_clock_t esp_bt_get_lpclk_src(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED && + btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_BT_SLEEP_CLOCK_NONE; + } + + return s_lp_cntl.lpclk_sel; +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + esp_err_t err = ESP_FAIL; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if (cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO + || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { + ESP_LOGE(BT_LOG_TAG, "Invalid controller task prioriy or stack size"); + return ESP_ERR_INVALID_ARG; + } + + if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { + ESP_LOGE(BT_LOG_TAG, "%s controller only support BLE only mode", __func__); + return ESP_ERR_NOT_SUPPORTED; + } + + if (cfg->bluetooth_mode & ESP_BT_MODE_BLE) { + if ((cfg->ble_max_act <= 0) || (cfg->ble_max_act > BT_CTRL_BLE_MAX_ACT_LIMIT)) { + ESP_LOGE(BT_LOG_TAG, "Invalid value of ble_max_act"); + return ESP_ERR_INVALID_ARG; + } + } + + if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { + if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_NONE) { + ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 enabled but sleep clock not configured"); + return ESP_ERR_INVALID_ARG; + } + if (cfg->sleep_clock > ESP_BT_SLEEP_CLOCK_RTC_SLOW) { + ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 is enabled but this sleep clock is not supported"); + return ESP_ERR_INVALID_ARG; + } + } + + // overwrite some parameters + cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; + +#if CONFIG_MAC_BB_PD + esp_mac_bb_pd_mem_init(); +#endif + esp_phy_modem_init(); + esp_bt_power_domain_on(); + + btdm_controller_mem_init(); + + 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; + } + + ESP_LOGI(BT_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); + + if ((err = btdm_low_power_mode_init(cfg)) != ESP_OK) { + ESP_LOGE(BT_LOG_TAG, "Low power module initialization failed"); + goto error; + } + #if CONFIG_SW_COEXIST_ENABLE coex_init(); #endif @@ -1336,69 +1432,70 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_OK; } -static void bt_controller_deinit_internal(void) +// deinit low power control resources +static void btdm_low_power_mode_deinit(void) { - periph_module_disable(PERIPH_BT_MODULE); - - // deinit low power control resources - do { - #if CONFIG_MAC_BB_PD - if (s_lp_cntl.mac_bb_pd) { - btdm_deep_sleep_mem_deinit(); - s_lp_cntl.mac_bb_pd = 0; - } + if (s_lp_cntl.mac_bb_pd) { + btdm_deep_sleep_mem_deinit(); + s_lp_cntl.mac_bb_pd = 0; + } #endif #ifdef CONFIG_PM_ENABLE - if (s_lp_cntl.no_light_sleep) { - if (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; - s_lp_stat.pm_lock_released = 0; + if (s_lp_cntl.no_light_sleep) { + if (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; + s_lp_stat.pm_lock_released = 0; + } #endif - if (s_lp_cntl.wakeup_timer_required) { - if (s_lp_stat.wakeup_timer_started) { - esp_timer_stop(s_btdm_slp_tmr); - } - s_lp_stat.wakeup_timer_started = 0; - esp_timer_delete(s_btdm_slp_tmr); - s_btdm_slp_tmr = NULL; + if (s_lp_cntl.wakeup_timer_required && s_btdm_slp_tmr != NULL) { + if (s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); } + s_lp_stat.wakeup_timer_started = 0; + 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); - if (s_wakeup_req_sem != NULL) { - semphr_delete_wrapper(s_wakeup_req_sem); - s_wakeup_req_sem = NULL; - } + 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; } + } - if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { #ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - if (s_lp_cntl.main_xtal_pu) { - ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF)); - s_lp_cntl.main_xtal_pu = 0; - } + if (s_lp_cntl.main_xtal_pu) { + ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF)); + s_lp_cntl.main_xtal_pu = 0; + } #endif - btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); - btdm_lpclk_set_div(0); + btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); + btdm_lpclk_set_div(0); #if CONFIG_SW_COEXIST_ENABLE - coex_update_lpclk_interval(); + coex_update_lpclk_interval(); #endif - } + } - btdm_lpcycle_us = 0; - } while (0); + btdm_lpcycle_us = 0; +} + +static void bt_controller_deinit_internal(void) +{ + periph_module_disable(PERIPH_BT_MODULE); + + btdm_low_power_mode_deinit(); esp_bt_power_domain_off(); #if CONFIG_MAC_BB_PD @@ -1677,4 +1774,55 @@ static void coex_wifi_sleep_set_hook(bool sleep) { } + +static int coex_schm_register_btdm_callback_wrapper(void *callback) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_register_callback(COEX_SCHM_CALLBACK_TYPE_BT, callback); +#else + return 0; +#endif +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif +} + +static uint32_t coex_schm_interval_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_interval_get(); +#else + return 0; +#endif +} + +static uint8_t coex_schm_curr_period_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_period_get(); +#else + return 1; +#endif +} + +static void * coex_schm_curr_phase_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_phase_get(); +#else + return NULL; +#endif +} + #endif /* CONFIG_BT_ENABLED */ |
