diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index ce17a58cc2..a72a77dff6 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -24,15 +24,15 @@ const static char *TAG = "efuse"; #if defined(BOOTLOADER_BUILD) #define EFUSE_LOCK_ACQUIRE() #define EFUSE_LOCK_RELEASE() -#define EFUSE_LOCK_ACQUIRE_RUCURSIVE() -#define EFUSE_LOCK_RELEASE_RUCURSIVE() +#define EFUSE_LOCK_ACQUIRE_RECURSIVE() +#define EFUSE_LOCK_RELEASE_RECURSIVE() #else #include static _lock_t s_efuse_lock; #define EFUSE_LOCK_ACQUIRE() _lock_acquire(&s_efuse_lock) #define EFUSE_LOCK_RELEASE() _lock_release(&s_efuse_lock) -#define EFUSE_LOCK_ACQUIRE_RUCURSIVE() _lock_acquire_recursive(&s_efuse_lock) -#define EFUSE_LOCK_RELEASE_RUCURSIVE() _lock_release_recursive(&s_efuse_lock) +#define EFUSE_LOCK_ACQUIRE_RECURSIVE() _lock_acquire_recursive(&s_efuse_lock) +#define EFUSE_LOCK_RELEASE_RECURSIVE() _lock_release_recursive(&s_efuse_lock) #endif static bool s_batch_writing_mode = false; @@ -80,7 +80,7 @@ esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_ // write array to EFUSE esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || src == NULL || src_size_bits == 0) { err = ESP_ERR_INVALID_ARG; @@ -100,14 +100,14 @@ esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void esp_efuse_utility_reset(); } } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } // program cnt bits to "1" esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || cnt == 0) { err = ESP_ERR_INVALID_ARG; @@ -135,7 +135,7 @@ esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) esp_efuse_utility_reset(); } } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } @@ -184,7 +184,7 @@ uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg) // writing efuse register. esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); if (s_batch_writing_mode == false) { esp_efuse_utility_reset(); } @@ -198,7 +198,7 @@ esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint3 } esp_efuse_utility_reset(); } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index f94fd806ff..fffee5cc0e 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -15,7 +15,6 @@ else() "cache_err_int.c" "cache_sram_mmu.c" "clk.c" - "cpu_start.c" "crosscore_int.c" "dport_access.c" "esp_himem.c" @@ -48,8 +47,6 @@ else() target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") - # Rely on user code to define app_main - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) # This has to be linked before esp32.project.ld diff --git a/components/esp32/cache_err_int.c b/components/esp32/cache_err_int.c index 9adb9effb2..f8deadbf9e 100644 --- a/components/esp32/cache_err_int.c +++ b/components/esp32/cache_err_int.c @@ -23,16 +23,22 @@ #include #include #include -#include "freertos/FreeRTOS.h" + #include "esp_err.h" -#include "esp_intr_alloc.h" #include "esp_attr.h" + +#include "esp_intr_alloc.h" #include "soc/dport_reg.h" +#include "hal/cpu_hal.h" + +#include "esp32/dport_access.h" +#include "esp32/rom/ets_sys.h" + #include "sdkconfig.h" void esp_cache_err_int_init(void) { - uint32_t core_id = xPortGetCoreID(); + uint32_t core_id = cpu_hal_get_core_id(); ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM); // We do not register a handler for the interrupt because it is interrupt diff --git a/components/esp32/clk.c b/components/esp32/clk.c index d12abd3ab7..6f2d0b7627 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -13,148 +13,20 @@ // limitations under the License. #include -#include -#include #include -#include "sdkconfig.h" + #include "esp_attr.h" -#include "esp_log.h" -#include "esp32/clk.h" -#include "esp_clk_internal.h" -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/uart.h" -#include "esp32/rom/rtc.h" -#include "soc/soc.h" -#include "soc/dport_reg.h" #include "soc/rtc.h" -#include "soc/rtc_periph.h" -#include "soc/i2s_periph.h" -#include "hal/wdt_hal.h" -#include "driver/periph_ctrl.h" -#include "xtensa/core-macros.h" -#include "bootloader_clock.h" -#include "driver/spi_common_internal.h" - -/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. - * Larger values increase startup delay. Smaller values may cause false positive - * detection (i.e. oscillator runs for a few cycles and then stops). - */ -#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES - -#ifdef CONFIG_ESP32_RTC_XTAL_CAL_RETRY -#define RTC_XTAL_CAL_RETRY CONFIG_ESP32_RTC_XTAL_CAL_RETRY -#else -#define RTC_XTAL_CAL_RETRY 1 -#endif +#include "esp32/clk.h" #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - -/* Indicates that this 32k oscillator gets input from external oscillator, rather - * than a crystal. - */ -#define EXT_OSC_FLAG BIT(3) - -/* This is almost the same as rtc_slow_freq_t, except that we define - * an extra enum member for the external 32k oscillator. - * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. - */ -typedef enum { - SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator - SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL - SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 - SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin -} slow_clk_sel_t; - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); - // g_ticks_us defined in ROMs for PRO and APP CPU extern uint32_t g_ticks_per_us_pro; #ifndef CONFIG_FREERTOS_UNICORE extern uint32_t g_ticks_per_us_app; #endif -static const char* TAG = "clk"; - - -void esp_clk_init(void) -{ - rtc_config_t cfg = RTC_CONFIG_DEFAULT(); - rtc_init(cfg); - -#if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK) - /* Check the bootloader set the XTAL frequency. - - Bootloaders pre-v2.1 don't do this. - */ - rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); - if (xtal_freq == RTC_XTAL_FREQ_AUTO) { - ESP_EARLY_LOGW(TAG, "RTC domain not initialised by bootloader"); - bootloader_clock_configure(); - } -#else - /* If this assertion fails, either upgrade the bootloader or enable CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS */ - assert(rtc_clk_xtal_freq_get() != RTC_XTAL_FREQ_AUTO); -#endif - - rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. - // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. - // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). - // This prevents excessive delay before resetting in case the supply voltage is drawdown. - // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) - select_rtc_slow_clk(SLOW_CLK_32K_XTAL); -#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC) - select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); -#elif defined(CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256) - select_rtc_slow_clk(SLOW_CLK_8MD256); -#else - select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); -#endif - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // After changing a frequency WDT timeout needs to be set for new frequency. - stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - - rtc_cpu_freq_config_t old_config, new_config; - rtc_clk_cpu_freq_get_config(&old_config); - const uint32_t old_freq_mhz = old_config.freq_mhz; - const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - - bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); - assert(res); - - // Wait for UART TX to finish, otherwise some UART output will be lost - // when switching APB frequency - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - - rtc_clk_cpu_freq_set_config(&new_config); - - // Re calculate the ccount to make time calculation correct. - XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); -} - int IRAM_ATTR esp_clk_cpu_freq(void) { return g_ticks_per_us_pro * MHZ; @@ -178,176 +50,3 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) g_ticks_per_us_app = ticks_per_us; #endif } - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) -{ - rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; - uint32_t cal_val = 0; - /* number of times to repeat 32k XTAL calibration - * before giving up and switching to the internal RC - */ - int retry_32k_xtal = RTC_XTAL_CAL_RETRY; - - do { - if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { - /* 32k XTAL oscillator needs to be enabled and running before it can - * be used. Hardware doesn't have a direct way of checking if the - * oscillator is running. Here we use rtc_clk_cal function to count - * the number of main XTAL cycles in the given number of 32k XTAL - * oscillator cycles. If the 32k XTAL has not started up, calibration - * will time out, returning 0. - */ - ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - if (slow_clk == SLOW_CLK_32K_XTAL) { - rtc_clk_32k_enable(true); - } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { - rtc_clk_32k_enable_external(); - } - // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. - if (SLOW_CLK_CAL_CYCLES > 0) { - cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { - if (retry_32k_xtal-- > 0) { - continue; - } - ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); - rtc_slow_freq = RTC_SLOW_FREQ_RTC; - } - } - } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { - rtc_clk_8m_enable(true, true); - } - rtc_clk_slow_freq_set(rtc_slow_freq); - - if (SLOW_CLK_CAL_CYCLES > 0) { - /* TODO: 32k XTAL oscillator has some frequency drift at startup. - * Improve calibration routine to wait until the frequency is stable. - */ - cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); - } else { - const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; - cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); - } - } while (cal_val == 0); - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); - esp_clk_slowclk_cal_set(cal_val); -} - -void rtc_clk_select_rtc_slow_clk(void) -{ - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); -} - -/* This function is not exposed as an API at this point. - * All peripheral clocks are default enabled after chip is powered on. - * This function disables some peripheral clocks when cpu starts. - * These peripheral clocks are enabled when the peripherals are initialized - * and disabled when they are de-initialized. - */ -void esp_perip_clk_init(void) -{ - uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; - -#if CONFIG_FREERTOS_UNICORE - RESET_REASON rst_reas[1]; -#else - RESET_REASON rst_reas[2]; -#endif - - rst_reas[0] = rtc_get_reset_reason(0); - -#if !CONFIG_FREERTOS_UNICORE - rst_reas[1] = rtc_get_reset_reason(1); -#endif - - /* For reason that only reset CPU, do not disable the clocks - * that have been enabled before reset. - */ - if ((rst_reas[0] >= TGWDT_CPU_RESET && rst_reas[0] <= RTCWDT_CPU_RESET) -#if !CONFIG_FREERTOS_UNICORE - || (rst_reas[1] >= TGWDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) -#endif - ) { - common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); - hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERI_CLK_EN_REG); - wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); - } - else { - common_perip_clk = DPORT_WDG_CLK_EN | - DPORT_PCNT_CLK_EN | - DPORT_LEDC_CLK_EN | - DPORT_TIMERGROUP1_CLK_EN | - DPORT_PWM0_CLK_EN | - DPORT_CAN_CLK_EN | - DPORT_PWM1_CLK_EN | - DPORT_PWM2_CLK_EN | - DPORT_PWM3_CLK_EN; - hwcrypto_perip_clk = DPORT_PERI_EN_AES | - DPORT_PERI_EN_SHA | - DPORT_PERI_EN_RSA | - DPORT_PERI_EN_SECUREBOOT; - wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | - DPORT_WIFI_CLK_BT_EN_M | - DPORT_WIFI_CLK_UNUSED_BIT5 | - DPORT_WIFI_CLK_UNUSED_BIT12 | - DPORT_WIFI_CLK_SDIOSLAVE_EN | - DPORT_WIFI_CLK_SDIO_HOST_EN | - DPORT_WIFI_CLK_EMAC_EN; - } - - //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. - common_perip_clk |= DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 2 - DPORT_UART2_CLK_EN | -#endif - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_UHCI1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_I2C_EXT1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI_DMA_CLK_EN; - - common_perip_clk &= ~DPORT_SPI01_CLK_EN; - -#if CONFIG_SPIRAM_SPEED_80M -//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in -//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' -//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should -//not modify that state, regardless of what we calculated earlier. - if (spicommon_periph_in_use(HSPI_HOST)) { - common_perip_clk &= ~DPORT_SPI2_CLK_EN; - } - if (spicommon_periph_in_use(VSPI_HOST)) { - common_perip_clk &= ~DPORT_SPI3_CLK_EN; - } -#endif - - /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, - * the current is not reduced when disable I2S clock. - */ - DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(0), I2S_CLKA_ENA); - DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(1), I2S_CLKA_ENA); - - /* Disable some peripheral clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); - - /* Disable hardware crypto clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, hwcrypto_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, hwcrypto_perip_clk); - - /* Disable WiFi/BT/SDIO clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); - - /* Enable RNG clock. */ - periph_module_enable(PERIPH_RNG_MODULE); -} diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c deleted file mode 100644 index 2aa6d9c462..0000000000 --- a/components/esp32/cpu_start.c +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "esp_attr.h" -#include "esp_err.h" - -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/uart.h" -#include "esp32/rom/rtc.h" -#include "esp32/rom/cache.h" - -#include "soc/cpu.h" -#include "soc/rtc.h" -#include "soc/dport_reg.h" -#include "soc/gpio_periph.h" -#include "soc/timer_periph.h" -#include "soc/efuse_periph.h" - -#include "hal/wdt_hal.h" - -#include "driver/rtc_io.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" - -#include "esp_heap_caps_init.h" -#include "sdkconfig.h" -#include "esp_system.h" -#include "esp_spi_flash.h" -#include "esp_flash_internal.h" -#include "nvs_flash.h" -#include "esp_spi_flash.h" -#include "esp_private/crosscore_int.h" -#include "esp_log.h" -#include "esp_vfs_dev.h" -#include "esp_newlib.h" -#include "esp32/brownout.h" -#include "esp_int_wdt.h" -#include "esp_task.h" -#include "esp_task_wdt.h" -#include "esp_phy_init.h" -#include "esp32/cache_err_int.h" -#include "esp_coexist_internal.h" -#include "esp_core_dump.h" -#include "esp_app_trace.h" -#include "esp_private/dbg_stubs.h" -#include "esp_flash_encrypt.h" -#include "esp32/spiram.h" -#include "esp_clk_internal.h" -#include "esp_timer.h" -#include "esp_pm.h" -#include "esp_private/pm_impl.h" -#include "trax.h" -#include "esp_ota_ops.h" -#include "esp_efuse.h" -#include "bootloader_flash_config.h" -#include "bootloader_mem.h" - -#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM -#include "esp32/rom/efuse.h" -#include "esp32/rom/spi_flash.h" -#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM - -#define STRINGIFY(s) STRINGIFY2(s) -#define STRINGIFY2(s) #s - -void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); -void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); -#if !CONFIG_FREERTOS_UNICORE -static void IRAM_ATTR call_start_cpu1(void) __attribute__((noreturn)); -void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn)); -void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn)); -static bool app_cpu_started = false; -#endif //!CONFIG_FREERTOS_UNICORE - -static void do_global_ctors(void); -static void main_task(void* args); -extern void app_main(void); -extern esp_err_t esp_pthread_init(void); - -extern int _bss_start; -extern int _bss_end; -extern int _rtc_bss_start; -extern int _rtc_bss_end; -#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY -extern int _iram_bss_start; -extern int _iram_bss_end; -#endif -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY -extern int _ext_ram_bss_start; -extern int _ext_ram_bss_end; -#endif -extern int _init_start; -extern void (*__init_array_start)(void); -extern void (*__init_array_end)(void); -extern volatile int port_xSchedulerRunning[2]; - -static const char* TAG = "cpu_start"; - -struct object { long placeholder[ 10 ]; }; -void __register_frame_info (const void *begin, struct object *ob); -extern char __eh_frame[]; - -//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. -static bool s_spiram_okay=true; - -/* - * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, - * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. - */ - -void IRAM_ATTR call_start_cpu0(void) -{ -#if CONFIG_FREERTOS_UNICORE - RESET_REASON rst_reas[1]; -#else - RESET_REASON rst_reas[2]; -#endif - - bootloader_init_mem(); - - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - rst_reas[0] = rtc_get_reset_reason(0); - -#if !CONFIG_FREERTOS_UNICORE - rst_reas[1] = rtc_get_reset_reason(1); -#endif - - // from panic handler we can be reset by RWDT or TG0WDT - if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET -#if !CONFIG_FREERTOS_UNICORE - || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET -#endif - ) { -#ifndef CONFIG_BOOTLOADER_WDT_ENABLE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - } - - //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); - -#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY - // Clear IRAM BSS - memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); -#endif - - /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ - if (rst_reas[0] != DEEPSLEEP_RESET) { - memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); - } - -#if CONFIG_SPIRAM_BOOT_INIT - esp_spiram_init_cache(); - if (esp_spiram_init() != ESP_OK) { -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); - abort(); -#endif - -#if CONFIG_SPIRAM_IGNORE_NOTFOUND - ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); - s_spiram_okay = false; -#else - ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); - abort(); -#endif - } -#endif - - ESP_EARLY_LOGI(TAG, "Pro cpu up."); - if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { - const esp_app_desc_t *app_desc = esp_ota_get_app_description(); - ESP_EARLY_LOGI(TAG, "Application information:"); -#ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR - ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name); -#endif -#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR - ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version); -#endif -#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION - ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version); -#endif -#ifdef CONFIG_APP_COMPILE_TIME_DATE - ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time); -#endif - char buf[17]; - esp_ota_get_app_elf_sha256(buf, sizeof(buf)); - ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf); - ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); - } - -#if !CONFIG_FREERTOS_UNICORE - if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); - ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); - abort(); - } - ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - - //Flush and enable icache for APP CPU - Cache_Flush(1); - Cache_Read_Enable(1); - esp_cpu_unstall(1); - // Enable clock and reset APP CPU. Note that OpenOCD may have already - // enabled clock and taken APP CPU out of reset. In this case don't reset - // APP CPU again, as that will clear the breakpoints which may have already - // been set. - if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - } - ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); - - while (!app_cpu_started) { - ets_delay_us(100); - } -#else - ESP_EARLY_LOGI(TAG, "Single core mode"); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); -#endif - - -#if CONFIG_SPIRAM_MEMTEST - if (s_spiram_okay) { - bool ext_ram_ok=esp_spiram_test(); - if (!ext_ram_ok) { - ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); - abort(); - } - } -#endif -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); -#endif - /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted. - If the heap allocator is initialized first, it will put free memory linked list items into - memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory, - corrupting those linked lists. Initializing the allocator *after* the app cpu has booted - works around this problem. - With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the - app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may - fail initializing it properly. */ - heap_caps_init(); - - ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - start_cpu0(); -} - -#if !CONFIG_FREERTOS_UNICORE - -static void wdt_reset_cpu1_info_enable(void) -{ - DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); - DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); -} - -void IRAM_ATTR call_start_cpu1(void) -{ - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - ets_set_appcpu_boot_addr(0); - - bootloader_init_mem(); - -#if CONFIG_ESP_CONSOLE_UART_NONE - ets_install_putc1(NULL); - ets_install_putc2(NULL); -#else // CONFIG_ESP_CONSOLE_UART_NONE - uartAttach(); - ets_install_uart_printf(); - uart_tx_switch(CONFIG_ESP_CONSOLE_UART_NUM); -#endif - - wdt_reset_cpu1_info_enable(); - ESP_EARLY_LOGI(TAG, "App cpu up."); - app_cpu_started = 1; - start_cpu1(); -} -#endif //!CONFIG_FREERTOS_UNICORE - -static void intr_matrix_clear(void) -{ - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { - intr_matrix_set(0, i, ETS_INVALID_INUM); -#if !CONFIG_FREERTOS_UNICORE - intr_matrix_set(1, i, ETS_INVALID_INUM); -#endif - } -} - -void start_cpu0_default(void) -{ - esp_err_t err; - esp_setup_syscall_table(); - - if (s_spiram_okay) { -#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - esp_err_t r=esp_spiram_add_to_heapalloc(); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); - abort(); - } -#if CONFIG_SPIRAM_USE_MALLOC - heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); -#endif -#endif - } - -//Enable trace memory and immediately start trace. -#if CONFIG_ESP32_TRAX -#if CONFIG_ESP32_TRAX_TWOBANKS - trax_enable(TRAX_ENA_PRO_APP); -#else - trax_enable(TRAX_ENA_PRO); -#endif - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif - esp_clk_init(); - esp_perip_clk_init(); - intr_matrix_clear(); - -#ifndef CONFIG_ESP_CONSOLE_UART_NONE -#ifdef CONFIG_PM_ENABLE - const int uart_clk_freq = REF_CLK_FREQ; - /* When DFS is enabled, use REFTICK as UART clock source */ - CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); -#else - const int uart_clk_freq = APB_CLK_FREQ; -#endif // CONFIG_PM_DFS_ENABLE - uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); -#endif // CONFIG_ESP_CONSOLE_UART_NONE - -#if CONFIG_ESP32_BROWNOUT_DET - esp_brownout_init(); -#endif - - rtc_gpio_force_hold_dis_all(); - -#ifdef CONFIG_VFS_SUPPORT_IO - esp_vfs_dev_uart_register(); -#endif // CONFIG_VFS_SUPPORT_IO - -#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - esp_reent_init(_GLOBAL_REENT); - const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); - _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); - _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); - _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); -#else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); -#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - // After setting _GLOBAL_REENT, ESP_LOGIx can be used instead of ESP_EARLY_LOGx. - -#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED - esp_flash_encryption_init_checks(); -#endif -#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE - esp_efuse_disable_basic_rom_console(); -#endif -#if CONFIG_SECURE_DISABLE_ROM_DL_MODE - esp_efuse_disable_rom_download_mode(); -#endif - - esp_timer_init(); - esp_set_time_from_rtc(); -#if CONFIG_APPTRACE_ENABLE - err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); -#endif -#if CONFIG_SYSVIEW_ENABLE - SEGGER_SYSVIEW_Conf(); -#endif -#if CONFIG_ESP_DEBUG_STUBS_ENABLE - esp_dbg_stubs_init(); -#endif - err = esp_pthread_init(); - assert(err == ESP_OK && "Failed to init pthread module!"); - - do_global_ctors(); -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#else -#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX - assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); -#endif -#endif - esp_cache_err_int_init(); - esp_crosscore_int_init(); -#ifndef CONFIG_FREERTOS_UNICORE - esp_dport_access_int_init(); -#endif - - bootloader_flash_update_id(); -#if !CONFIG_SPIRAM_BOOT_INIT - // Read the application binary image header. This will also decrypt the header if the image is encrypted. - esp_image_header_t fhdr = {0}; -#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM - fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO; - fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M; - fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB; - - extern void esp_rom_spiflash_attach(uint32_t, bool); - esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false); - esp_rom_spiflash_unlock(); -#else - // This assumes that DROM is the first segment in the application binary, i.e. that we can read - // the binary header through cache by accessing SOC_DROM_LOW address. - memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr)); -#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM - - // If psram is uninitialized, we need to improve some flash configuration. - bootloader_flash_clock_config(&fhdr); - bootloader_flash_gpio_config(&fhdr); - bootloader_flash_dummy_config(&fhdr); - bootloader_flash_cs_timing_config(); -#endif //!CONFIG_SPIRAM_BOOT_INIT - - spi_flash_init(); - /* init default OS-aware flash access critical section */ - spi_flash_guard_set(&g_flash_guard_default_ops); - - esp_flash_app_init(); - esp_err_t flash_ret = esp_flash_init_default_chip(); - assert(flash_ret == ESP_OK); - -#ifdef CONFIG_PM_ENABLE - esp_pm_impl_init(); -#ifdef CONFIG_PM_DFS_INIT_AUTO - int xtal_freq = (int) rtc_clk_xtal_freq_get(); - esp_pm_config_esp32_t cfg = { - .max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, - .min_freq_mhz = xtal_freq, - }; - esp_pm_configure(&cfg); -#endif //CONFIG_PM_DFS_INIT_AUTO -#endif //CONFIG_PM_ENABLE - -#if CONFIG_ESP32_ENABLE_COREDUMP - esp_core_dump_init(); -#endif - -#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE - esp_coex_adapter_register(&g_coex_adapter_funcs); - coex_pre_init(); -#endif - - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); - assert(res == pdTRUE); - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); - abort(); /* Only get to here if not enough free heap to start scheduler */ -} - -#if !CONFIG_FREERTOS_UNICORE -void start_cpu1_default(void) -{ - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } -#if CONFIG_ESP32_TRAX_TWOBANKS - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif -#if CONFIG_APPTRACE_ENABLE - esp_err_t err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); -#endif -#if CONFIG_ESP_INT_WDT - //Initialize the interrupt watch dog for CPU1. - esp_int_wdt_cpu_init(); -#endif - //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler - //has started, but it isn't active *on this CPU* yet. - esp_cache_err_int_init(); - esp_crosscore_int_init(); - esp_dport_access_int_init(); - - ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); - xPortStartScheduler(); - abort(); /* Only get to here if FreeRTOS somehow very broken */ -} -#endif //!CONFIG_FREERTOS_UNICORE - -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get(void) -{ - return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; -} -#endif - -static void do_global_ctors(void) -{ -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS - static struct object ob; - __register_frame_info( __eh_frame, &ob ); -#endif - - void (**p)(void); - for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { - (*p)(); - } -} - -static void main_task(void* args) -{ -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack - while (port_xSchedulerRunning[1] == 0) { - ; - } -#endif - //Enable allocation in region where the startup stacks were located. - heap_caps_enable_nonos_stack_heaps(); - - // Now we have startup stack RAM available for heap, enable any DMA pool memory -#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL - esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); - abort(); - } -#endif - - //Initialize task wdt if configured to do so -#ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); -#elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); -#endif - - //Add IDLE 0 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if(idle_0 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } -#endif - //Add IDLE 1 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); - if(idle_1 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); - } -#endif - - // Now that the application is about to start, disable boot watchdog -#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif -#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE - const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); - if (efuse_partition) { - esp_efuse_init(efuse_partition->address, efuse_partition->size); - } -#endif - app_main(); - vTaskDelete(NULL); -} - diff --git a/components/esp32/ld/esp32.project.ld.in b/components/esp32/ld/esp32.project.ld.in index 369ebb5d67..96557ed62e 100644 --- a/components/esp32/ld/esp32.project.ld.in +++ b/components/esp32/ld/esp32.project.ld.in @@ -208,6 +208,10 @@ SECTIONS _coredump_dram_end = ABSOLUTE(.); /* should be placed after coredump mapping */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + mapping[dram0_data] _data_end = ABSOLUTE(.); @@ -278,6 +282,7 @@ SECTIONS mapping[flash_rodata] + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -297,6 +302,7 @@ SECTIONS __init_array_start = ABSOLUTE(.); KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors SORT(.ctors.*))) __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.*(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) KEEP (*(SORT(.dtors.*))) diff --git a/components/esp32/system_api_esp32.c b/components/esp32/system_api_esp32.c index f32c59c802..66bf18f96f 100644 --- a/components/esp32/system_api_esp32.c +++ b/components/esp32/system_api_esp32.c @@ -33,12 +33,7 @@ #include "hal/wdt_hal.h" #include "freertos/xtensa_api.h" -#if CONFIG_IDF_TARGET_ESP32 #include "esp32/cache_err_int.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/cache_err_int.h" -#endif - /* "inner" restart function for after RTOS, interrupts & anything else on this * core are already stopped. Stalls other core, resets hardware, diff --git a/components/esp32s2/CMakeLists.txt b/components/esp32s2/CMakeLists.txt index b4b4865a41..624a78e4e6 100644 --- a/components/esp32s2/CMakeLists.txt +++ b/components/esp32s2/CMakeLists.txt @@ -14,7 +14,6 @@ else() set(srcs "cache_err_int.c" "memprot.c" "clk.c" - "cpu_start.c" "crosscore_int.c" "dport_access.c" "hw_random.c" @@ -51,9 +50,6 @@ else() target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32s2_out.ld") - # Rely on user code to define app_main - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") - # Process the template file through the linker script generation mechanism, and use the output for linking the # final binary target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32s2.project.ld.in" PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32s2.project.ld") diff --git a/components/esp32s2/cache_err_int.c b/components/esp32s2/cache_err_int.c index 11c2e73103..1db8f2b080 100644 --- a/components/esp32s2/cache_err_int.c +++ b/components/esp32s2/cache_err_int.c @@ -23,19 +23,25 @@ #include #include #include -#include "freertos/FreeRTOS.h" + #include "esp_err.h" -#include "esp_intr_alloc.h" #include "esp_attr.h" + +#include "esp_intr_alloc.h" + #include "soc/extmem_reg.h" #include "soc/dport_reg.h" #include "soc/periph_defs.h" -#include "sdkconfig.h" +#include "hal/cpu_hal.h" + #include "esp32s2/dport_access.h" +#include "esp32s2/rom/ets_sys.h" + +#include "sdkconfig.h" void esp_cache_err_int_init(void) { - uint32_t core_id = xPortGetCoreID(); + uint32_t core_id = cpu_hal_get_core_id(); ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM); // We do not register a handler for the interrupt because it is interrupt diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 36ed52dd34..12a26d43fa 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -13,318 +13,34 @@ // limitations under the License. #include -#include -#include #include -#include "sdkconfig.h" + #include "esp_attr.h" -#include "esp_log.h" -#include "esp32s2/clk.h" -#include "esp_clk_internal.h" -#include "esp32s2/rom/ets_sys.h" -#include "esp32s2/rom/uart.h" -#include "esp32s2/rom/rtc.h" -#include "soc/system_reg.h" -#include "soc/dport_access.h" -#include "soc/soc.h" #include "soc/rtc.h" -#include "soc/rtc_periph.h" -#include "soc/i2s_reg.h" -#include "hal/wdt_hal.h" -#include "driver/periph_ctrl.h" -#include "xtensa/core-macros.h" -#include "bootloader_clock.h" -#include "soc/syscon_reg.h" - -/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. - * Larger values increase startup delay. Smaller values may cause false positive - * detection (i.e. oscillator runs for a few cycles and then stops). - */ -#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES - -#ifdef CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY -#define RTC_XTAL_CAL_RETRY CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY -#else -#define RTC_XTAL_CAL_RETRY 1 -#endif +#include "esp32s2/clk.h" #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - -/* Indicates that this 32k oscillator gets input from external oscillator, rather - * than a crystal. - */ -#define EXT_OSC_FLAG BIT(3) - -/* This is almost the same as rtc_slow_freq_t, except that we define - * an extra enum member for the external 32k oscillator. - * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. - */ -typedef enum { - SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 90 kHz RC oscillator - SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL - SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 - SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin -} slow_clk_sel_t; - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); - -static const char *TAG = "clk"; - - -void esp_clk_init(void) -{ - rtc_config_t cfg = RTC_CONFIG_DEFAULT(); - RESET_REASON rst_reas; - rst_reas = rtc_get_reset_reason(0); - if (rst_reas == POWERON_RESET) { - cfg.cali_ocode = 1; - } - rtc_init(cfg); - - assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); - - rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. - // If the frequency changes from 90kHz to 32kHz, then the timeout set for the WDT will increase 2.8 times. - // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). - // This prevents excessive delay before resetting in case the supply voltage is drawdown. - // (If frequency is changed from 90kHz to 32kHz then WDT timeout will increased to 1.6sec * 90/32 = 4.5 sec). - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS) - select_rtc_slow_clk(SLOW_CLK_32K_XTAL); -#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC) - select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); -#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256) - select_rtc_slow_clk(SLOW_CLK_8MD256); -#else - select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); -#endif - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // After changing a frequency WDT timeout needs to be set for new frequency. - stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - - rtc_cpu_freq_config_t old_config, new_config; - rtc_clk_cpu_freq_get_config(&old_config); - const uint32_t old_freq_mhz = old_config.freq_mhz; - const uint32_t new_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; - - bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); - assert(res); - - // Wait for UART TX to finish, otherwise some UART output will be lost - // when switching APB frequency - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - - rtc_clk_cpu_freq_set_config(&new_config); - - // Re calculate the ccount to make time calculation correct. - XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); -} +// g_ticks_us defined in ROMs +extern uint32_t g_ticks_per_us_pro; int IRAM_ATTR esp_clk_cpu_freq(void) { - return ets_get_cpu_frequency() * 1000000; + return g_ticks_per_us_pro * MHZ; } int IRAM_ATTR esp_clk_apb_freq(void) { - return MIN(ets_get_cpu_frequency(), 80) * 1000000; + return MIN(g_ticks_per_us_pro, 80) * MHZ; } -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +int IRAM_ATTR esp_clk_xtal_freq(void) { - rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; - uint32_t cal_val = 0; - /* number of times to repeat 32k XTAL calibration - * before giving up and switching to the internal RC - */ - int retry_32k_xtal = RTC_XTAL_CAL_RETRY; - - do { - if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { - /* 32k XTAL oscillator needs to be enabled and running before it can - * be used. Hardware doesn't have a direct way of checking if the - * oscillator is running. Here we use rtc_clk_cal function to count - * the number of main XTAL cycles in the given number of 32k XTAL - * oscillator cycles. If the 32k XTAL has not started up, calibration - * will time out, returning 0. - */ - ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - if (slow_clk == SLOW_CLK_32K_XTAL) { - rtc_clk_32k_enable(true); - } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { - rtc_clk_32k_enable_external(); - } - // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. - if (SLOW_CLK_CAL_CYCLES > 0) { - cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { - if (retry_32k_xtal-- > 0) { - continue; - } - ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 90 kHz oscillator"); - rtc_slow_freq = RTC_SLOW_FREQ_RTC; - } - } - } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { - rtc_clk_8m_enable(true, true); - } - rtc_clk_slow_freq_set(rtc_slow_freq); - - if (SLOW_CLK_CAL_CYCLES > 0) { - /* TODO: 32k XTAL oscillator has some frequency drift at startup. - * Improve calibration routine to wait until the frequency is stable. - */ - cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); - } else { - const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; - cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); - } - } while (cal_val == 0); - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); - esp_clk_slowclk_cal_set(cal_val); + return rtc_clk_xtal_freq_get() * MHZ; } -void rtc_clk_select_rtc_slow_clk(void) +void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) { - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); -} - -/* This function is not exposed as an API at this point. - * All peripheral clocks are default enabled after chip is powered on. - * This function disables some peripheral clocks when cpu starts. - * These peripheral clocks are enabled when the peripherals are initialized - * and disabled when they are de-initialized. - */ -void esp_perip_clk_init(void) -{ - uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; - uint32_t common_perip_clk1 = 0; - - RESET_REASON rst_reas[1]; - - rst_reas[0] = rtc_get_reset_reason(0); - - /* For reason that only reset CPU, do not disable the clocks - * that have been enabled before reset. - */ - if (rst_reas[0] >= TG0WDT_CPU_RESET && - rst_reas[0] <= TG0WDT_CPU_RESET && - rst_reas[0] != RTCWDT_BROWN_OUT_RESET) { - common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); - hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN1_REG); - wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); - } else { - common_perip_clk = DPORT_WDG_CLK_EN | - DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif - DPORT_USB_CLK_EN | - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_PCNT_CLK_EN | - DPORT_LEDC_CLK_EN | - DPORT_TIMERGROUP1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_SPI4_CLK_EN | - DPORT_PWM0_CLK_EN | - DPORT_CAN_CLK_EN | - DPORT_PWM1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI2_DMA_CLK_EN | - DPORT_SPI3_DMA_CLK_EN | - DPORT_PWM2_CLK_EN | - DPORT_PWM3_CLK_EN; - common_perip_clk1 = 0; - hwcrypto_perip_clk = DPORT_CRYPTO_AES_CLK_EN | - DPORT_CRYPTO_SHA_CLK_EN | - DPORT_CRYPTO_RSA_CLK_EN; - wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | - DPORT_WIFI_CLK_BT_EN_M | - DPORT_WIFI_CLK_UNUSED_BIT5 | - DPORT_WIFI_CLK_UNUSED_BIT12 | - DPORT_WIFI_CLK_SDIOSLAVE_EN | - DPORT_WIFI_CLK_SDIO_HOST_EN | - DPORT_WIFI_CLK_EMAC_EN; - } - - //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. - common_perip_clk |= DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif - DPORT_USB_CLK_EN | - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_UHCI1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_SPI4_CLK_EN | - DPORT_I2C_EXT1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI2_DMA_CLK_EN | - DPORT_SPI3_DMA_CLK_EN; - common_perip_clk1 = 0; - - /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, - * the current is not reduced when disable I2S clock. - */ - REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); - REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); - - /* Disable some peripheral clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); - - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, common_perip_clk1); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, common_perip_clk1); - - /* Disable hardware crypto clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, hwcrypto_perip_clk); - - /* Disable WiFi/BT/SDIO clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); - - /* Enable WiFi MAC and POWER clocks */ - DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN); - - /* Set WiFi light sleep clock source to RTC slow clock */ - DPORT_REG_SET_FIELD(DPORT_BT_LPCK_DIV_INT_REG, DPORT_BT_LPCK_DIV_NUM, 0); - DPORT_CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_8M); - DPORT_SET_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_RTC_SLOW); - - /* Enable RNG clock. */ - periph_module_enable(PERIPH_RNG_MODULE); + /* Update scale factors used by ets_delay_us */ + g_ticks_per_us_pro = ticks_per_us; } diff --git a/components/esp32s2/cpu_start.c b/components/esp32s2/cpu_start.c deleted file mode 100644 index 66f4b63e3a..0000000000 --- a/components/esp32s2/cpu_start.c +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include "sdkconfig.h" -#include "esp_attr.h" -#include "esp_err.h" - -#include "esp32s2/rom/ets_sys.h" -#include "esp32s2/rom/uart.h" -#include "esp32s2/rom/rtc.h" -#include "esp32s2/rom/cache.h" -#include "esp32s2/dport_access.h" -#include "esp32s2/brownout.h" -#include "esp32s2/cache_err_int.h" -#include "esp32s2/spiram.h" -#include "esp32s2/memprot.h" - -#include "soc/cpu.h" -#include "soc/rtc.h" -#include "soc/dport_reg.h" -#include "soc/io_mux_reg.h" -#include "soc/rtc_cntl_reg.h" -#include "soc/timer_group_reg.h" -#include "soc/periph_defs.h" -#include "hal/wdt_hal.h" -#include "driver/rtc_io.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" - -#include "esp_heap_caps_init.h" -#include "esp_system.h" -#include "esp_spi_flash.h" -#include "esp_flash_internal.h" -#include "nvs_flash.h" -#include "esp_event.h" -#include "esp_spi_flash.h" -#include "esp_private/crosscore_int.h" -#include "esp_log.h" -#include "esp_vfs_dev.h" -#include "esp_newlib.h" -#include "esp_int_wdt.h" -#include "esp_task.h" -#include "esp_task_wdt.h" -#include "esp_phy_init.h" -#include "esp_coexist_internal.h" -#include "esp_debug_helpers.h" -#include "esp_core_dump.h" -#include "esp_app_trace.h" -#include "esp_private/dbg_stubs.h" -#include "esp_clk_internal.h" -#include "esp_timer.h" -#include "esp_pm.h" -#include "esp_private/pm_impl.h" -#include "trax.h" -#include "esp_ota_ops.h" -#include "esp_efuse.h" -#include "bootloader_mem.h" - -#define STRINGIFY(s) STRINGIFY2(s) -#define STRINGIFY2(s) #s - -void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); -void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); - -static void do_global_ctors(void); -static void main_task(void *args); -extern void app_main(void); -extern esp_err_t esp_pthread_init(void); - -extern int _bss_start; -extern int _bss_end; -extern int _rtc_bss_start; -extern int _rtc_bss_end; -extern int _init_start; -extern void (*__init_array_start)(void); -extern void (*__init_array_end)(void); -extern volatile int port_xSchedulerRunning[2]; - -static const char *TAG = "cpu_start"; - -struct object { - long placeholder[ 10 ]; -}; -void __register_frame_info (const void *begin, struct object *ob); -extern char __eh_frame[]; - -//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. -static bool s_spiram_okay = true; - -/* - * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, - * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. - */ - -void IRAM_ATTR call_start_cpu0(void) -{ - RESET_REASON rst_reas; - - bootloader_init_mem(); - - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - rst_reas = rtc_get_reset_reason(0); - - // from panic handler we can be reset by RWDT or TG0WDT - if (rst_reas == RTCWDT_SYS_RESET || rst_reas == TG0WDT_SYS_RESET) { -#ifndef CONFIG_BOOTLOADER_WDT_ENABLE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - } - - //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); - - /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ - if (rst_reas != DEEPSLEEP_RESET) { - memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); - } - - /* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */ - extern void esp_config_instruction_cache_mode(void); - esp_config_instruction_cache_mode(); - - /* If we need use SPIRAM, we should use data cache, or if we want to access rodata, we also should use data cache. - Configure the mode of data : cache size, cache associated ways, cache line size. - Enable data cache, so if we don't use SPIRAM, it just works. */ -#if CONFIG_SPIRAM_BOOT_INIT - extern void esp_config_data_cache_mode(void); - esp_config_data_cache_mode(); - Cache_Enable_DCache(0); -#endif - - /* In SPIRAM code, we will reconfigure data cache, as well as instruction cache, so that we can: - 1. make data buses works with SPIRAM - 2. make instruction and rodata work with SPIRAM, still through instruction cache */ -#if CONFIG_SPIRAM_BOOT_INIT - if (esp_spiram_init() != ESP_OK) { -#if CONFIG_SPIRAM_IGNORE_NOTFOUND - ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); - s_spiram_okay = false; -#else - ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); - abort(); -#endif - } - esp_spiram_init_cache(); -#endif - - ESP_EARLY_LOGI(TAG, "Pro cpu up."); - if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { - const esp_app_desc_t *app_desc = esp_ota_get_app_description(); - ESP_EARLY_LOGI(TAG, "Application information:"); -#ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR - ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name); -#endif -#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR - ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version); -#endif -#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION - ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version); -#endif -#ifdef CONFIG_APP_COMPILE_TIME_DATE - ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time); -#endif - char buf[17]; - esp_ota_get_app_elf_sha256(buf, sizeof(buf)); - ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf); - ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); - } - ESP_EARLY_LOGI(TAG, "Single core mode"); - -#if CONFIG_SPIRAM_MEMTEST - if (s_spiram_okay) { - bool ext_ram_ok = esp_spiram_test(); - if (!ext_ram_ok) { - ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); - abort(); - } - } -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - extern void instruction_flash_page_info_init(void); - instruction_flash_page_info_init(); -#endif -#if CONFIG_SPIRAM_RODATA - extern void rodata_flash_page_info_init(void); - rodata_flash_page_info_init(); -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - extern void esp_spiram_enable_instruction_access(void); - esp_spiram_enable_instruction_access(); -#endif -#if CONFIG_SPIRAM_RODATA - extern void esp_spiram_enable_rodata_access(void); - esp_spiram_enable_rodata_access(); -#endif - -#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP || CONFIG_ESP32S2_DATA_CACHE_WRAP - uint32_t icache_wrap_enable = 0, dcache_wrap_enable = 0; -#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP - icache_wrap_enable = 1; -#endif -#if CONFIG_ESP32S2_DATA_CACHE_WRAP - dcache_wrap_enable = 1; -#endif - extern void esp_enable_cache_wrap(uint32_t icache_wrap_enable, uint32_t dcache_wrap_enable); - esp_enable_cache_wrap(icache_wrap_enable, dcache_wrap_enable); -#endif - - /* Initialize heap allocator */ - heap_caps_init(); - - ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - start_cpu0(); -} - -static void intr_matrix_clear(void) -{ - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { - intr_matrix_set(0, i, ETS_INVALID_INUM); - } -} - -void start_cpu0_default(void) -{ - esp_err_t err; - esp_setup_syscall_table(); - - if (s_spiram_okay) { -#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - esp_err_t r = esp_spiram_add_to_heapalloc(); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); - abort(); - } -#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL - r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool!"); - abort(); - } -#endif -#if CONFIG_SPIRAM_USE_MALLOC - heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); -#endif -#endif - } - -//Enable trace memory and immediately start trace. -#if CONFIG_ESP32S2_TRAX - trax_enable(TRAX_ENA_PRO); - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif - esp_clk_init(); - esp_perip_clk_init(); - intr_matrix_clear(); - -#ifndef CONFIG_ESP_CONSOLE_UART_NONE -#ifdef CONFIG_PM_ENABLE - const int uart_clk_freq = REF_CLK_FREQ; - /* When DFS is enabled, use REFTICK as UART clock source */ - CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); -#else - const int uart_clk_freq = APB_CLK_FREQ; -#endif // CONFIG_PM_DFS_ENABLE - uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); -#endif // CONFIG_ESP_CONSOLE_UART_NONE - -#if CONFIG_ESP32S2_BROWNOUT_DET - esp_brownout_init(); -#endif - - rtc_gpio_force_hold_dis_all(); - -#ifdef CONFIG_VFS_SUPPORT_IO - esp_vfs_dev_uart_register(); -#endif // CONFIG_VFS_SUPPORT_IO - -#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - esp_reent_init(_GLOBAL_REENT); - const char *default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); - _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); - _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); - _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); -#else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); -#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - // After setting _GLOBAL_REENT, ESP_LOGIx can be used instead of ESP_EARLY_LOGx. - -#if CONFIG_SECURE_DISABLE_ROM_DL_MODE - err = esp_efuse_disable_rom_download_mode(); - assert(err == ESP_OK && "Failed to disable ROM download mode"); -#endif -#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE - err = esp_efuse_enable_rom_secure_download_mode(); - assert(err == ESP_OK && "Failed to enable Secure Download mode"); -#endif - - esp_timer_init(); - esp_set_time_from_rtc(); -#if CONFIG_APPTRACE_ENABLE - err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); -#endif -#if CONFIG_SYSVIEW_ENABLE - SEGGER_SYSVIEW_Conf(); -#endif -#if CONFIG_ESP32S2_DEBUG_STUBS_ENABLE - esp_dbg_stubs_init(); -#endif - err = esp_pthread_init(); - assert(err == ESP_OK && "Failed to init pthread module!"); - -#if CONFIG_ESP32S2_MEMPROT_FEATURE -#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK - esp_memprot_set_prot(true, true); -#else - esp_memprot_set_prot(true, false); -#endif -#endif - - do_global_ctors(); -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog - esp_int_wdt_cpu_init(); -#endif - esp_cache_err_int_init(); - esp_crosscore_int_init(); - spi_flash_init(); - /* init default OS-aware flash access critical section */ - spi_flash_guard_set(&g_flash_guard_default_ops); - - esp_flash_app_init(); - esp_err_t flash_ret = esp_flash_init_default_chip(); - assert(flash_ret == ESP_OK); - -#ifdef CONFIG_PM_ENABLE - esp_pm_impl_init(); -#ifdef CONFIG_PM_DFS_INIT_AUTO - int xtal_freq = (int) rtc_clk_xtal_freq_get(); - esp_pm_config_esp32s2_t cfg = { - .max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, - .min_freq_mhz = xtal_freq, - }; - esp_pm_configure(&cfg); -#endif //CONFIG_PM_DFS_INIT_AUTO -#endif //CONFIG_PM_ENABLE - -#if CONFIG_ESP32_ENABLE_COREDUMP - esp_core_dump_init(); -#endif - - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); - assert(res == pdTRUE); - - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); - abort(); /* Only get to here if not enough free heap to start scheduler */ -} - -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get(void) -{ - return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; -} -#endif - -static void do_global_ctors(void) -{ -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS - static struct object ob; - __register_frame_info( __eh_frame, &ob ); -#endif - - void (**p)(void); - for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { - (*p)(); - } -} - -static void main_task(void *args) -{ - //Enable allocation in region where the startup stacks were located. - heap_caps_enable_nonos_stack_heaps(); - - //Initialize task wdt if configured to do so -#ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); -#elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); -#endif - - //Add IDLE 0 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if (idle_0 != NULL) { - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } -#endif - - // Now that the application is about to start, disable boot watchdog -#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE - const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); - if (efuse_partition) { - esp_efuse_init(efuse_partition->address, efuse_partition->size); - } -#endif - - app_main(); - vTaskDelete(NULL); -} - diff --git a/components/esp32s2/esp_clk_internal.h b/components/esp32s2/esp_clk_internal.h deleted file mode 100644 index f1f8964573..0000000000 --- a/components/esp32s2/esp_clk_internal.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -/** - * @file esp_clk_internal.h - * - * Private clock-related functions - */ - -/** - * @brief Initialize clock-related settings - * - * Called from cpu_start.c, not intended to be called from other places. - * This function configures the CPU clock, RTC slow and fast clocks, and - * performs RTC slow clock calibration. - */ -void esp_clk_init(void); - - -/** - * @brief Disables clock of some peripherals - * - * Called from cpu_start.c, not intended to be called from other places. - * This function disables clock of useless peripherals when cpu starts. - */ -void esp_perip_clk_init(void); - -/* Selects an external clock source (32 kHz) for RTC. - * Only internal use in unit test. - */ -void rtc_clk_select_rtc_slow_clk(void); diff --git a/components/esp32s2/include/esp_spiram.h b/components/esp32s2/include/esp_spiram.h index 414cc310af..16212e5405 100644 --- a/components/esp32s2/include/esp_spiram.h +++ b/components/esp32s2/include/esp_spiram.h @@ -78,18 +78,6 @@ size_t esp_spiram_get_size(void); void esp_spiram_writeback_cache(void); - -/** - * @brief Reserve a pool of internal memory for specific DMA/internal allocations - * - * @param size Size of reserved pool in bytes - * - * @return - * - ESP_OK on success - * - ESP_ERR_NO_MEM when no memory available for pool - */ -esp_err_t esp_spiram_reserve_dma_pool(size_t size); - #ifdef __cplusplus } #endif diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index cffa42e9c4..71b24f7065 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -214,6 +214,10 @@ SECTIONS _coredump_dram_end = ABSOLUTE(.); /* should be placed after coredump mapping */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + mapping[dram0_data] _data_end = ABSOLUTE(.); diff --git a/components/esp_common/src/brownout.c b/components/esp_common/src/brownout.c index 57f62cefac..5408d10e57 100644 --- a/components/esp_common/src/brownout.c +++ b/components/esp_common/src/brownout.c @@ -69,7 +69,7 @@ void esp_brownout_init(void) brownout_hal_config(&cfg); - ESP_ERROR_CHECK( rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M) ); + rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M); brownout_hal_intr_enable(true); } diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 7e5b4d57c2..5da5b2b625 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -1,7 +1,19 @@ -idf_component_register(SRCS "panic.c" "system_api.c" +idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" INCLUDE_DIRS include PRIV_INCLUDE_DIRS private_include PRIV_REQUIRES spi_flash app_update + # requirements due to startup code + nvs_flash pthread app_trace LDFRAGMENTS "linker.lf") add_subdirectory(port) + +# After system initialization, `start_app` (and its other cores variant) is called. +# This is provided by the user or from another component. Since we can't establish +# dependency on what we don't know, force linker to not drop the symbol regardless +# of link line order. +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u start_app") + +if (NOT CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u start_app_other_cores") +endif() \ No newline at end of file diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 73b54ad48d..58a2b90cb3 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -32,4 +32,10 @@ menu "ESP System Settings" of the crash. endchoice + config ESP_SYSTEM_SINGLE_CORE_MODE + bool + default n + help + Only initialize and use the main core. + endmenu # ESP System Settings diff --git a/components/esp_system/include/esp_private/startup_internal.h b/components/esp_system/include/esp_private/startup_internal.h new file mode 100644 index 0000000000..8a12ee3673 --- /dev/null +++ b/components/esp_system/include/esp_private/startup_internal.h @@ -0,0 +1,70 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "esp_attr.h" + +#include "soc/soc_caps.h" +#include "hal/cpu_hal.h" + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern bool g_spiram_ok; // [refactor-todo] better way to communicate this from port layer to common startup code + +// Port layer defines the entry point. It then transfer control to a `sys_startup_fn_t`, stored in this +// array, one per core. +typedef void (*sys_startup_fn_t)(void); + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +extern sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM]; +#else +extern sys_startup_fn_t g_startup_fn[1]; +#endif + +// Utility to execute `sys_startup_fn_t` for the current core. +#define SYS_STARTUP_FN() ((*g_startup_fn[(cpu_hal_get_core_id())])()) + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +void startup_resume_other_cores(void); +#endif + +typedef struct { + void (*fn)(void); + uint32_t cores; +} esp_system_init_fn_t; + +/* + * Declare an component initialization function that will execute on the specified cores (ex. if BIT0 == 1, will execute + * on CORE0, CORE1 if BIT1 and so on). + * + * @note Initialization functions should be placed in a compilation unit where at least one other + * symbol is referenced 'meaningfully' in another compilation unit, otherwise this gets discarded during linking. (By + * 'meaningfully' we mean the reference should not itself get optimized out by the compiler/discarded by the linker). + */ +#define ESP_SYSTEM_INIT_FN(f, c, ...) \ +static void __attribute__((used)) __VA_ARGS__ __esp_system_init_fn_##f(void); \ +static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_system_init_fn", f) \ + esp_system_init_fn_##f = { .fn = ( __esp_system_init_fn_##f), .cores = (c) }; \ +static __attribute__((used)) __VA_ARGS__ void __esp_system_init_fn_##f(void) // [refactor-todo] this can be made public API if we allow components to declare init functions, + // instead of calling them explicitly + +#ifdef __cplusplus +} +#endif + diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 75def881d3..976b568b2f 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -1,6 +1,6 @@ target_include_directories(${COMPONENT_LIB} PRIVATE include) -set(srcs "panic_handler.c" "panic_handler_asm.S") +set(srcs "panic_handler.c" "panic_handler_asm.S" "cpu_start.c") add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c new file mode 100644 index 0000000000..9894176f05 --- /dev/null +++ b/components/esp_system/port/cpu_start.c @@ -0,0 +1,419 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "esp_attr.h" +#include "esp_err.h" + +#include "esp_log.h" +#include "esp_system.h" + +#include "esp_clk_internal.h" + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/cache_err_int.h" +#include "esp32/rom/cache.h" +#include "esp32/rom/rtc.h" +#include "esp32/rom/uart.h" +#include "esp32/spiram.h" +#include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/brownout.h" +#include "esp32s2/cache_err_int.h" +#include "esp32s2/rom/cache.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/rtc.h" +#include "esp32s2/spiram.h" +#include "esp32s2/rom/uart.h" +#include "soc/periph_defs.h" +#include "esp32s2/dport_access.h" +#include "esp32s2/memprot.h" +#endif + +#include "bootloader_flash_config.h" +#include "esp_private/crosscore_int.h" +#include "esp_flash_encrypt.h" + +#include "hal/rtc_io_hal.h" +#include "soc/dport_reg.h" +#include "soc/efuse_reg.h" +#include "soc/cpu.h" + +#include "trax.h" + +#include "bootloader_mem.h" + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_APP_BUILD_TYPE_ELF_RAM +#include "esp32/rom/efuse.h" +#include "esp32/rom/spi_flash.h" +#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM +#endif + +#include "esp_private/startup_internal.h" + +extern int _bss_start; +extern int _bss_end; +extern int _rtc_bss_start; +extern int _rtc_bss_end; + +extern int _init_start; + +static const char *TAG = "cpu_start"; + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY +extern int _ext_ram_bss_start; +extern int _ext_ram_bss_end; +#endif +#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY +extern int _iram_bss_start; +extern int _iram_bss_end; +#endif +#endif // CONFIG_IDF_TARGET_ESP32 + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +static volatile bool s_cpu_up[SOC_CPU_CORES_NUM] = { false }; +static volatile bool s_cpu_inited[SOC_CPU_CORES_NUM] = { false }; + +static volatile bool s_resume_cores; +#endif + +// If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. +bool g_spiram_ok = true; + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +void startup_resume_other_cores(void) +{ + s_resume_cores = true; +} + + +void IRAM_ATTR call_start_cpu1(void) +{ + cpu_hal_set_vecbase(&_init_start); + + ets_set_appcpu_boot_addr(0); + + bootloader_init_mem(); + +#if CONFIG_ESP_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_ESP_CONSOLE_UART_NONE + uartAttach(); + ets_install_uart_printf(); + uart_tx_switch(CONFIG_ESP_CONSOLE_UART_NUM); +#endif + + DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); + DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); + + s_cpu_up[1] = true; + ESP_EARLY_LOGI(TAG, "App cpu up."); + + //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler + //has started, but it isn't active *on this CPU* yet. + esp_cache_err_int_init(); + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_TRAX_TWOBANKS + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif +#endif + + s_cpu_inited[1] = true; + + while (!s_resume_cores) { + ets_delay_us(100); + } + + SYS_STARTUP_FN(); +} + +static void start_other_core(void) +{ + // If not the single core variant of ESP32 - check this since there is + // no separate soc_caps.h for the single core variant. + if (!REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); + + Cache_Flush(1); + Cache_Read_Enable(1); + esp_cpu_unstall(1); + + // Enable clock and reset APP CPU. Note that OpenOCD may have already + // enabled clock and taken APP CPU out of reset. In this case don't reset + // APP CPU again, as that will clear the breakpoints which may have already + // been set. + if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + } + ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); + + volatile bool cpus_up = false; + + while (!cpus_up){ + cpus_up = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + cpus_up &= s_cpu_up[i]; + } + ets_delay_us(100); + } + } +} +#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + +static void intr_matrix_clear(void) +{ + for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { + intr_matrix_set(0, i, ETS_INVALID_INUM); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + intr_matrix_set(1, i, ETS_INVALID_INUM); +#endif + } +} + +/* + * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, + * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. + */ +void IRAM_ATTR call_start_cpu0(void) +{ +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + RESET_REASON rst_reas[SOC_CPU_CORES_NUM]; +#else + RESET_REASON rst_reas[1]; +#endif + + bootloader_init_mem(); + + // Move exception vectors to IRAM + cpu_hal_set_vecbase(&_init_start); + + rst_reas[0] = rtc_get_reset_reason(0); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + +#ifndef CONFIG_BOOTLOADER_WDT_ENABLE + // from panic handler we can be reset by RWDT or TG0WDT + if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET +#endif + ) { + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + } +#endif + + //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. + memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + +#if defined(CONFIG_IDF_TARGET_ESP32) && defined(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) + // Clear IRAM BSS + memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); +#endif + + /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ + if (rst_reas[0] != DEEPSLEEP_RESET) { + memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); + } + +#if CONFIG_IDF_TARGET_ESP32S2 + /* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */ + extern void esp_config_instruction_cache_mode(void); + esp_config_instruction_cache_mode(); + + /* If we need use SPIRAM, we should use data cache, or if we want to access rodata, we also should use data cache. + Configure the mode of data : cache size, cache associated ways, cache line size. + Enable data cache, so if we don't use SPIRAM, it just works. */ +#if CONFIG_SPIRAM_BOOT_INIT + extern void esp_config_data_cache_mode(void); + esp_config_data_cache_mode(); + Cache_Enable_DCache(0); +#endif +#endif + +#if CONFIG_SPIRAM_BOOT_INIT + esp_spiram_init_cache(); + if (esp_spiram_init() != ESP_OK) { +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); + abort(); +#endif +#endif + +#if CONFIG_SPIRAM_IGNORE_NOTFOUND + ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); + g_spiram_ok = false; +#else + ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); + abort(); +#endif + } +#endif + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + s_cpu_up[0] = true; +#endif + ESP_EARLY_LOGI(TAG, "Pro cpu up."); + +#if SOC_CPU_CORES_NUM > 1 // there is no 'single-core mode' for natively single-core processors +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + start_other_core(); +#else + ESP_EARLY_LOGI(TAG, "Single core mode"); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); // stop the other core +#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +#endif // SOC_CPU_CORES_NUM > 1 + +#if CONFIG_SPIRAM_MEMTEST + if (g_spiram_ok) { + bool ext_ram_ok = esp_spiram_test(); + if (!ext_ram_ok) { + ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); + abort(); + } + } +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + extern void instruction_flash_page_info_init(void); + instruction_flash_page_info_init(); +#endif +#if CONFIG_SPIRAM_RODATA + extern void rodata_flash_page_info_init(void); + rodata_flash_page_info_init(); +#endif + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + extern void esp_spiram_enable_instruction_access(void); + esp_spiram_enable_instruction_access(); +#endif +#if CONFIG_SPIRAM_RODATA + extern void esp_spiram_enable_rodata_access(void); + esp_spiram_enable_rodata_access(); +#endif + +#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP || CONFIG_ESP32S2_DATA_CACHE_WRAP + uint32_t icache_wrap_enable = 0, dcache_wrap_enable = 0; +#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP + icache_wrap_enable = 1; +#endif +#if CONFIG_ESP32S2_DATA_CACHE_WRAP + dcache_wrap_enable = 1; +#endif + extern void esp_enable_cache_wrap(uint32_t icache_wrap_enable, uint32_t dcache_wrap_enable); + esp_enable_cache_wrap(icache_wrap_enable, dcache_wrap_enable); +#endif +#endif // CONFIG_IDF_TARGET_ESP32S2 + +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); +#endif + +//Enable trace memory and immediately start trace. +#if CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX +#if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_ESP32_TRAX_TWOBANKS + trax_enable(TRAX_ENA_PRO_APP); + #else + trax_enable(TRAX_ENA_PRO); + #endif +#elif CONFIG_IDF_TARGET_ESP32S2 + trax_enable(TRAX_ENA_PRO); +#endif + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif // CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX + + esp_clk_init(); + esp_perip_clk_init(); + intr_matrix_clear(); + +#ifndef CONFIG_ESP_CONSOLE_UART_NONE + const int uart_clk_freq = APB_CLK_FREQ; + uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); +#endif + + rtcio_hal_unhold_all(); + + esp_cache_err_int_init(); + +#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_ESP32S2_MEMPROT_FEATURE +#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK + esp_memprot_set_prot(true, true); +#else + esp_memprot_set_prot(true, false); +#endif +#endif +#endif + + bootloader_flash_update_id(); +#if CONFIG_IDF_TARGET_ESP32 +#if !CONFIG_SPIRAM_BOOT_INIT + // Read the application binary image header. This will also decrypt the header if the image is encrypted. + esp_image_header_t fhdr = {0}; +#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM + fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO; + fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M; + fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB; + + extern void esp_rom_spiflash_attach(uint32_t, bool); + esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false); + esp_rom_spiflash_unlock(); +#else + // This assumes that DROM is the first segment in the application binary, i.e. that we can read + // the binary header through cache by accessing SOC_DROM_LOW address. + memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr)); +#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM + + // If psram is uninitialized, we need to improve some flash configuration. + bootloader_flash_clock_config(&fhdr); + bootloader_flash_gpio_config(&fhdr); + bootloader_flash_dummy_config(&fhdr); + bootloader_flash_cs_timing_config(); +#endif //!CONFIG_SPIRAM_BOOT_INIT +#endif + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + s_cpu_inited[0] = true; + + volatile bool cpus_inited = false; + + while (!cpus_inited) { + cpus_inited = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + cpus_inited &= s_cpu_inited[i]; + } + ets_delay_us(100); + } +#endif + + SYS_STARTUP_FN(); +} \ No newline at end of file diff --git a/components/esp_system/port/esp32/CMakeLists.txt b/components/esp_system/port/esp32/CMakeLists.txt index ca83bcc618..e07df9ed2a 100644 --- a/components/esp_system/port/esp32/CMakeLists.txt +++ b/components/esp_system/port/esp32/CMakeLists.txt @@ -1,2 +1,4 @@ -target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S" - "${CMAKE_CURRENT_LIST_DIR}/reset_reason.c") +set(srcs "dport_panic_highint_hdl.S" "clk.c" "reset_reason.c") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/esp32/clk.c b/components/esp_system/port/esp32/clk.c new file mode 100644 index 0000000000..247f4e0f0a --- /dev/null +++ b/components/esp_system/port/esp32/clk.c @@ -0,0 +1,315 @@ + +// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/rtc.h" +#include "soc/dport_reg.h" +#include "soc/dport_access.h" +#include "xtensa/core-macros.h" +#include "soc/i2s_reg.h" +#include "driver/periph_ctrl.h" +#include "bootloader_clock.h" +#include "hal/wdt_hal.h" + +#include "driver/spi_common_internal.h" // [refactor-todo]: for spicommon_periph_in_use + +#include "esp_log.h" + +#include "esp32/clk.h" +#include "esp32/rom/uart.h" +#include "esp32/rom/rtc.h" + +#include "sdkconfig.h" + +static const char* TAG = "clk"; + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES + +#ifdef CONFIG_ESP32_RTC_XTAL_CAL_RETRY +#define RTC_XTAL_CAL_RETRY CONFIG_ESP32_RTC_XTAL_CAL_RETRY +#else +#define RTC_XTAL_CAL_RETRY 1 +#endif + +/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. + * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. + */ +#define MIN_32K_XTAL_CAL_VAL 15000000L + +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +{ + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = RTC_XTAL_CAL_RETRY; + + do { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; + } + } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); + } + rtc_clk_slow_freq_set(rtc_slow_freq); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void esp_clk_init(void) +{ + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + rtc_init(cfg); + +#if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK) + /* Check the bootloader set the XTAL frequency. + + Bootloaders pre-v2.1 don't do this. + */ + rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); + if (xtal_freq == RTC_XTAL_FREQ_AUTO) { + ESP_EARLY_LOGW(TAG, "RTC domain not initialised by bootloader"); + bootloader_clock_configure(); + } +#else + /* If this assertion fails, either upgrade the bootloader or enable CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS */ + assert(rtc_clk_xtal_freq_get() != RTC_XTAL_FREQ_AUTO); +#endif + + rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); +#else + select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + rtc_clk_cpu_freq_set_config(&new_config); + + // Re calculate the ccount to make time calculation correct. + XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + +#if CONFIG_FREERTOS_UNICORE + RESET_REASON rst_reas[1]; +#else + RESET_REASON rst_reas[2]; +#endif + + rst_reas[0] = rtc_get_reset_reason(0); + +#if !CONFIG_FREERTOS_UNICORE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if ((rst_reas[0] >= TGWDT_CPU_RESET && rst_reas[0] <= RTCWDT_CPU_RESET) +#if !CONFIG_FREERTOS_UNICORE + || (rst_reas[1] >= TGWDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) +#endif + ) { + common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERI_CLK_EN_REG); + wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); + } + else { + common_perip_clk = DPORT_WDG_CLK_EN | + DPORT_PCNT_CLK_EN | + DPORT_LEDC_CLK_EN | + DPORT_TIMERGROUP1_CLK_EN | + DPORT_PWM0_CLK_EN | + DPORT_CAN_CLK_EN | + DPORT_PWM1_CLK_EN | + DPORT_PWM2_CLK_EN | + DPORT_PWM3_CLK_EN; + hwcrypto_perip_clk = DPORT_PERI_EN_AES | + DPORT_PERI_EN_SHA | + DPORT_PERI_EN_RSA | + DPORT_PERI_EN_SECUREBOOT; + wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | + DPORT_WIFI_CLK_BT_EN_M | + DPORT_WIFI_CLK_UNUSED_BIT5 | + DPORT_WIFI_CLK_UNUSED_BIT12 | + DPORT_WIFI_CLK_SDIOSLAVE_EN | + DPORT_WIFI_CLK_SDIO_HOST_EN | + DPORT_WIFI_CLK_EMAC_EN; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 2 + DPORT_UART2_CLK_EN | +#endif + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_UHCI1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_I2C_EXT1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI_DMA_CLK_EN; + + common_perip_clk &= ~DPORT_SPI01_CLK_EN; + +#if CONFIG_SPIRAM_SPEED_80M +//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in +//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' +//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should +//not modify that state, regardless of what we calculated earlier. + if (spicommon_periph_in_use(HSPI_HOST)) { + common_perip_clk &= ~DPORT_SPI2_CLK_EN; + } + if (spicommon_periph_in_use(VSPI_HOST)) { + common_perip_clk &= ~DPORT_SPI3_CLK_EN; + } +#endif + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(0), I2S_CLKA_ENA); + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(1), I2S_CLKA_ENA); + + /* Disable some peripheral clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); + + /* Disable hardware crypto clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, hwcrypto_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +} \ No newline at end of file diff --git a/components/esp_system/port/esp32/intr.c b/components/esp_system/port/esp32/intr.c new file mode 100644 index 0000000000..59ca2756ec --- /dev/null +++ b/components/esp_system/port/esp32/intr.c @@ -0,0 +1,15 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + diff --git a/components/esp_system/port/esp32s2/CMakeLists.txt b/components/esp_system/port/esp32s2/CMakeLists.txt index ca83bcc618..e07df9ed2a 100644 --- a/components/esp_system/port/esp32s2/CMakeLists.txt +++ b/components/esp_system/port/esp32s2/CMakeLists.txt @@ -1,2 +1,4 @@ -target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S" - "${CMAKE_CURRENT_LIST_DIR}/reset_reason.c") +set(srcs "dport_panic_highint_hdl.S" "clk.c" "reset_reason.c") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/esp32s2/clk.c b/components/esp_system/port/esp32s2/clk.c new file mode 100644 index 0000000000..e516df44f1 --- /dev/null +++ b/components/esp_system/port/esp32s2/clk.c @@ -0,0 +1,318 @@ + +// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp32s2/clk.h" +#include "esp_clk_internal.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/uart.h" +#include "esp32s2/rom/rtc.h" +#include "soc/system_reg.h" +#include "soc/dport_access.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "hal/wdt_hal.h" +#include "soc/rtc_periph.h" +#include "soc/i2s_reg.h" +#include "driver/periph_ctrl.h" +#include "xtensa/core-macros.h" +#include "bootloader_clock.h" +#include "soc/syscon_reg.h" + +static const char *TAG = "clk"; + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES + +#ifdef CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY +#define RTC_XTAL_CAL_RETRY CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY +#else +#define RTC_XTAL_CAL_RETRY 1 +#endif + +/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. + * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. + */ +#define MIN_32K_XTAL_CAL_VAL 15000000L + +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 90 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); + +void esp_clk_init(void) +{ + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + RESET_REASON rst_reas; + rst_reas = rtc_get_reset_reason(0); + if (rst_reas == POWERON_RESET) { + cfg.cali_ocode = 1; + } + rtc_init(cfg); + + assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); + + rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 90kHz to 32kHz, then the timeout set for the WDT will increase 2.8 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 90kHz to 32kHz then WDT timeout will increased to 1.6sec * 90/32 = 4.5 sec). + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); +#else + select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + rtc_clk_cpu_freq_set_config(&new_config); + + // Re calculate the ccount to make time calculation correct. + XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); +} + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +{ + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = RTC_XTAL_CAL_RETRY; + + do { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 90 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; + } + } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); + } + rtc_clk_slow_freq_set(rtc_slow_freq); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + uint32_t common_perip_clk1 = 0; + + RESET_REASON rst_reas[1]; + + rst_reas[0] = rtc_get_reset_reason(0); + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if (rst_reas[0] >= TG0WDT_CPU_RESET && + rst_reas[0] <= TG0WDT_CPU_RESET && + rst_reas[0] != RTCWDT_BROWN_OUT_RESET) { + common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN1_REG); + wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); + } else { + common_perip_clk = DPORT_WDG_CLK_EN | + DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif + DPORT_USB_CLK_EN | + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_PCNT_CLK_EN | + DPORT_LEDC_CLK_EN | + DPORT_TIMERGROUP1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_SPI4_CLK_EN | + DPORT_PWM0_CLK_EN | + DPORT_CAN_CLK_EN | + DPORT_PWM1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI2_DMA_CLK_EN | + DPORT_SPI3_DMA_CLK_EN | + DPORT_PWM2_CLK_EN | + DPORT_PWM3_CLK_EN; + common_perip_clk1 = 0; + hwcrypto_perip_clk = DPORT_CRYPTO_AES_CLK_EN | + DPORT_CRYPTO_SHA_CLK_EN | + DPORT_CRYPTO_RSA_CLK_EN; + wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | + DPORT_WIFI_CLK_BT_EN_M | + DPORT_WIFI_CLK_UNUSED_BIT5 | + DPORT_WIFI_CLK_UNUSED_BIT12 | + DPORT_WIFI_CLK_SDIOSLAVE_EN | + DPORT_WIFI_CLK_SDIO_HOST_EN | + DPORT_WIFI_CLK_EMAC_EN; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif + DPORT_USB_CLK_EN | + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_UHCI1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_SPI4_CLK_EN | + DPORT_I2C_EXT1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI2_DMA_CLK_EN | + DPORT_SPI3_DMA_CLK_EN; + common_perip_clk1 = 0; + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + + /* Disable some peripheral clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); + + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, common_perip_clk1); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, common_perip_clk1); + + /* Disable hardware crypto clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + + /* Enable WiFi MAC and POWER clocks */ + DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN); + + /* Set WiFi light sleep clock source to RTC slow clock */ + DPORT_REG_SET_FIELD(DPORT_BT_LPCK_DIV_INT_REG, DPORT_BT_LPCK_DIV_NUM, 0); + DPORT_CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_8M); + DPORT_SET_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_RTC_SLOW); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +} \ No newline at end of file diff --git a/components/esp32/esp_clk_internal.h b/components/esp_system/port/include/esp_clk_internal.h similarity index 100% rename from components/esp32/esp_clk_internal.h rename to components/esp_system/port/include/esp_clk_internal.h diff --git a/components/esp_system/port/include/intr.h b/components/esp_system/port/include/intr.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c new file mode 100644 index 0000000000..85d0507c07 --- /dev/null +++ b/components/esp_system/startup.c @@ -0,0 +1,378 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "esp_attr.h" +#include "esp_err.h" + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_ota_ops.h" + +#include "sdkconfig.h" + +#include "soc/soc_caps.h" +#include "hal/wdt_hal.h" + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_heap_caps_init.h" +#include "esp_spi_flash.h" +#include "esp_flash_internal.h" +#include "esp_newlib.h" +#include "esp_vfs_dev.h" +#include "esp_timer.h" +#include "esp_efuse.h" +#include "esp_flash_encrypt.h" + +/***********************************************/ +// Headers for other components init functions +#include "nvs_flash.h" +#include "esp_phy_init.h" +#include "esp_coexist_internal.h" +#include "esp_core_dump.h" +#include "esp_app_trace.h" +#include "esp_private/dbg_stubs.h" +#include "esp_flash_encrypt.h" +#include "esp_pm.h" +#include "esp_private/pm_impl.h" +#include "esp_pthread.h" + +// [refactor-todo] make this file completely target-independent +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/uart.h" +#include "esp32/rom/ets_sys.h" +#include "esp32/spiram.h" +#include "esp32/brownout.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/uart.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/spiram.h" +#include "esp32s2/brownout.h" +#endif +/***********************************************/ + +#include "esp_private/startup_internal.h" + +// Ensure that system configuration matches the underlying number of cores. +// This should enable us to avoid checking for both everytime. +#if !(SOC_CPU_CORES_NUM > 1) && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "System has been configured to run on multiple cores, but target SoC only has a single core." +#endif + +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + +// App entry point for core 0 +extern void start_app(void); + +// Entry point for core 0 from hardware init (port layer) +void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +// Entry point for core [1..X] from hardware init (port layer) +void start_cpu_other_cores(void) __attribute__((weak, alias("start_cpu_other_cores_default"))) __attribute__((noreturn)); + +// App entry point for core [1..X] +void start_app_other_cores(void) __attribute__((weak, alias("start_app_other_cores_default"))) __attribute__((noreturn)); + +static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false }; + +sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0, +#if SOC_CPU_CORES_NUM > 1 + [1 ... SOC_CPU_CORES_NUM - 1] = start_cpu_other_cores +#endif +}; + +static volatile bool s_system_full_inited = false; +#else +sys_startup_fn_t g_startup_fn[1] = { start_cpu0 }; +#endif + +static const char* TAG = "cpu_start"; + +static void IRAM_ATTR do_global_ctors(void) +{ + extern void (*__init_array_start)(void); + extern void (*__init_array_end)(void); + +#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS + struct object { long placeholder[ 10 ]; }; + void __register_frame_info (const void *begin, struct object *ob); + extern char __eh_frame[]; + + static struct object ob; + __register_frame_info( __eh_frame, &ob ); +#endif + + void (**p)(void); + for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { + (*p)(); + } +} + +static void IRAM_ATTR do_system_init_fn(void) +{ + extern esp_system_init_fn_t _esp_system_init_fn_array_start; + extern esp_system_init_fn_t _esp_system_init_fn_array_end; + + esp_system_init_fn_t *p; + + for (p = &_esp_system_init_fn_array_end - 1; p >= &_esp_system_init_fn_array_start; --p) { + if (p->cores & BIT(cpu_hal_get_core_id())) { + (*(p->fn))(); + } + } + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + s_system_inited[cpu_hal_get_core_id()] = true; +#endif +} + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +static void IRAM_ATTR start_app_other_cores_default(void) +{ + while (1) { + ets_delay_us(UINT32_MAX); + } +} + +static void IRAM_ATTR start_cpu_other_cores_default(void) +{ + do_system_init_fn(); + + while (!s_system_full_inited) { + ets_delay_us(100); + } + + start_app_other_cores(); +} +#endif + +static void IRAM_ATTR do_core_init(void) +{ + /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted. + If the heap allocator is initialized first, it will put free memory linked list items into + memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory, + corrupting those linked lists. Initializing the allocator *after* the app cpu has booted + works around this problem. + With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the + app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may + fail initializing it properly. */ + heap_caps_init(); + esp_setup_syscall_table(); + + if (g_spiram_ok) { +#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) + esp_err_t r=esp_spiram_add_to_heapalloc(); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); + abort(); + } +#if CONFIG_SPIRAM_USE_MALLOC + heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); +#endif +#endif + } + +#if CONFIG_ESP32_BROWNOUT_DET || CONFIG_ESP32S2_BROWNOUT_DET + // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) -> + // malloc (newlib) -> heap_caps_malloc (heap), so heap must be at least initialized + esp_brownout_init(); +#endif + +#ifdef CONFIG_VFS_SUPPORT_IO + esp_vfs_dev_uart_register(); +#endif // CONFIG_VFS_SUPPORT_IO + +#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + esp_reent_init(_GLOBAL_REENT); + const char *default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); + _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); + _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); + _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); +#else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); +#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + +#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED + esp_flash_encryption_init_checks(); +#endif + +#if CONFIG_SECURE_DISABLE_ROM_DL_MODE + err = esp_efuse_disable_rom_download_mode(); + assert(err == ESP_OK && "Failed to disable ROM download mode"); +#endif + +#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE + err = esp_efuse_enable_rom_secure_download_mode(); + assert(err == ESP_OK && "Failed to enable Secure Download mode"); +#endif + +#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE + esp_efuse_disable_basic_rom_console(); +#endif + + esp_err_t err; + + esp_timer_init(); + esp_set_time_from_rtc(); + + // [refactor-todo] move this to secondary init +#if CONFIG_APPTRACE_ENABLE + err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); +#endif +#if CONFIG_SYSVIEW_ENABLE + SEGGER_SYSVIEW_Conf(); +#endif + +#if CONFIG_ESP_DEBUG_STUBS_ENABLE + esp_dbg_stubs_init(); +#endif + + err = esp_pthread_init(); + assert(err == ESP_OK && "Failed to init pthread module!"); + + spi_flash_init(); + /* init default OS-aware flash access critical section */ + spi_flash_guard_set(&g_flash_guard_default_ops); + + esp_flash_app_init(); + esp_err_t flash_ret = esp_flash_init_default_chip(); + assert(flash_ret == ESP_OK); +} + +static void IRAM_ATTR do_secondary_init(void) +{ +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + // The port layer transferred control to this function with other cores 'paused', + // resume execution so that cores might execute component initialization functions. + startup_resume_other_cores(); +#endif + + // Execute initialization functions esp_system_init_fn_t assigned to the main core. While + // this is happening, all other cores are executing the initialization functions + // assigned to them since they have been resumed already. + do_system_init_fn(); + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + // Wait for all cores to finish secondary init. + volatile bool system_inited = false; + + while (!system_inited) { + system_inited = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + system_inited &= s_system_inited[i]; + } + ets_delay_us(100); + } +#endif +} + +void IRAM_ATTR start_cpu0_default(void) +{ + ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); + + // Display information about the current running image. + if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { + const esp_app_desc_t *app_desc = esp_ota_get_app_description(); + ESP_EARLY_LOGI(TAG, "Application information:"); +#ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR + ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name); +#endif +#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR + ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version); +#endif +#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION + ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version); +#endif +#ifdef CONFIG_APP_COMPILE_TIME_DATE + ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time); +#endif + char buf[17]; + esp_ota_get_app_elf_sha256(buf, sizeof(buf)); + ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf); + ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); + } + + // Initialize core components and services. + do_core_init(); + + // Execute constructors. + do_global_ctors(); + + // Execute init functions of other components; blocks + // until all cores finish (when !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE). + do_secondary_init(); + + // Now that the application is about to start, disable boot watchdog +#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + s_system_full_inited = true; +#endif + + start_app(); + while (1); +} + +IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) +{ +#ifdef CONFIG_PM_ENABLE + const int uart_clk_freq = REF_CLK_FREQ; + /* When DFS is enabled, use REFTICK as UART clock source */ + CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); + uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); +#endif // CONFIG_ESP_CONSOLE_UART_NONE + +#ifdef CONFIG_PM_ENABLE + esp_pm_impl_init(); +#ifdef CONFIG_PM_DFS_INIT_AUTO + int xtal_freq = (int) rtc_clk_xtal_freq_get(); + esp_pm_config_esp32_t cfg = { + .max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, + .min_freq_mhz = xtal_freq, + }; + esp_pm_configure(&cfg); +#endif //CONFIG_PM_DFS_INIT_AUTO +#endif //CONFIG_PM_ENABLE + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_ENABLE_COREDUMP + esp_core_dump_init(); +#endif +#endif + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + esp_coex_adapter_register(&g_coex_adapter_funcs); + coex_pre_init(); +#endif +#endif + +#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE + const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); + if (efuse_partition) { + esp_efuse_init(efuse_partition->address, efuse_partition->size); + } +#endif +} \ No newline at end of file diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 6471d32622..5ca3475825 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -62,3 +62,11 @@ set_source_files_properties( PROPERTIES COMPILE_DEFINITIONS _ESP_FREERTOS_INTERNAL ) + +# The freertos component provides the `start_app` and `start_app_other_cores` +# if it is included in the build. It then calls `app_main` +# from the main task created, which must be provided by the user. +# Like for `start_app` and `start_app_other_cores`, +# we can't establish dependency on what we don't yet know, so we force the +# linker to not drop this symbol. +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") \ No newline at end of file diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index de7a368ff7..834067280c 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -1,9 +1,9 @@ menu "FreeRTOS" config FREERTOS_UNICORE - # This config variable is also checked in the ESP32 startup code, not only in FreeRTOS. bool "Run FreeRTOS only on first core" - default n + default "y" if IDF_TARGET_ESP32S2 + select ESP_SYSTEM_SINGLE_CORE_MODE help This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want to start it on the first core. diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index dbf0824bed..9c9fa0dc3d 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -103,6 +103,7 @@ #include "esp_debug_helpers.h" #include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" #include "esp_private/crosscore_int.h" #include "esp_intr_alloc.h" @@ -110,12 +111,37 @@ #include "sdkconfig.h" #include "esp_compiler.h" +#include "esp_task_wdt.h" +#include "esp_task.h" + +#include "soc/soc_caps.h" +#include "soc/efuse_reg.h" +#include "soc/dport_access.h" +#include "soc/dport_reg.h" +#include "esp_int_wdt.h" + + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/spiram.h" +#endif + +#include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok +#include "esp_app_trace.h" // [refactor-todo] for esp_app_trace_init + /* Defined in portasm.h */ extern void _frxt_tick_timer_init(void); /* Defined in xtensa_context.S */ extern void _xt_coproc_init(void); +extern void app_main(void); + +static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but + // for now maintain the same log output #if CONFIG_FREERTOS_CORETIMER_0 #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) @@ -127,10 +153,10 @@ extern void _xt_coproc_init(void); _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); /*-----------------------------------------------------------*/ -unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting +volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit -BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; -BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; +BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; +BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; /*-----------------------------------------------------------*/ // User exception dispatcher when exiting @@ -385,12 +411,12 @@ uint32_t xPortGetTickRateHz(void) { void __attribute__((optimize("-O3"))) vPortEnterCritical(portMUX_TYPE *mux) { BaseType_t oldInterruptLevel = portENTER_CRITICAL_NESTED(); - /* Interrupts may already be disabled (because we're doing this recursively) + /* Interrupts may already be disabled (because we're doing this recursively) * but we can't get the interrupt level after * vPortCPUAquireMutex, because it also may mess with interrupts. * Get it here first, then later figure out if we're nesting * and save for real there. - */ + */ vPortCPUAcquireMutex( mux ); BaseType_t coreID = xPortGetCoreID(); BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1; @@ -408,7 +434,7 @@ void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) vPortCPUReleaseMutex( mux ); BaseType_t coreID = xPortGetCoreID(); BaseType_t nesting = port_uxCriticalNesting[coreID]; - + if(nesting > 0U) { nesting--; @@ -434,4 +460,133 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c dest = strcat(dest, str[i]); } esp_system_abort(buf); +} + + +static void main_task(void* args) +{ +#if !CONFIG_FREERTOS_UNICORE + // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack + while (port_xSchedulerRunning[1] == 0) { + ; + } +#endif + + // [refactor-todo] check if there is a way to move the following block to esp_system startup + heap_caps_enable_nonos_stack_heaps(); + + // Now we have startup stack RAM available for heap, enable any DMA pool memory +#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL + if (g_spiram_ok) { + esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); + abort(); + } + } +#endif + + //Initialize task wdt if configured to do so +#ifdef CONFIG_ESP_TASK_WDT_PANIC + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); +#elif CONFIG_ESP_TASK_WDT + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); +#endif + + //Add IDLE 0 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); + } +#endif + //Add IDLE 1 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); + } +#endif + + app_main(); + vTaskDelete(NULL); +} + +// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) +// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +// should mirror each other's values. +// +// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE. +#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores." +#endif + + +#if !CONFIG_FREERTOS_UNICORE +void start_app_other_cores(void) +{ + // For now, we only support up to two core: 0 and 1. + if (xPortGetCoreID() >= 2) { + abort(); + } + + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + +#if CONFIG_APPTRACE_ENABLE + // [refactor-todo] move to esp_system initialization + esp_err_t err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); +#endif + +#if CONFIG_ESP_INT_WDT + //Initialize the interrupt watch dog for CPU1. + esp_int_wdt_cpu_init(); +#endif + + esp_crosscore_int_init(); + esp_dport_access_int_init(); + + ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); + xPortStartScheduler(); + abort(); /* Only get to here if FreeRTOS somehow very broken */ +} +#endif + +void start_app(void) +{ +#if CONFIG_ESP_INT_WDT + esp_int_wdt_init(); + //Initialize the interrupt watch dog for CPU0. + esp_int_wdt_cpu_init(); +#else +#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX + assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); +#endif +#endif + + esp_crosscore_int_init(); + +#ifndef CONFIG_FREERTOS_UNICORE + esp_dport_access_int_init(); +#endif + + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, 0); + assert(res == pdTRUE); + + // ESP32 has single core variants. Check that FreeRTOS has been configured properly. +#if CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE + if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGE(TAG, "Running on single core chip, but FreeRTOS is built with dual core support."); + ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); + abort(); + } +#endif // CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE + + ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); } \ No newline at end of file diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index cdff0519e5..95e182c1f0 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -82,6 +82,11 @@ esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg); */ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p); +/** + * @brief Initialize pthread library + */ +esp_err_t esp_pthread_init(void); + #ifdef __cplusplus } #endif diff --git a/components/soc/soc/esp32/include/soc/soc_caps.h b/components/soc/soc/esp32/include/soc/soc_caps.h index bb01067af8..9c4a19ef53 100644 --- a/components/soc/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/soc/esp32/include/soc/soc_caps.h @@ -12,4 +12,4 @@ #define SOC_CAN_SUPPORTED 1 #define SOC_EMAC_SUPPORTED 1 -#define SOC_CPU_CORES_NUM 2 +#define SOC_CPU_CORES_NUM 2 \ No newline at end of file diff --git a/components/soc/src/hal/cpu_hal.c b/components/soc/src/hal/cpu_hal.c index 1da4ff29ae..02898e6bf9 100644 --- a/components/soc/src/hal/cpu_hal.c +++ b/components/soc/src/hal/cpu_hal.c @@ -22,6 +22,14 @@ #include "soc/cpu_caps.h" +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/ets_sys.h" +#endif + #if SOC_CPU_BREAKPOINTS_NUM > 0 void cpu_hal_set_breakpoint(int id, const void* addr) { @@ -59,4 +67,4 @@ void cpu_hal_clear_watchpoint(int id) void cpu_hal_set_vecbase(const void* base) { cpu_ll_set_vecbase(base); -} +} \ No newline at end of file diff --git a/components/soc/test/test_rtc_clk.c b/components/soc/test/test_rtc_clk.c index 36480d0381..717acb713c 100644 --- a/components/soc/test/test_rtc_clk.c +++ b/components/soc/test/test_rtc_clk.c @@ -10,7 +10,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" -#include "../esp_clk_internal.h" + +extern void rtc_clk_select_rtc_slow_clk(void); #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2) diff --git a/components/xtensa/debug_helpers.c b/components/xtensa/debug_helpers.c index 06c7f9b23f..788f2b8c14 100644 --- a/components/xtensa/debug_helpers.c +++ b/components/xtensa/debug_helpers.c @@ -20,6 +20,8 @@ #include "soc/soc_memory_layout.h" #include "soc/cpu.h" +#include "sdkconfig.h" + #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32S2 diff --git a/components/xtensa/trax.c b/components/xtensa/trax.c index 725e677d4e..0bddcb341b 100644 --- a/components/xtensa/trax.c +++ b/components/xtensa/trax.c @@ -30,12 +30,12 @@ static const char* TAG = "trax"; int trax_start_trace(trax_downcount_unit_t units_until_stop) { #if !WITH_TRAX - ESP_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); + ESP_EARLY_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif uint32_t v; if (eri_read(ERI_TRAX_TRAXSTAT)&TRAXSTAT_TRACT) { - ESP_LOGI(TAG, "Stopping active trace first."); + ESP_EARLY_LOGI(TAG, "Stopping active trace first."); //Trace is active. Stop trace. eri_write(ERI_TRAX_DELAYCNT, 0); eri_write(ERI_TRAX_TRAXCTRL, eri_read(ERI_TRAX_TRAXCTRL)|TRAXCTRL_TRSTP); @@ -54,7 +54,7 @@ int trax_start_trace(trax_downcount_unit_t units_until_stop) int trax_trigger_traceend_after_delay(int delay) { #if !WITH_TRAX - ESP_LOGE(TAG, "Trax_trigger_traceend_after_delay called, but trax is disabled in menuconfig!"); + ESP_EARLY_LOGE(TAG, "Trax_trigger_traceend_after_delay called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif eri_write(ERI_TRAX_DELAYCNT, delay); diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index 7803653945..cdcb1ff95e 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -499,8 +499,8 @@ ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>` :ref:`CONFIG_FREERTOS_UNICORE` will run ESP-IDF FreeRTOS only on **PRO_CPU**. Note that this is **not equivalent to running vanilla - FreeRTOS**. Behaviors of multiple components in ESP-IDF will be modified such - as :component_file:`esp32/cpu_start.c`. For more details regarding the + FreeRTOS**. Note that this option may affect behavior of components other than + :component:`freertos`. For more details regarding the effects of running ESP-IDF FreeRTOS on a single core, search for occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components. diff --git a/tools/ci/test_build_system.sh b/tools/ci/test_build_system.sh index bc8632647b..5c09a05e1b 100755 --- a/tools/ci/test_build_system.sh +++ b/tools/ci/test_build_system.sh @@ -69,9 +69,9 @@ function run_tests() print_status "Updating component source file rebuilds component" # touch a file & do a build take_build_snapshot - touch ${IDF_PATH}/components/esp32/cpu_start.c + touch ${IDF_PATH}/components/esp_system/port/cpu_start.c make || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp32/libesp32.a esp32/cpu_start.o + assert_rebuilt ${APP_BINS} esp_system/libesp_system.a esp_system/port/cpu_start.o assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} partitions_singleapp.bin print_status "Bootloader source file rebuilds bootloader" @@ -251,12 +251,12 @@ function run_tests() echo "project-version-2.0(012345678901234567890123456789)" > ${TESTDIR}/template/version.txt make assert_rebuilt ${APP_BINS} - assert_not_rebuilt ${BOOTLOADER_BINS} esp32/libesp32.a + assert_not_rebuilt ${BOOTLOADER_BINS} esp_system/libesp_system.a print_status "Re-building does not change app.bin" take_build_snapshot make - assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp32/libesp32.a + assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp_system/libesp_system.a rm -f ${TESTDIR}/template/version.txt print_status "Get the version of app from git describe. Project is not inside IDF and do not have a tag only a hash commit." diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 9f8ddc43ec..ad6eb60edd 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -72,9 +72,9 @@ function run_tests() print_status "Updating component source file rebuilds component" # touch a file & do a build take_build_snapshot - touch ${IDF_PATH}/components/esp32/cpu_start.c + touch ${IDF_PATH}/components/esp_system/port/cpu_start.c idf.py build || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp-idf/esp32/libesp32.a esp-idf/esp32/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp32.dir/cpu_start.c.obj + assert_rebuilt ${APP_BINS} esp-idf/esp_system/libesp_system.a esp-idf/esp_system/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp_system.dir/port/cpu_start.c.obj assert_not_rebuilt esp-idf/lwip/liblwip.a esp-idf/freertos/libfreertos.a ${BOOTLOADER_BINS} ${PARTITION_BIN} print_status "Bootloader source file rebuilds bootloader" @@ -109,12 +109,12 @@ function run_tests() echo "project-version-2.0(012345678901234567890123456789)" > ${TESTDIR}/template/version.txt idf.py build || failure "Failed to rebuild with changed app version" assert_rebuilt ${APP_BINS} - assert_not_rebuilt ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a + assert_not_rebuilt ${BOOTLOADER_BINS} esp-idf/esp_system/libesp_system.a print_status "Re-building does not change app.bin" take_build_snapshot idf.py build - assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a + assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp-idf/esp_system/libesp_system.a rm -f ${IDF_PATH}/version.txt rm -f ${TESTDIR}/template/version.txt