From 1b608a1c0757529c54b701961f97fd17195f6149 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Fri, 31 Mar 2023 19:46:27 +0800 Subject: [PATCH] esp_system: Do not rely on bootloader cache settings, do cache settings unconditionally at startup app It makes multicore app runnable by unicore bootloader Closes https://github.com/espressif/esp-idf/issues/10714 --- .../bootloader_support/src/bootloader_init.c | 8 ++++ components/esp_system/port/cpu_start.c | 45 +++++++++++++++++++ components/hal/esp32/include/hal/cache_ll.h | 32 +++++++++++++ components/hal/esp32s3/include/hal/cache_ll.h | 31 +++++++++++++ 4 files changed, 116 insertions(+) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 932cac265c..3fc18415d7 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -94,4 +94,12 @@ void bootloader_print_banner(void) { ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER); ESP_LOGI(TAG, "compile time " __TIME__); + +#if CONFIG_FREERTOS_UNICORE +#if (SOC_CPU_CORES_NUM > 1) + ESP_EARLY_LOGW(TAG, "Unicore bootloader"); +#endif +#else + ESP_EARLY_LOGI(TAG, "Multicore bootloader"); +#endif } diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 913bfb6144..f2c18f7237 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -70,6 +70,10 @@ #include "hal/wdt_hal.h" #include "soc/rtc.h" #include "soc/efuse_reg.h" +#if (SOC_CPU_CORES_NUM > 1) +#include "hal/cache_ll.h" +#endif +#include "hal/efuse_ll.h" #include "soc/periph_defs.h" #include "soc/cpu.h" #include "soc/rtc.h" @@ -244,6 +248,39 @@ static void start_other_core(void) esp_rom_delay_us(100); } } + +// This function is needed to make the multicore app runnable on a unicore bootloader (built with FREERTOS UNICORE). +// It does some cache settings for other CPUs. +void IRAM_ATTR do_multicore_settings(void) +{ + // We intentionally do not check the cache settings before changing them, + // because it helps to get the application to run on older bootloaders. +#ifdef CONFIG_IDF_TARGET_ESP32 + if (!efuse_ll_get_disable_app_cpu()) { + Cache_Read_Disable(1); + Cache_Flush(1); + DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); + DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); + // We do not enable cache for CPU1 now because it will be done later in start_other_core(). + } +#endif + + cache_bus_mask_t cache_bus_mask_core0 = cache_ll_l1_get_enabled_bus(0); +#ifndef CONFIG_IDF_TARGET_ESP32 + // 1. disable the cache before changing its settings. + Cache_Disable_ICache(); + Cache_Disable_DCache(); +#endif + for (unsigned core = 1; core < SOC_CPU_CORES_NUM; core++) { + // 2. change cache settings. All cores must have the same settings. + cache_ll_l1_enable_bus(core, cache_bus_mask_core0); + } +#ifndef CONFIG_IDF_TARGET_ESP32 + // 3. enable the cache after changing its settings. + Cache_Enable_ICache(0); + Cache_Enable_DCache(0); +#endif +} #endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE /* @@ -312,6 +349,14 @@ void IRAM_ATTR call_start_cpu0(void) memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); } +#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + ESP_EARLY_LOGI(TAG, "Unicore app"); +#else + ESP_EARLY_LOGI(TAG, "Multicore app"); + // It helps to fix missed cache settings for other cores. It happens when bootloader is unicore. + do_multicore_settings(); +#endif + #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); diff --git a/components/hal/esp32/include/hal/cache_ll.h b/components/hal/esp32/include/hal/cache_ll.h index 7157eff9c5..ec7dd87d94 100644 --- a/components/hal/esp32/include/hal/cache_ll.h +++ b/components/hal/esp32/include/hal/cache_ll.h @@ -55,6 +55,38 @@ static inline void cache_ll_l1_enable_bus(uint32_t cache_id, cache_bus_mask_t ma } } +/** + * Returns enabled buses for a given core + * + * @param cache_id cache ID (when l1 cache is per core) + * + * @return State of enabled buses + */ +__attribute__((always_inline)) +static inline cache_bus_mask_t cache_ll_l1_get_enabled_bus(uint32_t cache_id) +{ + cache_bus_mask_t mask = 0; + HAL_ASSERT(cache_id == 0 || cache_id == 1); + if (cache_id == 0) { + uint32_t bus_mask= DPORT_REG_READ(DPORT_PRO_CACHE_CTRL1_REG); + mask |= (!(bus_mask & DPORT_PRO_CACHE_MASK_IRAM0)) ? CACHE_BUS_IBUS0 : 0; + mask |= (!(bus_mask & DPORT_PRO_CACHE_MASK_IRAM1)) ? CACHE_BUS_IBUS1 : 0; + mask |= (!(bus_mask & DPORT_PRO_CACHE_MASK_IROM0)) ? CACHE_BUS_IBUS2 : 0; + + mask |= (!(bus_mask & DPORT_PRO_CACHE_MASK_DROM0)) ? CACHE_BUS_DBUS0 : 0; + mask |= (!(bus_mask & DPORT_PRO_CACHE_MASK_DRAM1)) ? CACHE_BUS_DBUS1 : 0; + } else { + uint32_t bus_mask= DPORT_REG_READ(DPORT_APP_CACHE_CTRL1_REG); + mask |= (!(bus_mask & DPORT_APP_CACHE_MASK_IRAM0)) ? CACHE_BUS_IBUS0 : 0; + mask |= (!(bus_mask & DPORT_APP_CACHE_MASK_IRAM1)) ? CACHE_BUS_IBUS1 : 0; + mask |= (!(bus_mask & DPORT_APP_CACHE_MASK_IROM0)) ? CACHE_BUS_IBUS2 : 0; + + mask |= (!(bus_mask & DPORT_APP_CACHE_MASK_DROM0)) ? CACHE_BUS_DBUS0 : 0; + mask |= (!(bus_mask & DPORT_APP_CACHE_MASK_DRAM1)) ? CACHE_BUS_DBUS1 : 0; + } + return mask; +} + /** * Disable the Cache Buses * diff --git a/components/hal/esp32s3/include/hal/cache_ll.h b/components/hal/esp32s3/include/hal/cache_ll.h index c4de594de1..58125d0a3f 100644 --- a/components/hal/esp32s3/include/hal/cache_ll.h +++ b/components/hal/esp32s3/include/hal/cache_ll.h @@ -49,6 +49,37 @@ static inline void cache_ll_l1_enable_bus(uint32_t cache_id, cache_bus_mask_t ma REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, dbus_mask); } +/** + * Returns enabled buses for a given core + * + * @param cache_id cache ID (when l1 cache is per core) + * + * @return State of enabled buses + */ +__attribute__((always_inline)) +static inline cache_bus_mask_t cache_ll_l1_get_enabled_bus(uint32_t cache_id) +{ + cache_bus_mask_t mask = 0; + HAL_ASSERT(cache_id == 0 || cache_id == 1); + //On esp32s3, only `CACHE_BUS_IBUS0` and `CACHE_BUS_DBUS0` are supported. Use `cache_ll_l1_get_bus()` to get your bus first + + uint32_t ibus_mask = REG_READ(EXTMEM_ICACHE_CTRL1_REG); + if (cache_id == 0) { + mask |= (!(ibus_mask & EXTMEM_ICACHE_SHUT_CORE0_BUS)) ? CACHE_BUS_IBUS0 : 0; + } else { + mask |= (!(ibus_mask & EXTMEM_ICACHE_SHUT_CORE1_BUS)) ? CACHE_BUS_IBUS0 : 0; + } + + uint32_t dbus_mask = REG_READ(EXTMEM_DCACHE_CTRL1_REG); + if (cache_id == 1) { + mask |= (!(dbus_mask & EXTMEM_DCACHE_SHUT_CORE0_BUS)) ? CACHE_BUS_DBUS0 : 0; + } else { + mask |= (!(dbus_mask & EXTMEM_DCACHE_SHUT_CORE1_BUS)) ? CACHE_BUS_DBUS0 : 0; + } + + return mask; +} + /** * Disable the Cache Buses *