diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index 73cd9287d..2069665d1 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -18,6 +18,6 @@ ifdef IS_BOOTLOADER_BUILD # following lines are a workaround to link librtc into the # bootloader, until clock setting code is in a source-based esp-idf # component. See also rtc_printf() in bootloader_start.c -COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc +COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc_clk -lrtc COMPONENT_EXTRA_INCLUDES += $(IDF_PATH)/components/esp32/ endif diff --git a/components/bt/bluedroid/api/esp_bt_main.c b/components/bt/bluedroid/api/esp_bt_main.c index c9fe4fc06..f96cae1b3 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/bluedroid/api/esp_bt_main.c @@ -21,6 +21,8 @@ static bool esp_already_enable = false; static bool esp_already_init = false; +extern esp_err_t esp_phy_deinit(void); + esp_bluedroid_status_t esp_bluedroid_get_status(void) { if (esp_already_init) { @@ -164,6 +166,8 @@ esp_err_t esp_bluedroid_deinit(void) esp_already_init = false; + esp_phy_deinit(); + return ESP_OK; } diff --git a/components/bt/bt.c b/components/bt/bt.c index 5bad45ea2..4378b4da6 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -31,6 +31,8 @@ #if CONFIG_BT_ENABLED +extern void do_phy_init(void); + /* not for user call, so don't put to include file */ extern void btdm_osi_funcs_register(void *osi_funcs); extern void btdm_controller_init(void); @@ -145,6 +147,9 @@ void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) static void bt_controller_task(void *pvParam) { btdm_osi_funcs_register(&osi_funcs); + + do_phy_init(); + btdm_controller_init(); } diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index db9bb2539..5338e5f45 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -508,21 +508,6 @@ config PHY_ENABLED menu PHY visible if PHY_ENABLED -config ESP32_PHY_AUTO_INIT - bool "Initialize PHY in startup code" - depends on PHY_ENABLED - default y - help - If enabled, PHY will be initialized in startup code, before - app_main function runs. - If this is undesired, disable this option and call esp_phy_init - from the application before enabling WiFi or BT. - - If this option is enabled, startup code will also initialize - NVS prior to initializing PHY. - - If unsure, choose 'y'. - config ESP32_PHY_INIT_DATA_IN_PARTITION bool "Use a partition to store PHY init data" depends on PHY_ENABLED diff --git a/components/esp32/component.mk b/components/esp32/component.mk index a8109a0f5..e7a88571f 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -3,7 +3,7 @@ # COMPONENT_SRCDIRS := . hwcrypto -LIBS := core rtc +LIBS := core rtc rtc_clk ifdef CONFIG_PHY_ENABLED # BT || WIFI LIBS += phy coexist endif diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 5278f9b16..bc7ed6a71 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -73,9 +73,6 @@ static bool app_cpu_started = false; static void do_global_ctors(void); static void main_task(void* args); extern void app_main(void); -#if CONFIG_ESP32_PHY_AUTO_INIT -static void do_phy_init(); -#endif extern int _bss_start; extern int _bss_end; @@ -214,11 +211,6 @@ void start_cpu0_default(void) esp_core_dump_init(); #endif -#if CONFIG_ESP32_PHY_AUTO_INIT - nvs_flash_init(); - do_phy_init(); -#endif - #if CONFIG_SW_COEXIST_ENABLE if (coex_init() == ESP_OK) { coexist_set_enable(true); @@ -268,39 +260,3 @@ static void main_task(void* args) vTaskDelete(NULL); } -#if CONFIG_ESP32_PHY_AUTO_INIT -static void do_phy_init() -{ - esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; - if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { - calibration_mode = PHY_RF_CAL_NONE; - } - const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); - if (init_data == NULL) { - ESP_LOGE(TAG, "failed to obtain PHY init data"); - abort(); - } - esp_phy_calibration_data_t* cal_data = - (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); - if (cal_data == NULL) { - ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); - abort(); - } - esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); - if (err != ESP_OK) { - ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); - calibration_mode = PHY_RF_CAL_FULL; - } - - esp_phy_init(init_data, calibration_mode, cal_data); - - if (calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) { - err = esp_phy_store_cal_data_to_nvs(cal_data); - } else { - err = ESP_OK; - } - esp_phy_release_init_data(init_data); - free(cal_data); // PHY maintains a copy of calibration data, so we can free this -} -#endif //CONFIG_ESP32_PHY_AUTO_INIT - diff --git a/components/esp32/include/esp_phy_init.h b/components/esp32/include/esp_phy_init.h index e669a4415..55ce145e9 100644 --- a/components/esp32/include/esp_phy_init.h +++ b/components/esp32/include/esp_phy_init.h @@ -223,25 +223,31 @@ esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_da * @brief Initialize PHY module * * PHY module should be initialized in order to use WiFi or BT. - * If "Initialize PHY in startup code" option is set in menuconfig, - * this function will be called automatically before app_main is called, - * using parameters obtained from esp_phy_get_init_data. - * - * Applications which don't need to enable PHY on every start up should - * disable this menuconfig option and call esp_phy_init before calling - * esp_wifi_init or esp_bt_controller_init. See do_phy_init function in - * cpu_start.c for an example of using this function. + * Now PHY initializing job is done automatically when start WiFi or BT. Users should not + * call this API in their application. * * @param init_data PHY parameters. Default set of parameters can * be obtained by calling esp_phy_get_default_init_data * function. * @param mode Calibration mode (Full, partial, or no calibration) * @param[inout] calibration_data + * @param WiFi is_Waked up from sleep or not + * @return ESP_OK on success. + * @return ESP_FAIL on fail. + */ +esp_err_t esp_phy_init(const void* init_data, + int mode, void* calibration_data, bool is_sleep); + +/** + * @brief De-initialize PHY module + * + * PHY module should be de-initialized in order to shutdown WiFi or BT. + * Now PHY de-initializing job is done automatically when stop WiFi or BT. Users should not + * call this API in their application. + * * @return ESP_OK on success. */ -esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data); - +esp_err_t esp_phy_deinit(void); #ifdef __cplusplus } diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index ac04c07d5..43775a6c4 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -83,7 +83,11 @@ SECTIONS *libesp32.a:core_dump.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) - *libpp.a:(.literal .text .literal.* .text.*) + *librtc_clk.a:(.literal .text .literal.* .text.*) + *libpp.a:lmac.o(.literal .text .literal.* .text.*) + *libpp.a:wdev.o(.literal .text .literal.* .text.*) + *libcore.a:ets_timer.o(.literal .text .literal.* .text.*) + *libnet80211.a:ieee80211_misc.o(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) *libcoexist.a:(.literal .text .literal.* .text.*) _iram_text_end = ABSOLUTE(.); diff --git a/components/esp32/lib b/components/esp32/lib index 1627461bf..c0d942036 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 1627461bf2fc2ec8a090b30cddae2118d542c454 +Subproject commit c0d94203602f7dd3d755bb1180a1640c3715c3ae diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 5b130eaf7..6026da6ac 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -17,7 +17,14 @@ #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "freertos/ringbuf.h" + #include "rom/ets_sys.h" +#include "rom/rtc.h" #include "soc/dport_reg.h" #include "esp_err.h" @@ -25,30 +32,70 @@ #include "esp_system.h" #include "esp_log.h" #include "nvs.h" +#include "nvs_flash.h" #include "sdkconfig.h" #ifdef CONFIG_PHY_ENABLED #include "phy.h" #include "phy_init_data.h" +#include "rtc.h" static const char* TAG = "phy_init"; +/* Count value to indicate if there is peripheral that has initialized PHY and RF */ +int g_phy_rf_init_count = 0; -esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) +static xSemaphoreHandle g_phy_rf_init_mux = NULL; + +esp_err_t esp_phy_init(const void* init_data, + int mode, void* calibration_data, bool is_sleep) { - assert(init_data); - assert(calibration_data); + esp_phy_init_data_t* data = (esp_phy_init_data_t *)init_data; + esp_phy_calibration_mode_t cal_mode = (esp_phy_calibration_mode_t)mode; + esp_phy_calibration_data_t* cal_data = (esp_phy_calibration_data_t *)calibration_data; - REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - // Enable WiFi peripheral clock - SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); - ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", - init_data, calibration_data, mode); - phy_set_wifi_mode_only(0); - register_chipv7_phy(init_data, calibration_data, mode); - coex_bt_high_prio(); + assert((g_phy_rf_init_count <= 1) && (g_phy_rf_init_count >= 0)); + + if (g_phy_rf_init_mux == NULL) { + g_phy_rf_init_mux = xSemaphoreCreateMutex(); + if (g_phy_rf_init_mux == NULL) { + ESP_LOGE(TAG, "Create PHY RF mutex fail"); + return ESP_FAIL; + } + } + + xSemaphoreTake(g_phy_rf_init_mux, portMAX_DELAY); + if (g_phy_rf_init_count == 0) { + if (is_sleep == false) { + REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + } + // Enable WiFi peripheral clock + SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", + init_data, calibration_data, mode); + phy_set_wifi_mode_only(0); + register_chipv7_phy(data, cal_data, cal_mode); + coex_bt_high_prio(); + } + g_phy_rf_init_count++; + xSemaphoreGive(g_phy_rf_init_mux); + return ESP_OK; +} + +esp_err_t esp_phy_deinit(void) +{ + assert((g_phy_rf_init_count <= 2) && (g_phy_rf_init_count >= 1)); + + xSemaphoreTake(g_phy_rf_init_mux, portMAX_DELAY); + if (g_phy_rf_init_count == 1) { + // Disable PHY and RF. This is a teporary function. + pm_close_rf(); + // Disable WiFi peripheral clock + CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + } + g_phy_rf_init_count--; + xSemaphoreGive(g_phy_rf_init_mux); return ESP_OK; } @@ -220,4 +267,39 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, return err; } +void do_phy_init(void) +{ + esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; + nvs_flash_init(); + if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { + calibration_mode = PHY_RF_CAL_NONE; + } + const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); + if (init_data == NULL) { + ESP_LOGE(TAG, "failed to obtain PHY init data"); + abort(); + } + esp_phy_calibration_data_t* cal_data = + (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); + if (cal_data == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); + abort(); + } + esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); + if (err != ESP_OK) { + ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + calibration_mode = PHY_RF_CAL_FULL; + } + + esp_phy_init(init_data, calibration_mode, cal_data, false); + + if (calibration_mode != PHY_RF_CAL_NONE) { + err = esp_phy_store_cal_data_to_nvs(cal_data); + } else { + err = ESP_OK; + } + esp_phy_release_init_data(init_data); + free(cal_data); // PHY maintains a copy of calibration data, so we can free this +} + #endif // CONFIG_PHY_ENABLED diff --git a/components/esp32/rtc.h b/components/esp32/rtc.h index e1cf33522..48272259f 100644 --- a/components/esp32/rtc.h +++ b/components/esp32/rtc.h @@ -135,6 +135,10 @@ void rtc_slp_prep_lite(uint32_t deep_slp, uint32_t cpu_lp_mode); */ uint32_t rtc_sleep(uint32_t cycles_h, uint32_t cycles_l, uint32_t wakeup_opt, uint32_t reject_opt); +/** + * @brief Shutdown PHY and RF. This is a temporary function. + */ +void pm_close_rf(void); #ifdef __cplusplus } diff --git a/components/freertos/include/freertos/portable.h b/components/freertos/include/freertos/portable.h index b05755da4..0c10ac36e 100644 --- a/components/freertos/include/freertos/portable.h +++ b/components/freertos/include/freertos/portable.h @@ -216,6 +216,9 @@ static inline uint32_t xPortGetCoreID() { return id; } +/* Get tick rate per second */ +uint32_t xPortGetTickRateHz(void); + #ifdef __cplusplus } #endif diff --git a/components/freertos/port.c b/components/freertos/port.c index c778950d6..ba4da3e28 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -406,7 +406,9 @@ void vPortSetStackWatchpoint( void* pxStackStart ) { esp_set_watchpoint(1, (char*)addr, 32, ESP_WATCHPOINT_STORE); } - +uint32_t xPortGetTickRateHz(void) { + return (uint32_t)configTICK_RATE_HZ; +}