From c69af42b96a36afc3b74e1b52f4dcbc1eadffeb5 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 15 Dec 2017 10:32:53 +1100 Subject: [PATCH] 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 --- .../subproject/main/bootloader_start.c | 44 +------------ .../include/bootloader_clock.h | 21 +++++++ .../bootloader_support/src/bootloader_clock.c | 61 +++++++++++++++++++ components/esp32/Kconfig | 16 +++++ components/esp32/clk.c | 18 +++++- components/soc/esp32/include/soc/rtc.h | 15 ++++- 6 files changed, 130 insertions(+), 45 deletions(-) create mode 100644 components/bootloader_support/include/bootloader_clock.h create mode 100644 components/bootloader_support/src/bootloader_clock.c diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index 83e681189..56839e2f8 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/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) { diff --git a/components/bootloader_support/include/bootloader_clock.h b/components/bootloader_support/include/bootloader_clock.h new file mode 100644 index 000000000..9eaba46a8 --- /dev/null +++ b/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); diff --git a/components/bootloader_support/src/bootloader_clock.c b/components/bootloader_support/src/bootloader_clock.c new file mode 100644 index 000000000..2937210da --- /dev/null +++ b/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 +} diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 426045ad2..888bba17e 100644 --- a/components/esp32/Kconfig +++ b/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 diff --git a/components/esp32/clk.c b/components/esp32/clk.c index 4c6209762..369542eee 100644 --- a/components/esp32/clk.c +++ b/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 diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index 1b64d0073..fa34caaa8 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/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