Quellcode durchsuchen

esp32: Fix backwards compatibility for pre-v2.1 bootloaders

Older bootloaders don't set RTC_XTAL_FREQ_REG or call rtc_clk_init(),
app needs to pick this up.

Reported at
https://esp32.com/viewtopic.php?f=2&t=3939&p=17836
Angus Gratton vor 8 Jahren
Ursprung
Commit
c69af42b96

+ 2 - 42
components/bootloader/subproject/main/bootloader_start.c

@@ -48,6 +48,7 @@
 #include "bootloader_flash.h"
 #include "bootloader_random.h"
 #include "bootloader_config.h"
+#include "bootloader_clock.h"
 
 #include "flash_qio_mode.h"
 
@@ -75,7 +76,6 @@ static void set_cache_and_start_app(uint32_t drom_addr,
 static void update_flash_config(const esp_image_header_t* pfhdr);
 static void vddsdio_configure();
 static void flash_gpio_configure();
-static void clock_configure(void);
 static void uart_console_configure(void);
 static void wdt_reset_check(void);
 
@@ -447,7 +447,7 @@ void bootloader_main()
 {
     vddsdio_configure();
     flash_gpio_configure();
-    clock_configure();
+    bootloader_clock_configure();
     uart_console_configure();
     wdt_reset_check();
     ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
@@ -835,46 +835,6 @@ static void IRAM_ATTR flash_gpio_configure()
     }
 }
 
-static void clock_configure(void)
-{
-    // ROM bootloader may have put a lot of text into UART0 FIFO.
-    // Wait for it to be printed.
-    // This is not needed on power on reset, when ROM bootloader is running at
-    // 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
-    // and will be done with the bootloader much earlier than UART FIFO is empty.
-    uart_tx_wait_idle(0);
-
-    /* Set CPU to 80MHz. Keep other clocks unmodified. */
-    rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
-
-    /* On ESP32 rev 0, switching to 80MHz if clock was previously set to
-     * 240 MHz may cause the chip to lock up (see section 3.5 of the errata
-     * document). For rev. 0, switch to 240 instead if it was chosen in
-     * menuconfig.
-     */
-    uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
-    if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
-            CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
-        cpu_freq = RTC_CPU_FREQ_240M;
-    }
-
-    rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
-    clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
-    clk_cfg.cpu_freq = cpu_freq;
-    clk_cfg.slow_freq = rtc_clk_slow_freq_get();
-    clk_cfg.fast_freq = rtc_clk_fast_freq_get();
-    rtc_clk_init(clk_cfg);
-    /* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
-     * it here. Usually it needs some time to start up, so we amortize at least
-     * part of the start up time by enabling 32k XTAL early.
-     * App startup code will wait until the oscillator has started up.
-     */
-#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
-    if (!rtc_clk_32k_enabled()) {
-        rtc_clk_32k_bootstrap();
-    }
-#endif
-}
 
 static void uart_console_configure(void)
 {

+ 21 - 0
components/bootloader_support/include/bootloader_clock.h

@@ -0,0 +1,21 @@
+// Copyright 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
+
+/** @brief Configure clocks for early boot
+ *
+ * Called by bootloader, or by the app if the bootloader version is old (pre v2.1).
+ */
+void bootloader_clock_configure(void);

+ 61 - 0
components/bootloader_support/src/bootloader_clock.c

@@ -0,0 +1,61 @@
+// Copyright 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 "rom/uart.h"
+#include "rom/rtc.h"
+#include "soc/soc.h"
+#include "soc/rtc.h"
+#include "soc/dport_reg.h"
+#include "soc/efuse_reg.h"
+#include "soc/rtc_cntl_reg.h"
+
+void bootloader_clock_configure()
+{
+    // ROM bootloader may have put a lot of text into UART0 FIFO.
+    // Wait for it to be printed.
+    // This is not needed on power on reset, when ROM bootloader is running at
+    // 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
+    // and will be done with the bootloader much earlier than UART FIFO is empty.
+    uart_tx_wait_idle(0);
+
+    /* Set CPU to 80MHz. Keep other clocks unmodified. */
+    rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
+
+    /* On ESP32 rev 0, switching to 80MHz if clock was previously set to
+     * 240 MHz may cause the chip to lock up (see section 3.5 of the errata
+     * document). For rev. 0, switch to 240 instead if it was chosen in
+     * menuconfig.
+     */
+    uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
+    if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
+            CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
+        cpu_freq = RTC_CPU_FREQ_240M;
+    }
+
+    rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
+    clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
+    clk_cfg.cpu_freq = cpu_freq;
+    clk_cfg.slow_freq = rtc_clk_slow_freq_get();
+    clk_cfg.fast_freq = rtc_clk_fast_freq_get();
+    rtc_clk_init(clk_cfg);
+    /* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
+     * it here. Usually it needs some time to start up, so we amortize at least
+     * part of the start up time by enabling 32k XTAL early.
+     * App startup code will wait until the oscillator has started up.
+     */
+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+    if (!rtc_clk_32k_enabled()) {
+        rtc_clk_32k_bootstrap();
+    }
+#endif
+}

