Ver código fonte

feature: support multiple PHY init data

ronghulin 6 anos atrás
pai
commit
ffd8c26780

+ 22 - 17
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)

+ 27 - 1
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

+ 2 - 0
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,

+ 28 - 0
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 */
 

+ 2 - 0
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,

+ 30 - 0
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

+ 39 - 0
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

+ 2 - 1
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);

+ 3 - 1
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
   *

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit 5f483b84212a313d202580b0b20f9db09b07cbd9
+Subproject commit d72ff2a27e6892b40ff6cf4a1aec67aa552c299b

BIN
components/esp_wifi/phy_multiple_init_data.bin


+ 298 - 0
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;
+}

+ 3 - 0
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"