summaryrefslogtreecommitdiff
path: root/lib/bt/controller/esp32c3/bt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bt/controller/esp32c3/bt.c')
-rw-r--r--lib/bt/controller/esp32c3/bt.c724
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 */