+ 16 - 0
components/esp32/Kconfig

@@ -776,6 +776,22 @@ config ESP_TIMER_PROFILING
 		used for timer storage, and should only be used for debugging/testing
 		purposes.
 
+config COMPATIBLE_PRE_V2_1_BOOTLOADERS
+    bool "App compatible with bootloaders before IDF v2.1"
+    default n
+    help
+        Bootloaders before IDF v2.1 did less initialisation of the
+        system clock. This setting needs to be enabled to build an app
+        which can be booted by these older bootloaders.
+
+        If this setting is enabled, the app can be booted by any bootloader
+        from IDF v1.0 up to the current version.
+
+        If this setting is disabled, the app can only be booted by bootloaders
+        from IDF v2.1 or newer.
+
+        Enabling this setting adds approximately 1KB to the app's IRAM usage.
+
 endmenu  # ESP32-Specific
 
 menu Wi-Fi

+ 17 - 1
components/esp32/clk.c

@@ -27,10 +27,10 @@
 #include "soc/soc.h"
 #include "soc/rtc.h"
 #include "soc/rtc_cntl_reg.h"
-#include "soc/dport_reg.h"
 #include "soc/i2s_reg.h"
 #include "driver/periph_ctrl.h"
 #include "xtensa/core-macros.h"
+#include "bootloader_clock.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
@@ -54,6 +54,22 @@ void esp_clk_init(void)
 {
     rtc_config_t cfg = RTC_CONFIG_DEFAULT();
     rtc_init(cfg);
+
+#ifdef CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS
+    /* 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_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_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL

+ 13 - 2
components/soc/esp32/include/soc/rtc.h

@@ -149,13 +149,24 @@ void rtc_clk_init(rtc_clk_config_t cfg);
 /**
  * @brief Get main XTAL frequency
  *
- * This is the value passed to rtc_clk_init function, or if the value was
- * RTC_XTAL_FREQ_AUTO, the detected XTAL frequency.
+ * This is the value stored in RTC register RTC_XTAL_FREQ_REG by the bootloader. As passed to
+ * rtc_clk_init function, or if the value was RTC_XTAL_FREQ_AUTO, the detected
+ * XTAL frequency.
  *
  * @return XTAL frequency, one of rtc_xtal_freq_t
  */
 rtc_xtal_freq_t rtc_clk_xtal_freq_get();
 
+/**
+ * @brief Update XTAL frequency
+ *
+ * Updates the XTAL value stored in RTC_XTAL_FREQ_REG. Usually this value is ignored
+ * after startup.
+ *
+ * @param xtal_freq New frequency value
+ */
+void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq);
+
 /**
  * @brief Enable or disable 32 kHz XTAL oscillator
  * @param en  true to enable, false to disable