From ffd8c267802467862fc31d4461aba44218ad1c82 Mon Sep 17 00:00:00 2001 From: ronghulin Date: Wed, 16 Oct 2019 11:22:50 +0800 Subject: [PATCH] feature: support multiple PHY init data --- components/esp_wifi/CMakeLists.txt | 39 ++- components/esp_wifi/Kconfig | 28 +- components/esp_wifi/esp32/esp_adapter.c | 2 + .../esp_wifi/esp32/include/phy_init_data.h | 28 ++ components/esp_wifi/esp32s2/esp_adapter.c | 2 + .../esp_wifi/esp32s2/include/phy_init_data.h | 30 ++ components/esp_wifi/include/esp_phy_init.h | 39 +++ .../include/esp_private/wifi_os_adapter.h | 3 +- components/esp_wifi/include/esp_wifi.h | 4 +- components/esp_wifi/lib | 2 +- .../esp_wifi/phy_multiple_init_data.bin | Bin 0 -> 1072 bytes components/esp_wifi/src/phy_init.c | 298 ++++++++++++++++++ .../sdkconfig.ci.phy_multiple_init_data | 3 + 13 files changed, 457 insertions(+), 21 deletions(-) create mode 100644 components/esp_wifi/phy_multiple_init_data.bin create mode 100644 tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index d12ed929d..83ab61bcf 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -58,25 +58,30 @@ endif() if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) idf_component_get_property(esp_common_dir esp_common COMPONENT_DIR) partition_table_get_partition_info(phy_partition_offset "--partition-type data --partition-subtype phy" "offset") - set(phy_init_data_bin "${build_dir}/phy_init_data.bin") + + if(CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN) + set(phy_init_data_bin "${CMAKE_CURRENT_SOURCE_DIR}/phy_multiple_init_data.bin") + else() + set(phy_init_data_bin "${build_dir}/phy_init_data.bin") - # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy - # the object file to a raw binary - idf_build_get_property(config_dir CONFIG_DIR) - add_custom_command( - OUTPUT ${phy_init_data_bin} - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h - COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} - -o phy_init_data.obj - ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h - COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} - ) - add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) - add_dependencies(flash phy_init_data) + # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy + # the object file to a raw binary + idf_build_get_property(config_dir CONFIG_DIR) + add_custom_command( + OUTPUT ${phy_init_data_bin} + DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h + COMMAND ${CMAKE_C_COMPILER} -x c -c + -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} + -o phy_init_data.obj + ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h + COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} + ) + add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) + add_dependencies(flash phy_init_data) - idf_component_get_property(main_args esptool_py FLASH_ARGS) - idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) + idf_component_get_property(main_args esptool_py FLASH_ARGS) + idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) + endif() # ToDo: remove once MP chip is supported if(CONFIG_IDF_TARGET_ESP32) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index b238da7f5..c3688c6b4 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -325,7 +325,7 @@ menu "PHY" 2.Because of your board design, each time when you do calibration, the result are too unstable. If unsure, choose 'y'. - config ESP32_PHY_INIT_DATA_IN_PARTITION + menuconfig ESP32_PHY_INIT_DATA_IN_PARTITION bool "Use a partition to store PHY init data" default n help @@ -341,6 +341,32 @@ menu "PHY" If unsure, choose 'n'. + if ESP32_PHY_INIT_DATA_IN_PARTITION + config ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + bool "Support multiple PHY init data bin" + depends on ESP32_PHY_INIT_DATA_IN_PARTITION + default n + help + If enabled, the corresponding PHY init data type can be automatically switched + according to the country code. China's PHY init data bin is used by default. + Can be modified by country information in API esp_wifi_set_country(). + The priority of switching the PHY init data type is: + 1. Country configured by API esp_wifi_set_country() + and the parameter policy is WIFI_COUNTRY_POLICY_MANUAL. + 2. Country notified by the connected AP. + 3. Country configured by API esp_wifi_set_country() + and the parameter policy is WIFI_COUNTRY_POLICY_AUTO. + + config ESP32_PHY_INIT_DATA_ERROR + bool "Terminate operation when PHY init data error" + depends on ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + default n + help + If enabled, when an error occurs while the PHY init data is updated, + the program will terminate and restart. + If not enabled, the PHY init data will not be updated when an error occurs. + endif + config ESP32_PHY_MAX_WIFI_TX_POWER int "Max WiFi TX power (dBm)" range 10 20 diff --git a/components/esp_wifi/esp32/esp_adapter.c b/components/esp_wifi/esp32/esp_adapter.c index cab86b407..010fde884 100644 --- a/components/esp_wifi/esp32/esp_adapter.c +++ b/components/esp_wifi/esp32/esp_adapter.c @@ -40,6 +40,7 @@ #include "esp_phy_init.h" #include "soc/dport_reg.h" #include "soc/syscon_reg.h" +#include "phy_init_data.h" #include "driver/periph_ctrl.h" #include "nvs.h" #include "os.h" @@ -588,6 +589,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._phy_load_cal_and_init = esp_phy_load_cal_and_init, ._phy_common_clock_enable = esp_phy_common_clock_enable, ._phy_common_clock_disable = esp_phy_common_clock_disable, + ._phy_update_country_info = esp_phy_update_country_info, ._read_mac = esp_read_mac, ._timer_arm = timer_arm_wrapper, ._timer_disarm = timer_disarm_wrapper, diff --git a/components/esp_wifi/esp32/include/phy_init_data.h b/components/esp_wifi/esp32/include/phy_init_data.h index 2cb12a737..3b9a71c45 100644 --- a/components/esp_wifi/esp32/include/phy_init_data.h +++ b/components/esp_wifi/esp32/include/phy_init_data.h @@ -27,6 +27,12 @@ #define PHY_TX_POWER_OFFSET 44 #define PHY_TX_POWER_NUM 5 +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +#define PHY_CRC_ALGORITHM 1 +#define PHY_COUNTRY_CODE_LEN 2 +#define PHY_INIT_DATA_TYPE_OFFSET 126 +#define PHY_SUPPORT_MULTIPLE_BIN_OFFSET 125 +#endif static const char phy_init_magic_pre[] = PHY_INIT_MAGIC; /** @@ -144,5 +150,27 @@ static const esp_phy_init_data_t phy_init_data= { { static const char phy_init_magic_post[] = PHY_INIT_MAGIC; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief PHY init data control infomation structure + */ +typedef struct { + uint8_t control_info_checksum[4]; /*!< 4-byte control infomation checksum */ + uint8_t multiple_bin_checksum[4]; /*!< 4-byte multiple bin checksum */ + uint8_t check_algorithm; /*!< check algorithm */ + uint8_t version; /*!< PHY init data bin version */ + uint8_t number; /*!< PHY init data bin number */ + uint8_t length[2]; /*!< Length of each PHY init data bin */ + uint8_t reserved[19]; /*!< 19-byte reserved */ +} __attribute__ ((packed)) phy_control_info_data_t; + +/** + * @brief Country corresponds to PHY init data type structure + */ +typedef struct { + char cc[PHY_COUNTRY_CODE_LEN]; + uint8_t type; +} phy_country_to_bin_type_t; +#endif #endif /* PHY_INIT_DATA_H */ diff --git a/components/esp_wifi/esp32s2/esp_adapter.c b/components/esp_wifi/esp32s2/esp_adapter.c index cf0740086..200682b1f 100644 --- a/components/esp_wifi/esp32s2/esp_adapter.c +++ b/components/esp_wifi/esp32s2/esp_adapter.c @@ -41,6 +41,7 @@ #include "esp32s2/clk.h" #include "soc/dport_reg.h" #include "soc/syscon_reg.h" +#include "phy_init_data.h" #include "driver/periph_ctrl.h" #include "nvs.h" #include "os.h" @@ -576,6 +577,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._dport_access_stall_other_cpu_end_wrap = esp_empty_wrapper, ._phy_rf_deinit = esp_phy_rf_deinit, ._phy_load_cal_and_init = esp_phy_load_cal_and_init, + ._phy_update_country_info = esp_phy_update_country_info, ._read_mac = esp_read_mac, ._timer_arm = timer_arm_wrapper, ._timer_disarm = timer_disarm_wrapper, diff --git a/components/esp_wifi/esp32s2/include/phy_init_data.h b/components/esp_wifi/esp32s2/include/phy_init_data.h index da21d6fe2..9a1e5884e 100644 --- a/components/esp_wifi/esp32s2/include/phy_init_data.h +++ b/components/esp_wifi/esp32s2/include/phy_init_data.h @@ -31,6 +31,13 @@ extern "C" { #define PHY_TX_POWER_OFFSET 44 #define PHY_TX_POWER_NUM 5 +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +#define PHY_CRC_ALGORITHM 1 +#define PHY_COUNTRY_CODE_LEN 2 +#define PHY_INIT_DATA_TYPE_OFFSET 126 +#define PHY_SUPPORT_MULTIPLE_BIN_OFFSET 125 +#endif + static const char phy_init_magic_pre[] = PHY_INIT_MAGIC; /** @@ -148,6 +155,29 @@ static const esp_phy_init_data_t phy_init_data= { { static const char phy_init_magic_post[] = PHY_INIT_MAGIC; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief PHY init data control infomation structure + */ +typedef struct { + uint8_t control_info_checksum[4]; /*!< 4-byte control infomation checksum */ + uint8_t multiple_bin_checksum[4]; /*!< 4-byte multiple bin checksum */ + uint8_t check_algorithm; /*!< check algorithm */ + uint8_t version; /*!< PHY init data bin version */ + uint8_t number; /*!< PHY init data bin number */ + uint8_t length[2]; /*!< Length of each PHY init data bin */ + uint8_t reserved[19]; /*!< 19-byte reserved */ +} __attribute__ ((packed)) phy_control_info_data_t; + +/** + * @brief Country corresponds to PHY init data type structure + */ +typedef struct { + char cc[PHY_COUNTRY_CODE_LEN]; + uint8_t type; +} phy_country_to_bin_type_t; +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_phy_init.h b/components/esp_wifi/include/esp_phy_init.h index 1e5c3cf94..2e5953a08 100644 --- a/components/esp_wifi/include/esp_phy_init.h +++ b/components/esp_wifi/include/esp_phy_init.h @@ -63,6 +63,30 @@ typedef enum{ MODEM_MODULE_COUNT //!< Number of items }modem_sleep_module_t; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief PHY init data type + */ +typedef enum { + ESP_PHY_INIT_DATA_TYPE_DEFAULT = 0, + ESP_PHY_INIT_DATA_TYPE_SRRC, + ESP_PHY_INIT_DATA_TYPE_FCC, + ESP_PHY_INIT_DATA_TYPE_CE, + ESP_PHY_INIT_DATA_TYPE_NCC, + ESP_PHY_INIT_DATA_TYPE_KCC, + ESP_PHY_INIT_DATA_TYPE_MIC, + ESP_PHY_INIT_DATA_TYPE_IC, + ESP_PHY_INIT_DATA_TYPE_ACMA, + ESP_PHY_INIT_DATA_TYPE_ANATEL, + ESP_PHY_INIT_DATA_TYPE_ISED, + ESP_PHY_INIT_DATA_TYPE_WPC, + ESP_PHY_INIT_DATA_TYPE_OFCA, + ESP_PHY_INIT_DATA_TYPE_IFETEL, + ESP_PHY_INIT_DATA_TYPE_RCM, + ESP_PHY_INIT_DATA_TYPE_NUMBER, +} phy_init_data_type_t; +#endif + /** * @brief Module WIFI mask for medem sleep */ @@ -244,6 +268,21 @@ esp_err_t esp_modem_sleep_deregister(modem_sleep_module_t module); * microsecond since boot when phy/rf was last switched on */ int64_t esp_phy_rf_get_on_ts(void); + +/** + * @brief Update the corresponding PHY init type according to the country code of Wi-Fi. + */ +esp_err_t esp_phy_update_country_info(const char *country); + +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/** + * @brief Apply PHY init bin to PHY + * @return ESP_OK on success. + * @return ESP_FAIL on fail. + */ +esp_err_t esp_phy_apply_phy_init_data(uint8_t *init_data); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_private/wifi_os_adapter.h b/components/esp_wifi/include/esp_private/wifi_os_adapter.h index cfac30182..dd3f88447 100644 --- a/components/esp_wifi/include/esp_private/wifi_os_adapter.h +++ b/components/esp_wifi/include/esp_private/wifi_os_adapter.h @@ -21,7 +21,7 @@ extern "C" { #endif -#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000005 +#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000006 #define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF #define OSI_FUNCS_TIME_BLOCKING 0xffffffff @@ -83,6 +83,7 @@ typedef struct { void (* _phy_common_clock_enable)(void); void (* _phy_common_clock_disable)(void); #endif + int32_t (* _phy_update_country_info)(const char* country); int32_t (* _read_mac)(uint8_t* mac, uint32_t type); void (* _timer_arm)(void *timer, uint32_t tmout, bool repeat); void (* _timer_disarm)(void *timer); diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index d8b7618a4..ad8f63054 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -592,9 +592,11 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); * @attention 3. When the country policy is WIFI_COUNTRY_POLICY_MANUAL, always use the configured country info. * @attention 4. When the country info is changed because of configuration or because the station connects to a different * external AP, the country IE in probe response/beacon of the soft-AP is changed also. - * @attention 5. The country configuration is not stored into flash + * @attention 5. The country configuration is stored into flash. * @attention 6. This API doesn't validate the per-country rules, it's up to the user to fill in all fields according to * local regulations. + * @attention 7. When this API is called, the PHY init data will switch to the PHY init data type corresponding to the + * country info. * * @param country the configured country info * diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 5f483b842..d72ff2a27 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 5f483b84212a313d202580b0b20f9db09b07cbd9 +Subproject commit d72ff2a27e6892b40ff6cf4a1aec67aa552c299b diff --git a/components/esp_wifi/phy_multiple_init_data.bin b/components/esp_wifi/phy_multiple_init_data.bin new file mode 100644 index 0000000000000000000000000000000000000000..61ce8eb8e9ab15fd71694affbe0df89e969483d2 GIT binary patch literal 1072 zcmWIWi1hUH3}IknVC7_EWoBb#VPj!s00Jl%!~}sqfBt>=@ZrIO2NDtzejZLX7AB00 zj7&_-EUb(W1(cAC49fzb?hyLH_hWADy;4R7c7_HlW>Vx%CMOi21Oiy>z$wJYypA&a znSg-?0Zc$3EGTGfjMFkK5{yhI2G)M|?*nT;t2edm2PIw&VDxuj31*x^jBKscvY)*8 RXAz~yew-d7Qi7532LJ?cYux|< literal 0 HcmV?d00001 diff --git a/components/esp_wifi/src/phy_init.c b/components/esp_wifi/src/phy_init.c index 452fe97a9..036679b9d 100644 --- a/components/esp_wifi/src/phy_init.c +++ b/components/esp_wifi/src/phy_init.c @@ -38,9 +38,11 @@ #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" #include "esp32/rom/rtc.h" +#include "esp32/rom/crc.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/ets_sys.h" #include "esp32s2/rom/rtc.h" +#include "esp32s2/rom/crc.h" #endif #if CONFIG_IDF_TARGET_ESP32 @@ -85,6 +87,69 @@ static int64_t s_phy_rf_en_ts = 0; static DRAM_ATTR portMUX_TYPE s_phy_int_mux = portMUX_INITIALIZER_UNLOCKED; +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +/* The following static variables are only used by Wi-Fi tasks, so they can be handled without lock */ +static phy_init_data_type_t s_phy_init_data_type = 0; + +static phy_init_data_type_t s_current_apply_phy_init_data = 0; + +static char s_phy_current_country[PHY_COUNTRY_CODE_LEN] = {0}; + +/* Whether it is a new bin */ +static bool s_multiple_phy_init_data_bin = false; + +/* PHY init data type array */ +static char* s_phy_type[ESP_PHY_INIT_DATA_TYPE_NUMBER] = {"DEFAULT", "SRRC", "FCC", "CE", "NCC", "KCC", "MIC", "IC", + "ACMA", "ANATEL", "ISED", "WPC", "OFCA", "IFETEL", "RCM"}; + +/* Country and PHY init data type map */ +static phy_country_to_bin_type_t s_country_code_map_type_table[] = { + {"AT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"AU", ESP_PHY_INIT_DATA_TYPE_ACMA}, + {"BE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"BG", ESP_PHY_INIT_DATA_TYPE_CE}, + {"BR", ESP_PHY_INIT_DATA_TYPE_ANATEL}, + {"CA", ESP_PHY_INIT_DATA_TYPE_ISED}, + {"CH", ESP_PHY_INIT_DATA_TYPE_CE}, + {"CN", ESP_PHY_INIT_DATA_TYPE_SRRC}, + {"CY", ESP_PHY_INIT_DATA_TYPE_CE}, + {"CZ", ESP_PHY_INIT_DATA_TYPE_CE}, + {"DE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"DK", ESP_PHY_INIT_DATA_TYPE_CE}, + {"EE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"ES", ESP_PHY_INIT_DATA_TYPE_CE}, + {"FI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"FR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"GB", ESP_PHY_INIT_DATA_TYPE_CE}, + {"GR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"HK", ESP_PHY_INIT_DATA_TYPE_OFCA}, + {"HR", ESP_PHY_INIT_DATA_TYPE_CE}, + {"HU", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IN", ESP_PHY_INIT_DATA_TYPE_WPC}, + {"IS", ESP_PHY_INIT_DATA_TYPE_CE}, + {"IT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"JP", ESP_PHY_INIT_DATA_TYPE_MIC}, + {"KR", ESP_PHY_INIT_DATA_TYPE_KCC}, + {"LI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LU", ESP_PHY_INIT_DATA_TYPE_CE}, + {"LV", ESP_PHY_INIT_DATA_TYPE_CE}, + {"MT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"MX", ESP_PHY_INIT_DATA_TYPE_IFETEL}, + {"NL", ESP_PHY_INIT_DATA_TYPE_CE}, + {"NO", ESP_PHY_INIT_DATA_TYPE_CE}, + {"NZ", ESP_PHY_INIT_DATA_TYPE_RCM}, + {"PL", ESP_PHY_INIT_DATA_TYPE_CE}, + {"PT", ESP_PHY_INIT_DATA_TYPE_CE}, + {"RO", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SE", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SI", ESP_PHY_INIT_DATA_TYPE_CE}, + {"SK", ESP_PHY_INIT_DATA_TYPE_CE}, + {"TW", ESP_PHY_INIT_DATA_TYPE_NCC}, + {"US", ESP_PHY_INIT_DATA_TYPE_FCC}, +}; +#endif uint32_t IRAM_ATTR phy_enter_critical(void) { if (xPortInIsrContext()) { @@ -502,6 +567,14 @@ const esp_phy_init_data_t* esp_phy_get_init_data(void) ESP_LOGE(TAG, "failed to validate PHY data partition"); return NULL; } +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + if ((*(init_data_store + (sizeof(phy_init_magic_pre) + PHY_SUPPORT_MULTIPLE_BIN_OFFSET)))) { + s_multiple_phy_init_data_bin = true; + ESP_LOGI(TAG, "Support multiple PHY init data bins"); + } else { + ESP_LOGW(TAG, "Does not support multiple PHY init data bins"); + } +#endif ESP_LOGD(TAG, "PHY data partition validated"); return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre)); } @@ -601,6 +674,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle_t handle, { esp_err_t err; uint32_t cal_data_version; + err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to get cal_version (0x%x)", __func__, err); @@ -765,3 +839,227 @@ void esp_phy_load_cal_and_init(phy_rf_module_t module) free(cal_data); // PHY maintains a copy of calibration data, so we can free this } +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN +static esp_err_t phy_crc_check_init_data(uint8_t* init_data, const uint8_t* checksum, size_t init_data_length) +{ + uint32_t crc_data = 0; + crc_data = crc32_le(crc_data, init_data, init_data_length); + uint32_t crc_size_conversion = htonl(crc_data); + + if (crc_size_conversion != *(uint32_t*)(checksum)) { + return ESP_FAIL; + } + return ESP_OK; +} + +static uint8_t phy_find_bin_type_according_country(const char* country) +{ + uint32_t i = 0; + uint8_t phy_init_data_type = 0; + + for (i = 0; i < sizeof(s_country_code_map_type_table)/sizeof(phy_country_to_bin_type_t); i++) + { + if (!memcmp(country, s_country_code_map_type_table[i].cc, sizeof(s_phy_current_country))) { + phy_init_data_type = s_country_code_map_type_table[i].type; + ESP_LOGD(TAG, "Current country is %c%c, PHY init data type is %s\n", s_country_code_map_type_table[i].cc[0], + s_country_code_map_type_table[i].cc[1], s_phy_type[s_country_code_map_type_table[i].type]); + break; + } + } + + if (i == sizeof(s_country_code_map_type_table)/sizeof(phy_country_to_bin_type_t)) { + phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + ESP_LOGW(TAG, "Use the default certification code beacuse %c%c doesn't have a certificate", country[0], country[1]); + } + + return phy_init_data_type; +} + +static esp_err_t phy_find_bin_data_according_type(uint8_t* out_init_data_store, + const phy_control_info_data_t* init_data_control_info, + const uint8_t* init_data_multiple, + phy_init_data_type_t init_data_type) +{ + int i = 0; + for (i = 0; i < init_data_control_info->number; i++) { + if (init_data_type == *(init_data_multiple + (i * sizeof(esp_phy_init_data_t)) + PHY_INIT_DATA_TYPE_OFFSET)) { + memcpy(out_init_data_store + sizeof(phy_init_magic_pre), + init_data_multiple + (i * sizeof(esp_phy_init_data_t)), sizeof(esp_phy_init_data_t)); + break; + } + } + + if (i == init_data_control_info->number) { + return ESP_FAIL; + } + return ESP_OK; +} + +static esp_err_t phy_get_multiple_init_data(const esp_partition_t* partition, + uint8_t* init_data_store, + size_t init_data_store_length, + phy_init_data_type_t init_data_type) +{ + phy_control_info_data_t* init_data_control_info = (phy_control_info_data_t*) malloc(sizeof(phy_control_info_data_t)); + if (init_data_control_info == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for PHY init data control info"); + return ESP_FAIL; + } + + esp_err_t err = esp_partition_read(partition, init_data_store_length, init_data_control_info, sizeof(phy_control_info_data_t)); + if (err != ESP_OK) { + free(init_data_control_info); + ESP_LOGE(TAG, "failed to read PHY control info data partition (0x%x)", err); + return ESP_FAIL; + } + + if ((init_data_control_info->check_algorithm) == PHY_CRC_ALGORITHM) { + err = phy_crc_check_init_data(init_data_control_info->multiple_bin_checksum, init_data_control_info->control_info_checksum, + sizeof(phy_control_info_data_t) - sizeof(init_data_control_info->control_info_checksum)); + if (err != ESP_OK) { + free(init_data_control_info); + ESP_LOGE(TAG, "PHY init data control info check error"); + return ESP_FAIL; + } + } else { + free(init_data_control_info); + ESP_LOGE(TAG, "Check algorithm not CRC, PHY init data update failed"); + return ESP_FAIL; + } + + uint8_t* init_data_multiple = (uint8_t*) malloc(sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (init_data_multiple == NULL) { + free(init_data_control_info); + ESP_LOGE(TAG, "failed to allocate memory for PHY init data multiple bin"); + return ESP_FAIL; + } + + err = esp_partition_read(partition, init_data_store_length + sizeof(phy_control_info_data_t), + init_data_multiple, sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (err != ESP_OK) { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "failed to read PHY init data multiple bin partition (0x%x)", err); + return ESP_FAIL; + } + + if ((init_data_control_info->check_algorithm) == PHY_CRC_ALGORITHM) { + err = phy_crc_check_init_data(init_data_multiple, init_data_control_info->multiple_bin_checksum, + sizeof(esp_phy_init_data_t) * init_data_control_info->number); + if (err != ESP_OK) { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "PHY init data multiple bin check error"); + return ESP_FAIL; + } + } else { + free(init_data_multiple); + free(init_data_control_info); + ESP_LOGE(TAG, "Check algorithm not CRC, PHY init data update failed"); + return ESP_FAIL; + } + + err = phy_find_bin_data_according_type(init_data_store, init_data_control_info, init_data_multiple, init_data_type); + if (err != ESP_OK) { + ESP_LOGW(TAG, "%s has not been certified, use DEFAULT PHY init data", s_phy_type[init_data_type]); + s_phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + } else { + s_phy_init_data_type = init_data_type; + } + + free(init_data_multiple); + free(init_data_control_info); + return ESP_OK; +} + +esp_err_t esp_phy_update_init_data(phy_init_data_type_t init_data_type) +{ + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); + if (partition == NULL) { + ESP_LOGE(TAG, "Updated country code PHY data partition not found"); + return ESP_FAIL; + } + size_t init_data_store_length = sizeof(phy_init_magic_pre) + + sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post); + uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length); + if (init_data_store == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for updated country code PHY init data"); + return ESP_ERR_NO_MEM; + } + + esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); + if (err != ESP_OK) { + free(init_data_store); + ESP_LOGE(TAG, "failed to read updated country code PHY data partition (0x%x)", err); + return ESP_FAIL; + } + if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || + memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post), + PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) { + free(init_data_store); + ESP_LOGE(TAG, "failed to validate updated country code PHY data partition"); + return ESP_FAIL; + } + + //find init data bin according init data type + if (init_data_type != ESP_PHY_INIT_DATA_TYPE_DEFAULT) { + err = phy_get_multiple_init_data(partition, init_data_store, init_data_store_length, init_data_type); + if (err != ESP_OK) { + free(init_data_store); +#if CONFIG_ESP32_PHY_INIT_DATA_ERROR + abort(); +#else + return ESP_FAIL; +#endif + } + } else { + s_phy_init_data_type = ESP_PHY_INIT_DATA_TYPE_DEFAULT; + } + + if (s_current_apply_phy_init_data != s_phy_init_data_type) { + err = esp_phy_apply_phy_init_data(init_data_store + sizeof(phy_init_magic_pre)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "PHY init data failed to load"); + free(init_data_store); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "PHY init data type updated from %s to %s", + s_phy_type[s_current_apply_phy_init_data], s_phy_type[s_phy_init_data_type]); + s_current_apply_phy_init_data = s_phy_init_data_type; + } + + free(init_data_store); + return ESP_OK; +} +#endif + +esp_err_t esp_phy_update_country_info(const char *country) +{ +#if CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN + uint8_t phy_init_data_type_map = 0; + //if country equal s_phy_current_country, return; + if (!memcmp(country, s_phy_current_country, sizeof(s_phy_current_country))) { + return ESP_OK; + } + + memcpy(s_phy_current_country, country, sizeof(s_phy_current_country)); + + if (!s_multiple_phy_init_data_bin) { + ESP_LOGD(TAG, "Does not support multiple PHY init data bins"); + return ESP_FAIL; + } + + phy_init_data_type_map = phy_find_bin_type_according_country(country); + if (phy_init_data_type_map == s_phy_init_data_type) { + return ESP_OK; + } + + esp_err_t err = esp_phy_update_init_data(phy_init_data_type_map); + if (err != ESP_OK) { + return err; + } +#endif + return ESP_OK; +} diff --git a/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data b/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data new file mode 100644 index 000000000..b4d3f63c8 --- /dev/null +++ b/tools/test_apps/system/build_test/sdkconfig.ci.phy_multiple_init_data @@ -0,0 +1,3 @@ +CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION=y +CONFIG_ESP32_SUPPORT_MULTIPLE_PHY_INIT_DATA_BIN=y +CONFIG_IDF_TARGET="esp32"