diff --git a/components/esp_phy/CMakeLists.txt b/components/esp_phy/CMakeLists.txt index 7c827338a0..f73b24fbd0 100644 --- a/components/esp_phy/CMakeLists.txt +++ b/components/esp_phy/CMakeLists.txt @@ -22,6 +22,9 @@ if(CONFIG_ESP_PHY_ENABLED) else() set(link_binary_libs 1) set(ldfragments "linker.lf") + if(CONFIG_ESP_PHY_INIT_IRAM) + list(APPEND ldfragments "linker_esp32hxx.lf") + endif() endif() if(CONFIG_SOC_IEEE802154_BLE_ONLY) @@ -140,8 +143,9 @@ if(CONFIG_ESP_PHY_ENABLED) list(APPEND libs_to_link esp_phy_libphy) endif() - # Finally, link the libraries to the component - target_link_libraries(${COMPONENT_LIB} INTERFACE ${libs_to_link}) + # Finally, link the libraries to the component. + # PUBLIC is required for linker.lf fragment mappings (e.g. IRAM placement) to work. + target_link_libraries(${COMPONENT_LIB} PUBLIC ${libs_to_link}) endif() if(CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION) diff --git a/components/esp_phy/Kconfig b/components/esp_phy/Kconfig index 93661e0973..8f569a571f 100644 --- a/components/esp_phy/Kconfig +++ b/components/esp_phy/Kconfig @@ -207,5 +207,19 @@ menu "PHY" PLL track helps the PHY module adapt to temperature changes, ensuring stable performance. When pll enabled, the ESP PHY module will periodically track and adjust PLL parameters. + config ESP_PHY_INIT_IRAM + bool "Place PHY (de)init in IRAM" + depends on SOC_IEEE802154_BLE_ONLY + default n + help + Select this option to place esp_phy and PHY library functions related to phy_init in IRAM. + This config applies to ESP32-H2, ESP32-H21, and ESP32-H4. + + config ESP_PHY_ENABLE_VERSION_PRINT + bool "Print PHY version" + default y + help + Select to print PHY version in esp_phy_enable. This config only applies to esp32hxx for now. + endif endmenu # PHY diff --git a/components/esp_phy/linker_esp32hxx.lf b/components/esp_phy/linker_esp32hxx.lf new file mode 100644 index 0000000000..a157b54bea --- /dev/null +++ b/components/esp_phy/linker_esp32hxx.lf @@ -0,0 +1,91 @@ +# Linker fragment for ESP32-Hxx (H2/H21/H4) specific PHY IRAM placement +# These entries are used when CONFIG_ESP_PHY_INIT_IRAM is enabled + +[mapping:phy_hxx] +archive: libphy.a +entries: + if ESP_PHY_INIT_IRAM = y: + # esp_phy_disable (basically phy_close_rf) + phy_init:phy_close_rf (noflash) + phy_tsens:tsens_temp_read (noflash) + phy_hw_freq:get_freq_mem_param (noflash) + phy_hw_freq:get_freq_mem_addr (noflash) + phy_basic:enter_critical_phy (noflash) + phy_hw_freq:phy_dis_hw_set_freq (noflash) + phy_hw_freq:wait_freq_set_busy (noflash) + phy_hw_freq:read_rf_freq_mem_new (noflash) + phy_init:phy_xpd_rf (noflash) + phy_pbus:pbus_debugmode (noflash) + phy_pbus:pbus_force_mode (noflash) + phy_basic:exit_critical_phy (noflash) + phy_api:phy_xpd_tsens (noflash) + phy_pbus:pbus_xpd_tx_off (noflash) + phy_reg:phy_bbpll_cal (noflash) + phy_reg:phy_modem_lo_clk (noflash) + phy_pbus:pbus_force_test (noflash) + phy_pbus:pbus_workmode (noflash) + # esp_phy_enable (basically phy_wakeup_init) + phy_init:phy_wakeup_init (noflash) + phy_tsens:tsens_read_init (noflash) + phy_hw_freq:phy_chan_hw_init (noflash) + phy_hw_freq:freq_reg_init (noflash) + phy_rfpll:chan_to_freq (noflash) + phy_hw_freq:freq_i2c_data_write (noflash) + phy_hw_freq:freq_get_i2c_data (noflash) + phy_hw_freq:freq_i2c_write_set_new (noflash) + phy_hw_freq:freq_i2c_num_addr (noflash) + phy_hw_freq:freq_num_get_data (noflash) + phy_reg:open_i2c_xpd (noflash) + phy_i2c:i2c_clk_sel (noflash) + phy_basic:i2c_master_reset (noflash) + phy_reg:set_pbus_reg (noflash) + phy_i2c:phy_i2c_init1 (noflash) + phy_i2c:i2c_paral_write_num (noflash) + phy_i2c:i2c_paral_write (noflash) + phy_i2c:chip_i2c_readReg (noflash) + phy_i2c:get_i2c_read_mask (noflash) + phy_i2c:get_i2c_hostid (noflash) + phy_i2c:chip_i2c_readReg_org (noflash) + phy_i2c:i2c_sar2_init_code (noflash) + phy_i2c:i2c_writeReg_Mask (noflash) + phy_i2c:chip_i2c_writeReg (noflash) + phy_hw_freq:write_chan_freq (noflash) + phy_hw_freq:freq_chan_en_sw (noflash) + phy_reg:fe_reg_init (noflash) + phy_reg:adc_cal_set (noflash) + phy_reg:logain_reg_init (noflash) + phy_init:phy_reg_init (noflash) + phy_reg:iq_corr_enable (noflash) + phy_reg:agc_reg_init (noflash) + phy_reg:phy_ant_init (noflash) + phy_reg:bt_filter_reg (noflash) + phy_hw_freq:phy_en_hw_set_freq (noflash) + +[mapping:esp_phy_hxx] +archive: libesp_phy.a +entries: + if ESP_PHY_INIT_IRAM = y: + phy_init_esp32hxx:esp_phy_enable (noflash) + phy_init_esp32hxx:esp_phy_disable (noflash) + phy_common:phy_clr_modem_flag (noflash) + phy_common:phy_get_modem_flag (noflash) + phy_common:phy_set_modem_flag (noflash) + phy_common:phy_track_pll_deinit (noflash) + phy_common:phy_track_pll_init (noflash) + phy_common:phy_track_pll (noflash) + phy_common:phy_enabled_modem_contains (noflash) + +[mapping:phy_hal_hxx] +archive: libesp_hal_ana_conv.a +entries: + if ESP_PHY_INIT_IRAM = y: + temperature_sensor_hal:temperature_sensor_hal_get_degree (noflash) + temperature_sensor_hal:temperature_sensor_hal_init (noflash) + temperature_sensor_hal:temperature_sensor_ll_set_range (noflash) + +[mapping:esp_timer_hxx] +archive: libesp_timer.a +entries: + if ESP_PHY_INIT_IRAM = y: + esp_timer:esp_timer_create (noflash) + esp_timer:esp_timer_delete (noflash) diff --git a/components/esp_phy/src/phy_init_esp32hxx.c b/components/esp_phy/src/phy_init_esp32hxx.c index 727cb8c8d5..c8a63e377b 100644 --- a/components/esp_phy/src/phy_init_esp32hxx.c +++ b/components/esp_phy/src/phy_init_esp32hxx.c @@ -21,8 +21,6 @@ #define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0 #endif -#define PHY_ENABLE_VERSION_PRINT 1 - static DRAM_ATTR portMUX_TYPE s_phy_int_mux = portMUX_INITIALIZER_UNLOCKED; extern void phy_version_print(void); @@ -117,7 +115,9 @@ void esp_phy_enable(esp_phy_modem_t modem) assert(phy_module_has_clock_bits(PHY_INIT_MODEM_CLOCK_REQUIRED_BITS)); if (!s_phy_is_enabled) { register_chipv7_phy(NULL, NULL, PHY_RF_CAL_FULL); +#if CONFIG_ESP_PHY_ENABLE_VERSION_PRINT phy_version_print(); +#endif s_phy_is_enabled = true; } else { phy_wakeup_init(); diff --git a/components/esp_phy/test/CMakeLists.txt b/components/esp_phy/test/CMakeLists.txt deleted file mode 100644 index 69dc92a8b8..0000000000 --- a/components/esp_phy/test/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -idf_component_register(SRC_DIRS . - PRIV_INCLUDE_DIRS . ${CMAKE_CURRENT_BINARY_DIR} - PRIV_REQUIRES cmock test_utils nvs_flash ulp esp_common esp_phy esp_wifi - ) diff --git a/components/esp_phy/test/test_phy_rtc.c b/components/esp_phy/test/test_phy_rtc.c deleted file mode 100644 index 1d653ce15c..0000000000 --- a/components/esp_phy/test/test_phy_rtc.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Tests for the Wi-Fi -*/ -#include "string.h" -#include "esp_system.h" -#include "unity.h" -#include "esp_log.h" -#include "nvs_flash.h" -#include "test_utils.h" -#include -#include -#include -#include "soc/soc_caps.h" -#include "esp_private/esp_modem_clock.h" -#include "esp_private/wifi.h" - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32H2) -//IDF-5046 - -#include "esp_phy_init.h" - -//Function just extern, need not test -#if SOC_BT_SUPPORTED -extern void bt_bb_init_cmplx(void); -#endif -extern void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void); -extern void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void); - -//Functions in librtc.a called by WIFI or Blutooth directly in ISR -#if SOC_BT_SUPPORTED -extern void bt_track_pll_cap(void); -#endif - - -static const char* TAG = "test_phy_rtc"; - -static SemaphoreHandle_t semphr_done; - -//Functions in libphy.a called by WIFI or Blutooth directly in ISR -static void test_phy_rtc_init(void) -{ - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_LOGI(TAG, "no free pages or nvs version mismatch, erase.."); - TEST_ESP_OK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - TEST_ESP_OK(ret); -#if CONFIG_ESP_WIFI_ENABLED - esp_phy_enable(PHY_MODEM_WIFI); -#endif -#if CONFIG_BT_ENABLED - esp_phy_enable(PHY_MODEM_BT); -#endif -#if CONFIG_IEEE802154_ENABLED - esp_phy_enable(PHY_MODEM_IEEE802154); -#endif - //must run here, not blocking in above code - TEST_ASSERT(1); - nvs_flash_deinit(); -} - -static IRAM_ATTR void test_phy_rtc_cache_task(void *arg) -{ - //power up wifi and bt mac bb power domain - esp_wifi_power_domain_on(); -#if CONFIG_IDF_TARGET_ESP32C6 - modem_clock_module_enable(PERIPH_PHY_MODULE); -#endif // CONFIG_IDF_TARGET_ESP32C6 - test_phy_rtc_init(); - -#if CONFIG_IDF_TARGET_ESP32 - extern void force_wifi_mode(int); - extern void unforce_wifi_mode(void); - - for (int i = 0; i < 2; i++) { - ESP_LOGI(TAG, "Test force_wifi_mode(%d)...", i); - spi_flash_disable_interrupts_caches_and_other_cpu(); - force_wifi_mode(i); - spi_flash_enable_interrupts_caches_and_other_cpu(); - - ESP_LOGI(TAG, "Test unforce_wifi_mode()..."); - spi_flash_disable_interrupts_caches_and_other_cpu(); - unforce_wifi_mode(); - spi_flash_enable_interrupts_caches_and_other_cpu(); - } -#endif //CONFIG_IDF_TARGET_ESP32 - -#if SOC_BT_SUPPORTED - -#if CONFIG_IDF_TARGET_ESP32 - /* Only esp32 will call bt_track_pll_cap() in the interrupt - handler, other chips will call this function in the task - */ - ESP_LOGI(TAG, "Test bt_track_pll_cap()..."); - spi_flash_disable_interrupts_caches_and_other_cpu(); - bt_track_pll_cap(); - spi_flash_enable_interrupts_caches_and_other_cpu(); - - extern void bt_bb_init_cmplx_reg(void); - ESP_LOGI(TAG, "Test bt_bb_init_cmplx_reg()..."); - spi_flash_disable_interrupts_caches_and_other_cpu(); - bt_bb_init_cmplx_reg(); - spi_flash_enable_interrupts_caches_and_other_cpu(); -#endif //CONFIG_IDF_TARGET_ESP32 - -#endif //SOC_BT_SUPPORTED - -#if CONFIG_IDF_TARGET_ESP32C6 - modem_clock_module_disable(PERIPH_PHY_MODULE); -#endif // CONFIG_IDF_TARGET_ESP32C6 - //power down wifi and bt mac bb power domain - esp_wifi_power_domain_off(); - - TEST_ASSERT( xSemaphoreGive(semphr_done) ); - - vTaskDelete(NULL); -} - -TEST_CASE("Test PHY/RTC functions called when cache is disabled", "[phy_rtc][cache_disabled]") -{ - semphr_done = xSemaphoreCreateCounting(1, 0); - - xTaskCreatePinnedToCore(test_phy_rtc_cache_task, "phy_rtc_test_task", 3072, - NULL, configMAX_PRIORITIES-1, NULL, 0); - - TEST_ASSERT( xSemaphoreTake(semphr_done, portMAX_DELAY) ); - - vSemaphoreDelete(semphr_done); -} -#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6) diff --git a/components/esp_phy/test_apps/.build-test-rules.yml b/components/esp_phy/test_apps/.build-test-rules.yml index 51491cb49f..e09fd07766 100644 --- a/components/esp_phy/test_apps/.build-test-rules.yml +++ b/components/esp_phy/test_apps/.build-test-rules.yml @@ -1,5 +1,18 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps +components/esp_phy/test_apps/phy_iram: + enable: + - if: SOC_IEEE802154_BLE_ONLY == 1 + disable: + - if: IDF_TARGET not in ["esp32h2"] + temporary: true + reason: not supported for esp32h21 and esp32h4 yet + depends_components: + - esp_phy + - esp_pm + - esp_timer + - spi_flash + - nvs_flash components/esp_phy/test_apps/phy_multiple_init_data: disable: - if: IDF_TARGET == "esp32p4" # Update with caps here when IDF-7460 is resolved diff --git a/components/esp_phy/test_apps/phy_iram/CMakeLists.txt b/components/esp_phy/test_apps/phy_iram/CMakeLists.txt new file mode 100644 index 0000000000..fc8645648d --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/CMakeLists.txt @@ -0,0 +1,7 @@ +#This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.22) + +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_phy_iram) diff --git a/components/esp_phy/test_apps/phy_iram/README.md b/components/esp_phy/test_apps/phy_iram/README.md new file mode 100644 index 0000000000..900ce85073 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32-H2 | +| ----------------- | -------- | + +This project tests whether esp_phy_enable and esp_phy_disable can be fully placed in IRAM for the ESP32-H2. diff --git a/components/esp_phy/test_apps/phy_iram/main/CMakeLists.txt b/components/esp_phy/test_apps/phy_iram/main/CMakeLists.txt new file mode 100644 index 0000000000..27e654faf5 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/main/CMakeLists.txt @@ -0,0 +1,7 @@ +set(srcs "test_app_main.c" + "test_phy.c") + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES unity nvs_flash esp_phy ieee802154 + WHOLE_ARCHIVE) diff --git a/components/esp_phy/test_apps/phy_iram/main/test_app_main.c b/components/esp_phy/test_apps/phy_iram/main/test_app_main.c new file mode 100644 index 0000000000..6cd28065b4 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/main/test_app_main.c @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +void app_main(void) +{ + vTaskPrioritySet(NULL, 5); + unity_run_menu(); +} diff --git a/components/esp_phy/test_apps/phy_iram/main/test_phy.c b/components/esp_phy/test_apps/phy_iram/main/test_phy.c new file mode 100644 index 0000000000..09842e9bf8 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/main/test_phy.c @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_system.h" +#include "unity.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include +#include +#include + +#include "esp_phy_init.h" + +extern void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void); +extern void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void); + +static const char* TAG = "test_phy_iram"; + +static SemaphoreHandle_t semphr_done; + +//Functions in libphy.a called by WIFI or Bluetooth directly in ISR +static void test_phy_rtc_init(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_LOGI(TAG, "no free pages or nvs version mismatch, erase.."); + TEST_ESP_OK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + TEST_ESP_OK(ret); + +#if CONFIG_IEEE802154_ENABLED + esp_phy_enable(PHY_MODEM_IEEE802154); +#endif + //must run here, not blocking in above code + TEST_ASSERT(1); + nvs_flash_deinit(); +} + +static IRAM_ATTR void test_phy_rtc_cache_task(void *arg) +{ + test_phy_rtc_init(); + +#if CONFIG_IDF_TARGET_ESP32H2 + /* Check if esp_phy_enable is fully placed in IRAM, + requires CONFIG_ESP_PHY_ENABLE_VERSION_PRINT to be disabled. + Do not suspend OS scheduler because of _lock_acquire. + */ + spi_flash_disable_interrupts_caches_and_other_cpu_no_os(); + esp_phy_disable(PHY_MODEM_IEEE802154); + esp_phy_enable(PHY_MODEM_IEEE802154); + spi_flash_enable_interrupts_caches_no_os(); +#endif + + TEST_ASSERT( xSemaphoreGive(semphr_done) ); + + vTaskDelete(NULL); +} + +TEST_CASE("Test PHY enable/disable functions with cache disabled", "[phy_iram][cache_disabled]") +{ + semphr_done = xSemaphoreCreateCounting(1, 0); + + xTaskCreatePinnedToCore(test_phy_rtc_cache_task, "phy_rtc_test_task", 3072, + NULL, configMAX_PRIORITIES-1, NULL, 0); + + TEST_ASSERT( xSemaphoreTake(semphr_done, portMAX_DELAY) ); + + vSemaphoreDelete(semphr_done); +} diff --git a/components/esp_phy/test_apps/phy_iram/pytest_phy.py b/components/esp_phy/test_apps/phy_iram/pytest_phy.py new file mode 100644 index 0000000000..81847d86e5 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/pytest_phy.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.generic +@pytest.mark.eco5 +@idf_parametrize('target', ['esp32h2'], indirect=['target']) +def test_phy(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_phy/test_apps/phy_iram/sdkconfig.defaults b/components/esp_phy/test_apps/phy_iram/sdkconfig.defaults new file mode 100644 index 0000000000..8d0d9e46b8 --- /dev/null +++ b/components/esp_phy/test_apps/phy_iram/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_ESP_PHY_ENABLE_VERSION_PRINT=n +CONFIG_ESP_PHY_INIT_IRAM=y +CONFIG_ESP_TIMER_IN_IRAM=y +CONFIG_FREERTOS_IN_IRAM=y +CONFIG_PM_SLP_IRAM_OPT=y + +CONFIG_ESP_TASK_WDT_INIT=n diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index cd783b7ae9..0602de07fc 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -42,6 +42,9 @@ entries: systimer (noflash) if IDF_TARGET_ESP32H21 != y && IDF_TARGET_ESP32H4 != y: sar_periph_ctrl:sar_periph_ctrl_power_disable (noflash) + sar_periph_ctrl:adc_reset_lock_acquire (noflash) + sar_periph_ctrl:adc_reset_lock_release (noflash) + sar_periph_ctrl:sar_periph_ctrl_adc_reset (noflash) if SOC_TEMP_SENSOR_SUPPORTED = y: sar_tsens_ctrl:temperature_sensor_power_acquire (noflash) sar_tsens_ctrl:temperature_sensor_power_release (noflash) diff --git a/pytest.ini b/pytest.ini index e725786d3c..3b04c406f7 100644 --- a/pytest.ini +++ b/pytest.ini @@ -135,3 +135,4 @@ env_markers = rev_default: Runner with default revision connected flash_32m: Runner with 32MB flash eco4: Runner with SOC chip that is exactly with the ECO4 version + eco5: Runner with esp32h2 eco5 connected diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index b9cad01aef..0a7316fe69 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -379,7 +379,6 @@ components/esp_hid/private/bt_hidd.h components/esp_hid/private/bt_hidh.h components/esp_local_ctrl/src/esp_local_ctrl_priv.h components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c -components/esp_phy/test/test_phy_rtc.c components/esp_rom/esp32/include/esp32/rom/tjpgd.h components/esp_rom/esp32/ld/esp32.rom.api.ld components/esp_rom/esp32/ld/esp32.rom.eco3.ld diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index 5f5530bf97..4eeba91086 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -32,4 +32,5 @@ ECO_MARKERS = [ 'esp32p4_eco4', 'esp32c5_eco3', 'eco4', + 'eco5', ]