From d37a419dfcbf439da6f59b8827b3db531036d2fc Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 12 Feb 2020 13:57:58 +0100 Subject: [PATCH 1/7] esp_pm: esp_pm_dump_locks: don't print from a critical section --- components/esp_common/src/pm_locks.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/components/esp_common/src/pm_locks.c b/components/esp_common/src/pm_locks.c index 0784676da1..002057290a 100644 --- a/components/esp_common/src/pm_locks.c +++ b/components/esp_common/src/pm_locks.c @@ -173,26 +173,35 @@ esp_err_t esp_pm_dump_locks(FILE* stream) fprintf(stream, "Lock stats:\n"); esp_pm_lock_t* it; + char line[64]; SLIST_FOREACH(it, &s_list, next) { + char *buf = line; + size_t len = sizeof(line) - 1; + line[len] = 0; + size_t cb; + portENTER_CRITICAL(&it->spinlock); if (it->name == NULL) { - fprintf(stream, "lock@%p ", it); + cb = snprintf(buf, len, "lock@%p ", it); } else { - fprintf(stream, "%-15s ", it->name); + cb = snprintf(buf, len, "%-15s ", it->name); } + buf += cb; + len -= cb; #ifdef WITH_PROFILING pm_time_t time_held = it->time_held; if (it->count > 0) { time_held += cur_time - it->last_taken; } - fprintf(stream, "%10s %3d %3d %9d %9lld %3lld%%\n", + snprintf(buf, len, "%10s %3d %3d %9d %9lld %3lld%%\n", s_lock_type_names[it->type], it->arg, it->count, it->times_taken, time_held, (time_held + cur_time_d100 - 1) / cur_time_d100); #else - fprintf(stream, "%10s %3d %3d\n", s_lock_type_names[it->type], it->arg, it->count); + snprintf(buf, len, "%10s %3d %3d\n", s_lock_type_names[it->type], it->arg, it->count); #endif // WITH_PROFILING portEXIT_CRITICAL(&it->spinlock); + fputs(line, stream); } _lock_release(&s_list_lock); #ifdef WITH_PROFILING From d2d3269159870a8c848d8627c5696a9a1904d347 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 12 Feb 2020 12:41:52 +0100 Subject: [PATCH 2/7] esp32s2: sync esp_pm code from esp32 --- components/esp32s2/cpu_start.c | 9 +- components/esp32s2/include/esp32s2/pm.h | 6 +- components/esp32s2/pm_esp32s2.c | 244 +++++++++++++----------- components/esp32s2/pm_trace.c | 12 +- 4 files changed, 141 insertions(+), 130 deletions(-) diff --git a/components/esp32s2/cpu_start.c b/components/esp32s2/cpu_start.c index 4d1d37e89e..f25cb3b075 100644 --- a/components/esp32s2/cpu_start.c +++ b/components/esp32s2/cpu_start.c @@ -317,11 +317,10 @@ void start_cpu0_default(void) #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO - rtc_cpu_freq_t max_freq; - rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &max_freq); - esp_pm_config_esp32_t cfg = { - .max_cpu_freq = max_freq, - .min_cpu_freq = RTC_CPU_FREQ_XTAL + 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 diff --git a/components/esp32s2/include/esp32s2/pm.h b/components/esp32s2/include/esp32s2/pm.h index a7cbf0eac7..dac31e0c9c 100644 --- a/components/esp32s2/include/esp32s2/pm.h +++ b/components/esp32s2/include/esp32s2/pm.h @@ -31,10 +31,10 @@ extern "C" { * Pass a pointer to this structure as an argument to esp_pm_configure function. */ typedef struct { - rtc_cpu_freq_t max_cpu_freq; /*!< Maximum CPU frequency to use */ - rtc_cpu_freq_t min_cpu_freq; /*!< Minimum CPU frequency to use when no frequency locks are taken */ + int max_freq_mhz; /*!< Maximum CPU frequency, in MHz */ + int min_freq_mhz; /*!< Minimum CPU frequency to use when no locks are taken, in MHz */ bool light_sleep_enable; /*!< Enter light sleep when no locks are taken */ -} esp_pm_config_esp32_t; +} esp_pm_config_esp32s2_t; #ifdef __cplusplus diff --git a/components/esp32s2/pm_esp32s2.c b/components/esp32s2/pm_esp32s2.c index 7368c7b902..2bfd4c351d 100644 --- a/components/esp32s2/pm_esp32s2.c +++ b/components/esp32s2/pm_esp32s2.c @@ -1,4 +1,4 @@ -// Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD +// Copyright 2016-2020 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. @@ -35,6 +35,7 @@ #include "esp_private/pm_trace.h" #include "esp_private/esp_timer_private.h" #include "esp32s2/pm.h" +#include "esp_sleep.h" /* CCOMPARE update timeout, in CPU cycles. Any value above ~600 cycles will work * for the purpose of detecting a deadlock. @@ -51,6 +52,9 @@ */ #define LIGHT_SLEEP_EARLY_WAKEUP_US 100 +/* Minimal divider at which REF_CLK_FREQ can be obtained */ +#define REF_CLK_DIV_MIN 2 + #ifdef CONFIG_PM_PROFILING #define WITH_PROFILING #endif @@ -75,49 +79,42 @@ static uint32_t s_mode_mask; static uint32_t s_ccount_div; static uint32_t s_ccount_mul; +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +/* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU. + * This in turn gets used in IDLE hook to decide if `waiti` needs + * to be invoked or not. + */ +static bool s_skipped_light_sleep[portNUM_PROCESSORS]; + +#if portNUM_PROCESSORS == 2 +/* When light sleep is finished on one CPU, it is possible that the other CPU + * will enter light sleep again very soon, before interrupts on the first CPU + * get a chance to run. To avoid such situation, set a flag for the other CPU to + * skip light sleep attempt. + */ +static bool s_skip_light_sleep[portNUM_PROCESSORS]; +#endif // portNUM_PROCESSORS == 2 +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + /* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU. * Used in conjunction with cross-core interrupt to update CCOMPARE on the other CPU. */ static volatile bool s_need_update_ccompare[portNUM_PROCESSORS]; -/* When no RTOS tasks are active, these locks are released to allow going into - * a lower power mode. Used by ISR hook and idle hook. - */ -static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS]; - /* A flag indicating that Idle hook has run on a given CPU; * Next interrupt on the same CPU will take s_rtos_lock_handle. */ static bool s_core_idle[portNUM_PROCESSORS]; -/* g_ticks_us defined in ROM for PRO CPU */ -extern uint32_t g_ticks_per_us_pro; +/* When no RTOS tasks are active, these locks are released to allow going into + * a lower power mode. Used by ISR hook and idle hook. + */ +static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS]; -/* Lookup table of CPU frequencies to be used in each mode. +/* Lookup table of CPU frequency configs to be used in each mode. * Initialized by esp_pm_impl_init and modified by esp_pm_configure. */ -rtc_cpu_freq_t s_cpu_freq_by_mode[PM_MODE_COUNT]; - -/* Lookup table of CPU ticks per microsecond for each RTC_CPU_FREQ_ value. - * Essentially the same as returned by rtc_clk_cpu_freq_value(), but without - * the function call. Not const because XTAL frequency is only known at run time. - */ -static uint32_t s_cpu_freq_to_ticks[] = { - [RTC_CPU_FREQ_XTAL] = 0, /* This is set by esp_pm_impl_init */ - [RTC_CPU_FREQ_80M] = 80, - [RTC_CPU_FREQ_160M] = 160, - [RTC_CPU_FREQ_240M] = 240, - [RTC_CPU_FREQ_2M] = 2 -}; - -/* Lookup table of names for each RTC_CPU_FREQ_ value. Used for logging only. */ -static const char* s_freq_names[] __attribute__((unused)) = { - [RTC_CPU_FREQ_XTAL] = "XTAL", - [RTC_CPU_FREQ_80M] = "80", - [RTC_CPU_FREQ_160M] = "160", - [RTC_CPU_FREQ_240M] = "240", - [RTC_CPU_FREQ_2M] = "2" -}; +rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT]; /* Whether automatic light sleep is enabled */ static bool s_light_sleep_en = false; @@ -144,7 +141,7 @@ static const char* s_mode_names[] = { #endif // WITH_PROFILING -static const char* TAG = "pm_esp32"; +static const char* TAG = "pm_esp32s2"; static void update_ccompare(void); static void do_switch(pm_mode_t new_mode); @@ -167,74 +164,62 @@ pm_mode_t esp_pm_impl_get_mode(esp_pm_lock_type_t type, int arg) } } -/* rtc_cpu_freq_t enum is not ordered by frequency, so convert to MHz, - * figure out the maximum value, then convert back to rtc_cpu_freq_t. - */ -static rtc_cpu_freq_t max_freq_of(rtc_cpu_freq_t f1, rtc_cpu_freq_t f2) -{ - int f1_hz = rtc_clk_cpu_freq_value(f1); - int f2_hz = rtc_clk_cpu_freq_value(f2); - int f_max_hz = MAX(f1_hz, f2_hz); - rtc_cpu_freq_t result = RTC_CPU_FREQ_XTAL; - if (!rtc_clk_cpu_freq_from_mhz(f_max_hz/1000000, &result)) { - assert(false && "unsupported frequency"); - } - return result; -} - esp_err_t esp_pm_configure(const void* vconfig) { #ifndef CONFIG_PM_ENABLE return ESP_ERR_NOT_SUPPORTED; #endif - const esp_pm_config_esp32_t* config = (const esp_pm_config_esp32_t*) vconfig; + const esp_pm_config_esp32s2_t* config = (const esp_pm_config_esp32s2_t*) vconfig; #ifndef CONFIG_FREERTOS_USE_TICKLESS_IDLE if (config->light_sleep_enable) { return ESP_ERR_NOT_SUPPORTED; } #endif - if (config->min_cpu_freq == RTC_CPU_FREQ_2M) { - /* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */ - return ESP_ERR_NOT_SUPPORTED; - } + int min_freq_mhz = config->min_freq_mhz; + int max_freq_mhz = config->max_freq_mhz; - rtc_cpu_freq_t min_freq = config->min_cpu_freq; - rtc_cpu_freq_t max_freq = config->max_cpu_freq; - int min_freq_mhz = rtc_clk_cpu_freq_value(min_freq); - int max_freq_mhz = rtc_clk_cpu_freq_value(max_freq); if (min_freq_mhz > max_freq_mhz) { return ESP_ERR_INVALID_ARG; } - rtc_cpu_freq_t apb_max_freq = max_freq; /* CPU frequency in APB_MAX mode */ - if (max_freq == RTC_CPU_FREQ_240M) { - /* We can't switch between 240 and 80/160 without disabling PLL, - * so use 240MHz CPU frequency when 80MHz APB frequency is requested. - */ - apb_max_freq = RTC_CPU_FREQ_240M; - } else if (max_freq == RTC_CPU_FREQ_160M || max_freq == RTC_CPU_FREQ_80M) { - /* Otherwise, can use 80MHz - * CPU frequency when 80MHz APB frequency is requested. - */ - apb_max_freq = RTC_CPU_FREQ_80M; + rtc_cpu_freq_config_t freq_config; + if (!rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &freq_config)) { + ESP_LOGW(TAG, "invalid min_freq_mhz value (%d)", min_freq_mhz); + return ESP_ERR_INVALID_ARG; } - apb_max_freq = max_freq_of(apb_max_freq, min_freq); + int xtal_freq_mhz = (int) rtc_clk_xtal_freq_get(); + if (min_freq_mhz < xtal_freq_mhz && min_freq_mhz * MHZ / REF_CLK_FREQ < REF_CLK_DIV_MIN) { + ESP_LOGW(TAG, "min_freq_mhz should be >= %d", REF_CLK_FREQ * REF_CLK_DIV_MIN / MHZ); + return ESP_ERR_INVALID_ARG; + } + + if (!rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &freq_config)) { + ESP_LOGW(TAG, "invalid max_freq_mhz value (%d)", max_freq_mhz); + return ESP_ERR_INVALID_ARG; + } + + int apb_max_freq = MIN(max_freq_mhz, 80); /* CPU frequency in APB_MAX mode */ + apb_max_freq = MAX(apb_max_freq, min_freq_mhz); ESP_LOGI(TAG, "Frequency switching config: " - "CPU_MAX: %s, APB_MAX: %s, APB_MIN: %s, Light sleep: %s", - s_freq_names[max_freq], - s_freq_names[apb_max_freq], - s_freq_names[min_freq], + "CPU_MAX: %d, APB_MAX: %d, APB_MIN: %d, Light sleep: %s", + max_freq_mhz, + apb_max_freq, + min_freq_mhz, config->light_sleep_enable ? "ENABLED" : "DISABLED"); portENTER_CRITICAL(&s_switch_lock); - s_cpu_freq_by_mode[PM_MODE_CPU_MAX] = max_freq; - s_cpu_freq_by_mode[PM_MODE_APB_MAX] = apb_max_freq; - s_cpu_freq_by_mode[PM_MODE_APB_MIN] = min_freq; - s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = min_freq; + bool res; + res = rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_CPU_MAX]); + assert(res); + res = rtc_clk_cpu_freq_mhz_to_config(apb_max_freq, &s_cpu_freq_by_mode[PM_MODE_APB_MAX]); + assert(res); + res = rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_APB_MIN]); + assert(res); + s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = s_cpu_freq_by_mode[PM_MODE_APB_MIN]; s_light_sleep_en = config->light_sleep_enable; s_config_changed = true; portEXIT_CRITICAL(&s_switch_lock); @@ -261,7 +246,7 @@ void IRAM_ATTR esp_pm_impl_switch_mode(pm_mode_t mode, { bool need_switch = false; uint32_t mode_mask = BIT(mode); - portENTER_CRITICAL(&s_switch_lock); + portENTER_CRITICAL_SAFE(&s_switch_lock); uint32_t count; if (lock_or_unlock == MODE_LOCK) { count = ++s_mode_lock_counts[mode]; @@ -288,7 +273,7 @@ void IRAM_ATTR esp_pm_impl_switch_mode(pm_mode_t mode, s_last_mode_change_time = now; #endif // WITH_PROFILING } - portEXIT_CRITICAL(&s_switch_lock); + portEXIT_CRITICAL_SAFE(&s_switch_lock); if (need_switch && new_mode != s_mode) { do_switch(new_mode); } @@ -310,7 +295,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p } /* Calculate new tick divisor */ - _xt_tick_divisor = ticks_per_us * 1000000 / XT_TICK_PER_SEC; + _xt_tick_divisor = ticks_per_us * MHZ / XT_TICK_PER_SEC; int core_id = xPortGetCoreID(); if (s_rtos_lock_handle[core_id] != NULL) { @@ -375,17 +360,18 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode) s_config_changed = false; portEXIT_CRITICAL_ISR(&s_switch_lock); - rtc_cpu_freq_t new_freq = s_cpu_freq_by_mode[new_mode]; - rtc_cpu_freq_t old_freq; + rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode]; + rtc_cpu_freq_config_t old_config; + if (!config_changed) { - old_freq = s_cpu_freq_by_mode[s_mode]; + old_config = s_cpu_freq_by_mode[s_mode]; } else { - old_freq = rtc_clk_cpu_freq_get(); + rtc_clk_cpu_freq_get_config(&old_config); } - if (new_freq != old_freq) { - uint32_t old_ticks_per_us = g_ticks_per_us_pro; - uint32_t new_ticks_per_us = s_cpu_freq_to_ticks[new_freq]; + if (new_config.freq_mhz != old_config.freq_mhz) { + uint32_t old_ticks_per_us = old_config.freq_mhz; + uint32_t new_ticks_per_us = new_config.freq_mhz; bool switch_down = new_ticks_per_us < old_ticks_per_us; @@ -393,7 +379,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode) if (switch_down) { on_freq_update(old_ticks_per_us, new_ticks_per_us); } - rtc_clk_cpu_freq_set_fast(new_freq); + rtc_clk_cpu_freq_set_config_fast(&new_config); if (!switch_down) { on_freq_update(old_ticks_per_us, new_ticks_per_us); } @@ -449,6 +435,28 @@ void esp_pm_impl_idle_hook(void) ESP_PM_TRACE_ENTER(IDLE, core_id); } +void IRAM_ATTR esp_pm_impl_isr_hook(void) +{ + int core_id = xPortGetCoreID(); + ESP_PM_TRACE_ENTER(ISR_HOOK, core_id); + /* Prevent higher level interrupts (than the one this function was called from) + * from happening in this section, since they will also call into esp_pm_impl_isr_hook. + */ + uint32_t state = portENTER_CRITICAL_NESTED(); +#if portNUM_PROCESSORS == 2 + if (s_need_update_ccompare[core_id]) { + update_ccompare(); + s_need_update_ccompare[core_id] = false; + } else { + leave_idle(); + } +#else + leave_idle(); +#endif // portNUM_PROCESSORS == 2 + portEXIT_CRITICAL_NESTED(state); + ESP_PM_TRACE_EXIT(ISR_HOOK, core_id); +} + void esp_pm_impl_waiti(void) { #if CONFIG_FREERTOS_USE_TICKLESS_IDLE @@ -467,30 +475,37 @@ void esp_pm_impl_waiti(void) #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE } -void IRAM_ATTR esp_pm_impl_isr_hook(void) -{ - int core_id = xPortGetCoreID(); - ESP_PM_TRACE_ENTER(ISR_HOOK, core_id); -#if portNUM_PROCESSORS == 2 - if (s_need_update_ccompare[core_id]) { - update_ccompare(); - s_need_update_ccompare[core_id] = false; - } else { - leave_idle(); - } -#else - leave_idle(); -#endif // portNUM_PROCESSORS == 2 - ESP_PM_TRACE_EXIT(ISR_HOOK, core_id); -} - #if CONFIG_FREERTOS_USE_TICKLESS_IDLE -bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) +static inline bool IRAM_ATTR should_skip_light_sleep(int core_id) +{ +#if portNUM_PROCESSORS == 2 + if (s_skip_light_sleep[core_id]) { + s_skip_light_sleep[core_id] = false; + s_skipped_light_sleep[core_id] = true; + return true; + } +#endif // portNUM_PROCESSORS == 2 + if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) { + s_skipped_light_sleep[core_id] = true; + } else { + s_skipped_light_sleep[core_id] = false; + } + return s_skipped_light_sleep[core_id]; +} + +static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id) +{ +#if portNUM_PROCESSORS == 2 + s_skip_light_sleep[!core_id] = true; +#endif +} + +void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) { - bool result = false; portENTER_CRITICAL(&s_switch_lock); - if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) { + int core_id = xPortGetCoreID(); + if (!should_skip_light_sleep(core_id)) { /* Calculate how much we can sleep */ int64_t next_esp_timer_alarm = esp_timer_get_next_alarm(); int64_t now = esp_timer_get_time(); @@ -504,7 +519,6 @@ bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); #endif /* Enter sleep */ - int core_id = xPortGetCoreID(); ESP_PM_TRACE_ENTER(SLEEP, core_id); int64_t sleep_start = esp_timer_get_time(); esp_light_sleep_start(); @@ -526,11 +540,10 @@ bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) ; } } - result = true; + other_core_should_skip_light_sleep(core_id); } } portEXIT_CRITICAL(&s_switch_lock); - return result; } #endif //CONFIG_FREERTOS_USE_TICKLESS_IDLE @@ -554,9 +567,9 @@ void esp_pm_impl_dump_stats(FILE* out) /* don't display light sleep mode if it's not enabled */ continue; } - fprintf(out, "%8s %6s %12lld %2d%%\n", + fprintf(out, "%8s %3dM %12lld %2d%%\n", s_mode_names[i], - s_freq_names[s_cpu_freq_by_mode[i]], + s_cpu_freq_by_mode[i].freq_mhz, time_in_mode[i], (int) (time_in_mode[i] * 100 / now)); } @@ -565,7 +578,6 @@ void esp_pm_impl_dump_stats(FILE* out) void esp_pm_impl_init(void) { - s_cpu_freq_to_ticks[RTC_CPU_FREQ_XTAL] = rtc_clk_xtal_freq_get(); #ifdef CONFIG_PM_TRACE esp_pm_trace_init(); #endif @@ -581,11 +593,11 @@ void esp_pm_impl_init(void) /* Configure all modes to use the default CPU frequency. * This will be modified later by a call to esp_pm_configure. */ - rtc_cpu_freq_t default_freq; - if (!rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &default_freq)) { + rtc_cpu_freq_config_t default_config; + if (!rtc_clk_cpu_freq_mhz_to_config(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &default_config)) { assert(false && "unsupported frequency"); } for (size_t i = 0; i < PM_MODE_COUNT; ++i) { - s_cpu_freq_by_mode[i] = default_freq; + s_cpu_freq_by_mode[i] = default_config; } } diff --git a/components/esp32s2/pm_trace.c b/components/esp32s2/pm_trace.c index cad2e40e2d..db9dbfa2dd 100644 --- a/components/esp32s2/pm_trace.c +++ b/components/esp32s2/pm_trace.c @@ -22,12 +22,12 @@ * Feel free to change when debugging. */ static const int DRAM_ATTR s_trace_io[] = { - BIT(4), BIT(5), // ESP_PM_TRACE_IDLE - BIT(16), BIT(17), // ESP_PM_TRACE_TICK - BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH - BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE - BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK - BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP + BIT(2), 0, // ESP_PM_TRACE_IDLE + BIT(3), 0, // ESP_PM_TRACE_TICK + BIT(4), 0, // ESP_PM_TRACE_FREQ_SWITCH + BIT(5), 0, // ESP_PM_TRACE_CCOMPARE_UPDATE + BIT(6), 0, // ESP_PM_TRACE_ISR_HOOK + BIT(7), 0, // ESP_PM_TRACE_SLEEP }; void esp_pm_trace_init(void) From 74ac618287d4d75208b50c40f5bed6c085e118b6 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 12 Feb 2020 13:56:59 +0100 Subject: [PATCH 3/7] soc/rtc: update frequency switching APIs to match the master branch esp32s2 code was based in IDF v3.1, and used outdated APIs. Closes IDF-670 --- .../bootloader_support/src/bootloader_clock.c | 11 +- components/esp32s2/clk.c | 31 +- components/esp32s2/panic.c | 2 +- components/esp32s2/sleep_modes.c | 8 +- components/esp32s2/system_api_esp32s2.c | 2 +- components/soc/soc/esp32/include/soc/rtc.h | 2 +- components/soc/soc/esp32s2/include/soc/rtc.h | 100 ++-- components/soc/src/esp32s2/CMakeLists.txt | 1 + components/soc/src/esp32s2/rtc_clk.c | 560 +++++++----------- components/soc/src/esp32s2/rtc_clk_common.h | 56 ++ components/soc/src/esp32s2/rtc_clk_init.c | 88 +++ 11 files changed, 433 insertions(+), 428 deletions(-) create mode 100644 components/soc/src/esp32s2/rtc_clk_common.h create mode 100644 components/soc/src/esp32s2/rtc_clk_init.c diff --git a/components/bootloader_support/src/bootloader_clock.c b/components/bootloader_support/src/bootloader_clock.c index 40630a7f77..d3305dfe7c 100644 --- a/components/bootloader_support/src/bootloader_clock.c +++ b/components/bootloader_support/src/bootloader_clock.c @@ -35,15 +35,15 @@ void bootloader_clock_configure(void) // 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. */ + int cpu_freq_mhz = 80; + +#if CONFIG_IDF_TARGET_ESP32 /* On ESP32 rev 0, switching to 80/160 MHz 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 has been enabled * previously. */ -#if CONFIG_IDF_TARGET_ESP32 - /* Set CPU to 80MHz. Keep other clocks unmodified. */ - int cpu_freq_mhz = 80; - uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG); if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 && DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL) == DPORT_CPUPERIOD_SEL_240) { @@ -54,11 +54,10 @@ void bootloader_clock_configure(void) rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT(); #if CONFIG_IDF_TARGET_ESP32 clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ; - clk_cfg.cpu_freq_mhz = cpu_freq_mhz; #elif CONFIG_IDF_TARGET_ESP32S2 clk_cfg.xtal_freq = RTC_XTAL_FREQ_40M; - clk_cfg.cpu_freq = RTC_CPU_FREQ_80M; #endif + clk_cfg.cpu_freq_mhz = cpu_freq_mhz; clk_cfg.slow_freq = rtc_clk_slow_freq_get(); clk_cfg.fast_freq = rtc_clk_fast_freq_get(); rtc_clk_init(clk_cfg); diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 5b579db228..7304a6f1e2 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -86,35 +86,22 @@ void esp_clk_init(void) rtc_wdt_protect_on(); #endif - uint32_t freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; - rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M; - switch (freq_mhz) { - case 240: - freq = RTC_CPU_FREQ_240M; - break; - case 160: - freq = RTC_CPU_FREQ_160M; - break; - case 80: - freq = RTC_CPU_FREQ_80M; - break; - default: - freq_mhz = 80; - freq = RTC_CPU_FREQ_80M; - break; - } + 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); - uint32_t freq_before = rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()) / MHZ ; - - rtc_clk_cpu_freq_set(freq); + rtc_clk_cpu_freq_set_config(&new_config); // Re calculate the ccount to make time calculation correct. - uint32_t freq_after = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; - XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before ); + XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); } int IRAM_ATTR esp_clk_cpu_freq(void) diff --git a/components/esp32s2/panic.c b/components/esp32s2/panic.c index dccfe04676..1209974f89 100644 --- a/components/esp32s2/panic.c +++ b/components/esp32s2/panic.c @@ -476,7 +476,7 @@ static void esp_panic_dig_reset(void) // make sure all the panic handler output is sent from UART FIFO uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); // switch to XTAL (otherwise we will keep running from the PLL) - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL); + rtc_clk_cpu_freq_set_xtal(); // reset the digital part esp_cpu_unstall(PRO_CPU_NUM); SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); diff --git a/components/esp32s2/sleep_modes.c b/components/esp32s2/sleep_modes.c index 529b14085b..17d831f06b 100644 --- a/components/esp32s2/sleep_modes.c +++ b/components/esp32s2/sleep_modes.c @@ -172,8 +172,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) } // Save current frequency and switch to XTAL - rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get(); - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL); + // Save current frequency and switch to XTAL + rtc_cpu_freq_config_t cpu_freq_config; + rtc_clk_cpu_freq_get_config(&cpu_freq_config); + rtc_clk_cpu_freq_set_xtal(); // Configure pins for external wakeup if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { @@ -199,7 +201,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0, 1); // Restore CPU frequency - rtc_clk_cpu_freq_set(cpu_freq); + rtc_clk_cpu_freq_set_config(&cpu_freq_config); // re-enable UART output resume_uarts(); diff --git a/components/esp32s2/system_api_esp32s2.c b/components/esp32s2/system_api_esp32s2.c index 096ea860f4..e4c17b9785 100644 --- a/components/esp32s2/system_api_esp32s2.c +++ b/components/esp32s2/system_api_esp32s2.c @@ -94,7 +94,7 @@ void IRAM_ATTR esp_restart_noos(void) DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0); // Set CPU back to XTAL source, no PLL, same as hard reset - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL); + rtc_clk_cpu_freq_set_xtal(); // Reset CPUs if (core_id == 0) { diff --git a/components/soc/soc/esp32/include/soc/rtc.h b/components/soc/soc/esp32/include/soc/rtc.h index cb999ae1c8..96982a038d 100644 --- a/components/soc/soc/esp32/include/soc/rtc.h +++ b/components/soc/soc/esp32/include/soc/rtc.h @@ -130,7 +130,7 @@ typedef enum { */ typedef struct rtc_clk_config_s { rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency - rtc_cpu_freq_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz + uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz rtc_fast_freq_t fast_freq : 1; //!< RTC_FAST_CLK frequency to set rtc_slow_freq_t slow_freq : 2; //!< RTC_SLOW_CLK frequency to set uint32_t clk_8m_div : 3; //!< RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency) diff --git a/components/soc/soc/esp32s2/include/soc/rtc.h b/components/soc/soc/esp32s2/include/soc/rtc.h index 15156da858..7953510edc 100644 --- a/components/soc/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/soc/esp32s2/include/soc/rtc.h @@ -148,6 +148,26 @@ typedef enum { RTC_CPU_FREQ_XTAL_DIV2 = 7, //!< XTAL/2 after reset } rtc_cpu_freq_t; +/** + * @brief CPU clock source + */ +typedef enum { + RTC_CPU_FREQ_SRC_XTAL, //!< XTAL + RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M) + RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator + RTC_CPU_FREQ_SRC_APLL //!< APLL +} rtc_cpu_freq_src_t; + +/** + * @brief CPU clock configuration structure + */ +typedef struct rtc_cpu_freq_config_s { + rtc_cpu_freq_src_t source; //!< The clock from which CPU clock is derived + uint32_t source_freq_mhz; //!< Source clock frequency + uint32_t div; //!< Divider, freq_mhz = source_freq_mhz / div + uint32_t freq_mhz; //!< CPU clock frequency +} rtc_cpu_freq_config_t; + /** * @brief RTC SLOW_CLK frequency values */ @@ -187,7 +207,7 @@ typedef enum { */ typedef struct { rtc_xtal_freq_t xtal_freq : 8; //!< Main XTAL frequency - rtc_cpu_freq_t cpu_freq : 3; //!< CPU frequency to set + uint32_t cpu_freq_mhz : 10; //!< CPU frequency to set, in MHz rtc_fast_freq_t fast_freq : 1; //!< RTC_FAST_CLK frequency to set rtc_slow_freq_t slow_freq : 2; //!< RTC_SLOW_CLK frequency to set uint32_t clk_rtc_clk_div : 8; @@ -201,7 +221,7 @@ typedef struct { */ #define RTC_CLK_CONFIG_DEFAULT() { \ .xtal_freq = RTC_XTAL_FREQ_40M, \ - .cpu_freq = RTC_CPU_FREQ_80M, \ + .cpu_freq_mhz = 80, \ .fast_freq = RTC_FAST_FREQ_8M, \ .slow_freq = RTC_SLOW_FREQ_RTC, \ .clk_rtc_clk_div = 0, \ @@ -415,63 +435,63 @@ void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq); rtc_fast_freq_t rtc_clk_fast_freq_get(void); /** - * @brief Switch CPU frequency - * - * If a PLL-derived frequency is requested (80, 160, 240 MHz), this function - * will enable the PLL. Otherwise, PLL will be disabled. - * Note: this function is not optimized for switching speed. It may take several - * hundred microseconds to perform frequency switch. - * - * @param cpu_freq new CPU frequency + * @brief Get CPU frequency config for a given frequency + * @param freq_mhz Frequency in MHz + * @param[out] out_config Output, CPU frequency configuration structure + * @return true if frequency can be obtained, false otherwise */ -void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq); +bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config); /** * @brief Switch CPU frequency * - * This is a faster version of rtc_clk_cpu_freq_set, which can handle some of - * the frequency switch paths (XTAL -> PLL, PLL -> XTAL). - * When switching from PLL to XTAL, PLL is not disabled (unlike rtc_clk_cpu_freq_set). - * When switching back from XTAL to PLL, only the same PLL can be used. - * Therefore it is not possible to switch 240 -> XTAL -> (80 or 160) using this - * function. + * This function sets CPU frequency according to the given configuration + * structure. It enables PLLs, if necessary. * - * For unsupported cases, this function falls back to rtc_clk_cpu_freq_set. + * @note This function in not intended to be called by applications in FreeRTOS + * environment. This is because it does not adjust various timers based on the + * new CPU frequency. * - * Unlike rtc_clk_cpu_freq_set, this function relies on static data, so it is - * less safe to use it e.g. from a panic handler (when memory might be corrupted). - * - * @param cpu_freq new CPU frequency + * @param config CPU frequency configuration structure */ -void rtc_clk_cpu_freq_set_fast(rtc_cpu_freq_t cpu_freq); +void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config); /** - * @brief Get the currently selected CPU frequency + * @brief Switch CPU frequency (optimized for speed) * - * Although CPU can be clocked by APLL and RTC 8M sources, such support is not - * exposed through this library. As such, this function will not return - * meaningful values when these clock sources are configured (e.g. using direct - * access to clock selection registers). In debug builds, it will assert; in - * release builds, it will return RTC_CPU_FREQ_XTAL. + * This function is a faster equivalent of rtc_clk_cpu_freq_set_config. + * It works faster because it does not disable PLLs when switching from PLL to + * XTAL and does not enabled them when switching back. If PLL is not already + * enabled when this function is called to switch from XTAL to PLL frequency, + * or the PLL which is enabled is the wrong one, this function will fall back + * to calling rtc_clk_cpu_freq_set_config. * - * @return CPU frequency (one of rtc_cpu_freq_t values) + * Unlike rtc_clk_cpu_freq_set_config, this function relies on static data, + * so it is less safe to use it e.g. from a panic handler (when memory might + * be corrupted). + * + * @note This function in not intended to be called by applications in FreeRTOS + * environment. This is because it does not adjust various timers based on the + * new CPU frequency. + * + * @param config CPU frequency configuration structure */ -rtc_cpu_freq_t rtc_clk_cpu_freq_get(void); +void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config); /** - * @brief Get corresponding frequency value for rtc_cpu_freq_t enum value - * @param cpu_freq CPU frequency, on of rtc_cpu_freq_t values - * @return CPU frequency, in HZ + * @brief Get the currently used CPU frequency configuration + * @param[out] out_config Output, CPU frequency configuration structure */ -uint32_t rtc_clk_cpu_freq_value(rtc_cpu_freq_t cpu_freq); +void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config); /** - * @brief Get rtc_cpu_freq_t enum value for given CPU frequency - * @param cpu_freq_mhz CPU frequency, one of 80, 160, 240, 2, and XTAL frequency - * @param[out] out_val output, rtc_cpu_freq_t value corresponding to the frequency - * @return true if the given frequency value matches one of enum values + * @brief Switch CPU clock source to XTAL + * + * Short form for filling in rtc_cpu_freq_config_t structure and calling + * rtc_clk_cpu_freq_set_config when a switch to XTAL is needed. + * Assumes that XTAL frequency has been determined — don't call in startup code. */ - bool rtc_clk_cpu_freq_from_mhz(int cpu_freq_mhz, rtc_cpu_freq_t* out_val); +void rtc_clk_cpu_freq_set_xtal(void); /** * @brief Store new APB frequency value into RTC_APB_FREQ_REG diff --git a/components/soc/src/esp32s2/CMakeLists.txt b/components/soc/src/esp32s2/CMakeLists.txt index 86cf1c3d39..4fc1eb04c4 100644 --- a/components/soc/src/esp32s2/CMakeLists.txt +++ b/components/soc/src/esp32s2/CMakeLists.txt @@ -1,6 +1,7 @@ set(srcs "brownout_hal.c" "cpu_util.c" "rtc_clk.c" + "rtc_clk_init.c" "rtc_init.c" "rtc_pm.c" "rtc_sleep.c" diff --git a/components/soc/src/esp32s2/rtc_clk.c b/components/soc/src/esp32s2/rtc_clk.c index 0d0ce595c0..3e9234258b 100644 --- a/components/soc/src/esp32s2/rtc_clk.c +++ b/components/soc/src/esp32s2/rtc_clk.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "sdkconfig.h" #include "esp32s2/rom/ets_sys.h" #include "esp32s2/rom/rtc.h" @@ -30,21 +31,19 @@ #include "soc/syscon_reg.h" #include "i2c_rtc_clk.h" #include "soc_log.h" +#include "rtc_clk_common.h" #include "sdkconfig.h" #include "xtensa/core-macros.h" static const char *TAG = "rtc_clk"; -/* PLL currently enabled, if any */ -typedef enum { - RTC_PLL_NONE, - RTC_PLL_320M, - RTC_PLL_480M -} rtc_pll_t; -static rtc_pll_t s_cur_pll = RTC_PLL_NONE; +#define RTC_PLL_FREQ_320M 320 +#define RTC_PLL_FREQ_480M 480 -/* Current CPU frequency; saved in a variable for faster freq. switching */ -static rtc_cpu_freq_t s_cur_freq = RTC_CPU_FREQ_XTAL; +// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. +static int s_cur_pll_freq; + +static void rtc_clk_cpu_freq_to_8m(void); void rtc_clk_32k_enable_internal(x32k_config_t cfg) { @@ -120,25 +119,7 @@ void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1); REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0); - /* BIAS I2C not exist any more, but not sure how to get the same effect yet... - * if (!enable && - * REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL) != DPORT_SOC_CLK_SEL_PLL) { - * REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD); - * } else { - * REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD); - * } - */ - if (enable) { - /* no need to differentiate ECO chip any more - uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1; - uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0); - if (is_rev0) { - sdm0 = 0; - sdm1 = 0; - sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0; - } - */ I2C_WRITEREG_MASK_RTC(I2C_APLL, I2C_APLL_DSDM2, sdm2); I2C_WRITEREG_MASK_RTC(I2C_APLL, I2C_APLL_DSDM0, sdm0); I2C_WRITEREG_MASK_RTC(I2C_APLL, I2C_APLL_DSDM1, sdm1); @@ -226,17 +207,20 @@ rtc_fast_freq_t rtc_clk_fast_freq_get(void) return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL); } -/* In 7.2.2, cpu can run at 80M/160M/240M if PLL is 480M - * pll can run 80M/160M is PLL is 320M - */ -#define DR_REG_I2C_MST_BASE 0x3f40E000 -#define I2C_MST_ANA_STATE_REG (DR_REG_I2C_MST_BASE + 0x040) -#define I2C_MST_BBPLL_CAL_END (BIT(24)) -#define I2C_MST_BBPLL_CAL_END_M (BIT(24)) -#define I2C_MST_BBPLL_CAL_END_V 0x1 -#define I2C_MST_BBPLL_CAL_END_S 24 +static void rtc_clk_bbpll_disable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | + RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD); + s_cur_pll_freq = 0; +} -void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_pll_t pll_freq) +static void rtc_clk_bbpll_enable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | + RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD); +} + +void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) { uint8_t div_ref; uint8_t div7_0; @@ -247,11 +231,8 @@ void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_pll_t pll_freq) assert(xtal_freq == RTC_XTAL_FREQ_40M); - if (pll_freq == RTC_PLL_480M) { - /* Raise the voltage, if needed */ - /* move to 240M logic */ - //REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M); - /* Set this register to let digital know pll is 480M */ + if (pll_freq == RTC_PLL_FREQ_480M) { + /* Clear this register to let the digital part know 480M PLL is used */ SET_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL); /* Configure 480M PLL */ div_ref = 0; @@ -262,11 +243,9 @@ void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_pll_t pll_freq) dcur = 4; I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B); } else { - /* Raise the voltage */ - //REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M); - //ets_delay_us(DELAY_PLL_DBIAS_RAISE); + /* Clear this register to let the digital part know 320M PLL is used */ CLEAR_PERI_REG_MASK(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL); - /* Configure 480M PLL */ + /* Configure 320M PLL */ div_ref = 0; div7_0 = 4; dr1 = 0; @@ -295,280 +274,213 @@ void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_pll_t pll_freq) } if (ext_cap == 15) { SOC_LOGE(TAG, "BBPLL SOFTWARE CAL FAIL"); + abort(); } } - - /* this delay is replaced by polling Pll calibration end flag - * uint32_t delay_pll_en = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ? - * DELAY_PLL_ENABLE_WITH_150K : DELAY_PLL_ENABLE_WITH_32K; - * ets_delay_us(delay_pll_en); - */ - /* this calibration didn't work on 480M - need to test exact delay according to 320M - while (!GET_PERI_REG_MASK(I2C_MST_ANA_STATE_REG, I2C_MST_BBPLL_CAL_END)) { - ets_delay_us(1); - } - */ -} - -/** - * Switch to XTAL frequency. Does not disable the PLL. - */ -static void rtc_clk_cpu_freq_to_xtal(void) -{ - rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); - ets_update_cpu_frequency(xtal_freq); - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); - REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0); - REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 0); - /* Why we need to do this ? */ - //DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 0); // clear DPORT_CPUPERIOD_SEL - - rtc_clk_apb_freq_update(xtal_freq * MHZ); - s_cur_freq = RTC_CPU_FREQ_XTAL; - s_cur_pll = RTC_PLL_NONE; + s_cur_pll_freq = pll_freq; } /** * Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL. * PLL must already be enabled. - * If switching between frequencies derived from different PLLs (320M and 480M), - * fall back to rtc_clk_cpu_freq_set. * @param cpu_freq new CPU frequency */ -static void rtc_clk_cpu_freq_to_pll(rtc_cpu_freq_t cpu_freq) +static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) { - int freq = 0; - if ((s_cur_pll == RTC_PLL_NONE) || ((s_cur_pll == RTC_PLL_320M) && (cpu_freq == RTC_CPU_FREQ_240M))) { - /* - * if switch from non-pll or switch from PLL 320M to 480M - * need to switch PLLs, fall back to full implementation - */ - rtc_clk_cpu_freq_set(cpu_freq); - return; + int dbias = DIG_DBIAS_80M_160M; + int per_conf = DPORT_CPUPERIOD_SEL_80; + if (cpu_freq_mhz == 80) { + /* nothing to do */ + } else if (cpu_freq_mhz == 160) { + per_conf = DPORT_CPUPERIOD_SEL_160; + } else if (cpu_freq_mhz == 240) { + dbias = DIG_DBIAS_240M; + per_conf = DPORT_CPUPERIOD_SEL_240; + } else { + SOC_LOGE(TAG, "invalid frequency"); + abort(); } - - if ((cpu_freq == RTC_CPU_FREQ_80M) || (cpu_freq == RTC_CPU_320M_80M)) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M); - DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 0); - freq = 80; - } else if ((cpu_freq == RTC_CPU_FREQ_160M) || (cpu_freq == RTC_CPU_320M_160M)) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M); - DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 1); - freq = 160; - } else if (cpu_freq == RTC_CPU_FREQ_240M) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M); - DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, 2); - freq = 240; - } - // REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL); - rtc_clk_apb_freq_update(80 * MHZ); - ets_update_cpu_frequency(freq); - s_cur_freq = cpu_freq; -} - -void rtc_clk_cpu_freq_set_fast(rtc_cpu_freq_t cpu_freq) -{ - if (cpu_freq == s_cur_freq) { - return; - } else if (cpu_freq == RTC_CPU_FREQ_2M || s_cur_freq == RTC_CPU_FREQ_2M) { - /* fall back to full implementation if switch to/from 2M is needed */ - rtc_clk_cpu_freq_set(cpu_freq); - } else if (cpu_freq == RTC_CPU_FREQ_XTAL) { - rtc_clk_cpu_freq_to_xtal(); - } else if (cpu_freq > RTC_CPU_FREQ_XTAL) { - rtc_clk_cpu_freq_to_pll(cpu_freq); - /* Not neccessary any more */ - //rtc_clk_wait_for_slow_cycle(); - } -} - -void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq) -{ - rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); - /* Switch CPU to XTAL frequency first */ - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); - REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 0); + REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, per_conf); REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0); - ets_update_cpu_frequency(xtal_freq); - /* Frequency switch is synchronized to SLOW_CLK cycle. Wait until the switch - * is complete before disabling the PLL. - */ - /* register SOC_CLK_SEL is moved to APB domain, so this delay is not neccessary any more */ - //rtc_clk_wait_for_slow_cycle(); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias); + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL); + rtc_clk_apb_freq_update(80 * MHZ); + ets_update_cpu_frequency(cpu_freq_mhz); +} - DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0); +bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config) +{ + uint32_t source_freq_mhz; + rtc_cpu_freq_src_t source; + uint32_t divider; + uint32_t real_freq_mhz; - /* BBPLL force power down won't affect force power up setting */ - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, - RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD | - RTC_CNTL_BBPLL_I2C_FORCE_PD); - s_cur_pll = RTC_PLL_NONE; - rtc_clk_apb_freq_update(xtal_freq * MHZ); + uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get(); + if (freq_mhz <= xtal_freq) { + divider = xtal_freq / freq_mhz; + real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */ + if (real_freq_mhz != freq_mhz) { + // no suitable divider + return false; + } - /* is APLL under force power down? */ - /* may need equivalent function - uint32_t apll_fpd = REG_GET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD); - - * if (apll_fpd) { - * SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD); - * } - */ - - /* now switch to the desired frequency */ - if (cpu_freq == RTC_CPU_FREQ_XTAL) { - /* already at XTAL, nothing to do */ - } else if (cpu_freq == RTC_CPU_FREQ_2M) { - /* set up divider to produce 2MHz from XTAL */ - REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, (xtal_freq / 2) - 1); - ets_update_cpu_frequency(2); - rtc_clk_apb_freq_update(2 * MHZ); - /* lower the voltage */ - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M); - } else { - /* use PLL as clock source */ - CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, - RTC_CNTL_BB_I2C_FORCE_PD | - RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD); - if (cpu_freq > RTC_CPU_FREQ_2M) { - rtc_clk_bbpll_set(xtal_freq, RTC_PLL_320M); - s_cur_pll = RTC_PLL_320M; - } else { - rtc_clk_bbpll_set(xtal_freq, RTC_PLL_480M); - s_cur_pll = RTC_PLL_480M; - } - - if ((cpu_freq == RTC_CPU_FREQ_80M) || (cpu_freq == RTC_CPU_320M_80M)) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M); - DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0); - ets_update_cpu_frequency(80); - } else if ((cpu_freq == RTC_CPU_FREQ_160M) || (cpu_freq == RTC_CPU_320M_160M)) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M); - DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 1); - ets_update_cpu_frequency(160); - } else if (cpu_freq == RTC_CPU_FREQ_240M) { - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M); - DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 2); - ets_update_cpu_frequency(240); - } - REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, 1); - //rtc_clk_wait_for_slow_cycle(); - rtc_clk_apb_freq_update(80 * MHZ); - } - s_cur_freq = cpu_freq; -} - -rtc_cpu_freq_t rtc_clk_cpu_freq_get(void) -{ - uint32_t soc_clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL); - switch (soc_clk_sel) { - case 0: { - uint32_t pre_div = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT); - if (pre_div == 0) { - return RTC_CPU_FREQ_XTAL; - } else if (pre_div == 1) { - return RTC_CPU_FREQ_XTAL_DIV2; - } else if (pre_div == rtc_clk_xtal_freq_get() / 2 - 1) { - return RTC_CPU_FREQ_2M; - } else { - assert(false && "unsupported frequency"); - } - break; - } - case 1: { - uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL); - uint32_t pllfreq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL); - if (cpuperiod_sel == 0) { - if (pllfreq_sel == 1) { - return RTC_CPU_FREQ_80M; - } else { - return RTC_CPU_320M_80M; - } - } else if (cpuperiod_sel == 1) { - if (pllfreq_sel == 1) { - return RTC_CPU_FREQ_160M; - } else { - return RTC_CPU_320M_160M; - } - } else if (cpuperiod_sel == 2) { - return RTC_CPU_FREQ_240M; - } else { - assert(false && "unsupported frequency"); - } - break; - } - case 2: - case 3: - default: - assert(false && "unsupported frequency"); - } - return 0; -} - -uint32_t rtc_clk_cpu_freq_value(rtc_cpu_freq_t cpu_freq) -{ - switch (cpu_freq) { - case RTC_CPU_FREQ_XTAL: - return ((uint32_t) rtc_clk_xtal_freq_get()) * MHZ; - case RTC_CPU_FREQ_XTAL_DIV2: - return ((uint32_t) rtc_clk_xtal_freq_get()) / 2 * MHZ; - case RTC_CPU_FREQ_2M: - return 2 * MHZ; - case RTC_CPU_FREQ_80M: - return 80 * MHZ; - case RTC_CPU_FREQ_160M: - return 160 * MHZ; - case RTC_CPU_FREQ_240M: - return 240 * MHZ; - case RTC_CPU_320M_80M: - return 80 * MHZ; - case RTC_CPU_320M_160M: - return 160 * MHZ; - default: - assert(false && "invalid rtc_cpu_freq_t value"); - return 0; - } -} - -bool rtc_clk_cpu_freq_from_mhz(int mhz, rtc_cpu_freq_t *out_val) -{ - if (mhz == 240) { - *out_val = RTC_CPU_FREQ_240M; - } else if (mhz == 160) { - *out_val = RTC_CPU_FREQ_160M; - } else if (mhz == 80) { - *out_val = RTC_CPU_FREQ_80M; - } else if (mhz == (int) rtc_clk_xtal_freq_get()) { - *out_val = RTC_CPU_FREQ_XTAL; - } else if (mhz == (int) rtc_clk_xtal_freq_get() / 2) { - *out_val = RTC_CPU_FREQ_XTAL_DIV2; - } else if (mhz == 2) { - *out_val = RTC_CPU_FREQ_2M; + source_freq_mhz = xtal_freq; + source = RTC_CPU_FREQ_SRC_XTAL; + } else if (freq_mhz == 80) { + real_freq_mhz = freq_mhz; + source = RTC_CPU_FREQ_SRC_PLL; + source_freq_mhz = RTC_PLL_FREQ_480M; + divider = 6; + } else if (freq_mhz == 160) { + real_freq_mhz = freq_mhz; + source = RTC_CPU_FREQ_SRC_PLL; + source_freq_mhz = RTC_PLL_FREQ_480M; + divider = 3; + } else if (freq_mhz == 240) { + real_freq_mhz = freq_mhz; + source = RTC_CPU_FREQ_SRC_PLL; + source_freq_mhz = RTC_PLL_FREQ_480M; + divider = 2; } else { + // unsupported frequency return false; } + *out_config = (rtc_cpu_freq_config_t) { + .source = source, + .div = divider, + .source_freq_mhz = source_freq_mhz, + .freq_mhz = real_freq_mhz + }; return true; } -/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in - * lower and upper 16-bit halves. These are the routines to work with such a - * representation. +void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config) +{ + rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); + uint32_t soc_clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL); + if (soc_clk_sel != DPORT_SOC_CLK_SEL_XTAL) { + rtc_clk_cpu_freq_to_xtal(xtal_freq, 1); + } + if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) { + rtc_clk_bbpll_disable(); + } + if (config->source == RTC_CPU_FREQ_SRC_XTAL) { + if (config->div > 1) { + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); + } + } else if (config->source == RTC_CPU_FREQ_SRC_PLL) { + rtc_clk_bbpll_enable(); + rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz); + rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz); + } else if (config->source == RTC_CPU_FREQ_SRC_8M) { + rtc_clk_cpu_freq_to_8m(); + } +} + +void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config) +{ + rtc_cpu_freq_src_t source; + uint32_t source_freq_mhz; + uint32_t div; + uint32_t freq_mhz; + uint32_t soc_clk_sel = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL); + switch (soc_clk_sel) { + case DPORT_SOC_CLK_SEL_XTAL: { + source = RTC_CPU_FREQ_SRC_XTAL; + div = REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT) + 1; + source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get(); + freq_mhz = source_freq_mhz / div; + } + break; + case DPORT_SOC_CLK_SEL_PLL: { + source = RTC_CPU_FREQ_SRC_PLL; + uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL); + uint32_t pllfreq_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_PLL_FREQ_SEL); + source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M; + if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4; + freq_mhz = 80; + } else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2; + div = 3; + freq_mhz = 160; + } else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_240) { + div = 2; + freq_mhz = 240; + } else { + SOC_LOGE(TAG, "unsupported frequency configuration"); + abort(); + } + break; + } + case DPORT_SOC_CLK_SEL_8M: + source = RTC_CPU_FREQ_SRC_8M; + source_freq_mhz = 8; + div = 1; + freq_mhz = source_freq_mhz; + break; + case DPORT_SOC_CLK_SEL_APLL: + default: + SOC_LOGE(TAG, "unsupported frequency configuration"); + abort(); + } + *out_config = (rtc_cpu_freq_config_t) { + .source = source, + .source_freq_mhz = source_freq_mhz, + .div = div, + .freq_mhz = freq_mhz + }; +} + +void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config) +{ + if (config->source == RTC_CPU_FREQ_SRC_XTAL) { + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); + } else if (config->source == RTC_CPU_FREQ_SRC_PLL && + s_cur_pll_freq == config->source_freq_mhz) { + rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz); + } else { + /* fallback */ + rtc_clk_cpu_freq_set_config(config); + } +} + +void rtc_clk_cpu_freq_set_xtal(void) +{ + int freq_mhz = (int) rtc_clk_xtal_freq_get(); + + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); + rtc_clk_bbpll_disable(); +} + +/** + * Switch to XTAL frequency. Does not disable the PLL. */ -static bool clk_val_is_valid(uint32_t val) +void rtc_clk_cpu_freq_to_xtal(int freq, int div) { - return (val & 0xffff) == ((val >> 16) & 0xffff) && - val != 0 && - val != UINT32_MAX; + ets_update_cpu_frequency(freq); + /* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */ + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0); + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, div - 1); + /* no need to adjust the REF_TICK */ + /* switch clock source */ + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL); + rtc_clk_apb_freq_update(freq * MHZ); + /* lower the voltage */ + if (freq <= 2) { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M); + } else { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); + } } -static uint32_t reg_val_to_clk_val(uint32_t val) +static void rtc_clk_cpu_freq_to_8m(void) { - return val & UINT16_MAX; -} - -static uint32_t clk_val_to_reg_val(uint32_t val) -{ - return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16); + ets_update_cpu_frequency(8); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_PRE_DIV_CNT, 0); + REG_SET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M); + rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M); } rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) @@ -614,66 +526,6 @@ void rtc_clk_8m_divider_set(uint32_t div) SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); } -void rtc_clk_init(rtc_clk_config_t cfg) -{ - rtc_cpu_freq_t cpu_source_before = rtc_clk_cpu_freq_get(); - /* If we get a TG WDT system reset while running at 240MHz, - * DPORT_CPUPERIOD_SEL register will be reset to 0 resulting in 120MHz - * APB and CPU frequencies after reset. This will cause issues with XTAL - * frequency estimation, so we switch to XTAL frequency first. - * - * Ideally we would only do this if SYSCON_SOC_CLK_SEL == PLL and - * PLL is configured for 480M, but it takes less time to switch to 40M and - * run the following code than querying the PLL does. - */ - if (REG_GET_FIELD(DPORT_SYSCLK_CONF_REG, DPORT_SOC_CLK_SEL) == 1) { - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL); - } - - /* Set tuning parameters for 8M and 150k clocks. - * Note: this doesn't attempt to set the clocks to precise frequencies. - * Instead, we calibrate these clocks against XTAL frequency later, when necessary. - * - SCK_DCAP value controls tuning of 150k clock. - * The higher the value of DCAP is, the lower is the frequency. - * - CK8M_DFREQ value controls tuning of 8M clock. - * CLK_8M_DFREQ constant gives the best temperature characteristics. - */ - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap); - REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq); - - /* Configure 150k clock division */ - rtc_clk_divider_set(cfg.clk_rtc_clk_div); - /* Configure 8M clock division */ - rtc_clk_8m_divider_set(cfg.clk_8m_clk_div); - - /* Enable the internal bus used to configure PLLs */ - SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S); - CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M); - - rtc_xtal_freq_t xtal_freq = cfg.xtal_freq; - uart_tx_wait_idle(0); - rtc_clk_xtal_freq_update(xtal_freq); - rtc_clk_apb_freq_update(xtal_freq * MHZ); - /* Set CPU frequency */ - rtc_clk_cpu_freq_set(cfg.cpu_freq); - - /* Re-calculate the ccount to make time calculation correct. */ - uint32_t freq_before = rtc_clk_cpu_freq_value(cpu_source_before) / MHZ; - uint32_t freq_after = rtc_clk_cpu_freq_value(cfg.cpu_freq) / MHZ; - XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before ); - - /* Slow & fast clocks setup */ - if (cfg.slow_freq == RTC_SLOW_FREQ_32K_XTAL) { - rtc_clk_32k_enable(true); - } - if (cfg.fast_freq == RTC_FAST_FREQ_8M) { - bool need_8md256 = cfg.slow_freq == RTC_SLOW_FREQ_8MD256; - rtc_clk_8m_enable(true, need_8md256); - } - rtc_clk_fast_freq_set(cfg.fast_freq); - rtc_clk_slow_freq_set(cfg.slow_freq); -} - /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/soc/src/esp32s2/rtc_clk_common.h b/components/soc/src/esp32s2/rtc_clk_common.h new file mode 100644 index 0000000000..cb92f67ac2 --- /dev/null +++ b/components/soc/src/esp32s2/rtc_clk_common.h @@ -0,0 +1,56 @@ +// Copyright 2015-2020 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 + +#define MHZ (1000000) + +#define DPORT_CPUPERIOD_SEL_80 0 +#define DPORT_CPUPERIOD_SEL_160 1 +#define DPORT_CPUPERIOD_SEL_240 2 + +#define DPORT_SOC_CLK_SEL_XTAL 0 +#define DPORT_SOC_CLK_SEL_PLL 1 +#define DPORT_SOC_CLK_SEL_8M 2 +#define DPORT_SOC_CLK_SEL_APLL 3 + +#define RTC_FAST_CLK_FREQ_8M 8500000 + +#ifdef __cplusplus +extern "C" { +#endif + +void rtc_clk_cpu_freq_to_xtal(int freq, int div); + +/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in + * lower and upper 16-bit halves. These are the routines to work with such a + * representation. + */ +static inline bool clk_val_is_valid(uint32_t val) { + return (val & 0xffff) == ((val >> 16) & 0xffff) && + val != 0 && + val != UINT32_MAX; +} + +static inline uint32_t reg_val_to_clk_val(uint32_t val) { + return val & UINT16_MAX; +} + +static inline uint32_t clk_val_to_reg_val(uint32_t val) { + return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/src/esp32s2/rtc_clk_init.c b/components/soc/src/esp32s2/rtc_clk_init.c new file mode 100644 index 0000000000..6480e593b1 --- /dev/null +++ b/components/soc/src/esp32s2/rtc_clk_init.c @@ -0,0 +1,88 @@ +// Copyright 2015-2020 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 "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/rtc.h" +#include "esp32s2/rom/uart.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/sens_periph.h" +#include "soc/efuse_periph.h" +#include "soc/apb_ctrl_reg.h" +#include "i2c_rtc_clk.h" +#include "soc_log.h" +#include "sdkconfig.h" +#include "xtensa/core-macros.h" +#include "rtc_clk_common.h" + +static const char* TAG = "rtc_clk_init"; + +void rtc_clk_init(rtc_clk_config_t cfg) +{ + rtc_cpu_freq_config_t old_config, new_config; + + /* Set tuning parameters for 8M and 90k clocks. + * Note: this doesn't attempt to set the clocks to precise frequencies. + * Instead, we calibrate these clocks against XTAL frequency later, when necessary. + * - SCK_DCAP value controls tuning of 90k clock. + * The higher the value of DCAP is, the lower is the frequency. + * - CK8M_DFREQ value controls tuning of 8M clock. + * CLK_8M_DFREQ constant gives the best temperature characteristics. + */ + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap); + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq); + + /* Configure 90k clock division */ + rtc_clk_divider_set(cfg.clk_rtc_clk_div); + + /* Configure 8M clock division */ + rtc_clk_8m_divider_set(cfg.clk_8m_clk_div); + + /* Enable the internal bus used to configure PLLs */ + SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S); + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M); + + rtc_xtal_freq_t xtal_freq = cfg.xtal_freq; + uart_tx_wait_idle(0); + rtc_clk_xtal_freq_update(xtal_freq); + rtc_clk_apb_freq_update(xtal_freq * MHZ); + + /* Set CPU frequency */ + rtc_clk_cpu_freq_get_config(&old_config); + uint32_t freq_before = old_config.freq_mhz; + bool res = rtc_clk_cpu_freq_mhz_to_config(cfg.cpu_freq_mhz, &new_config); + if (!res) { + SOC_LOGE(TAG, "invalid CPU frequency value"); + abort(); + } + 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() * cfg.cpu_freq_mhz / freq_before ); + + /* Slow & fast clocks setup */ + if (cfg.slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + rtc_clk_32k_enable(true); + } + if (cfg.fast_freq == RTC_FAST_FREQ_8M) { + bool need_8md256 = cfg.slow_freq == RTC_SLOW_FREQ_8MD256; + rtc_clk_8m_enable(true, need_8md256); + } + rtc_clk_fast_freq_set(cfg.fast_freq); + rtc_clk_slow_freq_set(cfg.slow_freq); +} From 490bf29767ce057bc4944db23f26b8a9376bfa16 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 12 Feb 2020 18:09:17 +0100 Subject: [PATCH 4/7] esp32s2: fix enabling 32k XTAL clock On the ESP32S2, rtc_clk_cal(RTC_CAL_RTC_MUX) measures the frequency of the 90kHz RTC clock regardless of the selected slow clock frequency. Keep track which clock is selected and pass the argument to rtc_clk_cal accordingly. fix clock choices update rtc 32k xtal code for s2 missed api in rtc.h bootloader_clock: update for S2 --- .../bootloader_support/src/bootloader_clock.c | 14 ++- components/esp32s2/Kconfig | 23 ++++- components/esp32s2/clk.c | 95 ++++++++++++------- components/soc/soc/esp32s2/include/soc/rtc.h | 5 + components/soc/src/esp32s2/rtc_clk.c | 23 ++++- 5 files changed, 116 insertions(+), 44 deletions(-) diff --git a/components/bootloader_support/src/bootloader_clock.c b/components/bootloader_support/src/bootloader_clock.c index d3305dfe7c..09186402b8 100644 --- a/components/bootloader_support/src/bootloader_clock.c +++ b/components/bootloader_support/src/bootloader_clock.c @@ -54,9 +54,8 @@ void bootloader_clock_configure(void) rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT(); #if CONFIG_IDF_TARGET_ESP32 clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ; -#elif CONFIG_IDF_TARGET_ESP32S2 - clk_cfg.xtal_freq = RTC_XTAL_FREQ_40M; #endif + /* ESP32-S2 doesn't have XTAL_FREQ choice, always 40MHz */ clk_cfg.cpu_freq_mhz = cpu_freq_mhz; clk_cfg.slow_freq = rtc_clk_slow_freq_get(); clk_cfg.fast_freq = rtc_clk_fast_freq_get(); @@ -66,11 +65,20 @@ void bootloader_clock_configure(void) * 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_CLK_SRC_EXT_CRYS + + /* TODO: move the clock option into esp_system, so that this doesn't have + * to continue: + */ +#if CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS if (!rtc_clk_32k_enabled()) { rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES); } #endif +#if CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS + if (!rtc_clk_32k_enabled()) { + rtc_clk_32k_bootstrap(0); + } +#endif } #ifdef BOOTLOADER_BUILD diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index 62c3ab42c3..a166c2cdc7 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -431,10 +431,31 @@ menu "ESP32S2-specific" help Choose which clock is used as RTC clock source. + - "Internal 90kHz oscillator" option provides lowest deep sleep current + consumption, and does not require extra external components. However + frequency stability with respect to temperature is poor, so time may + drift in deep/light sleep modes. + - "External 32kHz crystal" provides better frequency stability, at the + expense of slightly higher (1uA) deep sleep current consumption. + - "External 32kHz oscillator" allows using 32kHz clock generated by an + external circuit. In this case, external clock signal must be connected + to 32K_XP pin. Amplitude should be <1.2V in case of sine wave signal, + and <1V in case of square wave signal. Common mode voltage should be + 0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude. + Additionally, 1nF capacitor must be connected between 32K_XN pin and + ground. 32K_XN pin can not be used as a GPIO in this case. + - "Internal 8MHz oscillator divided by 256" option results in higher + deep sleep current (by 5uA) but has better frequency stability than + the internal 90kHz oscillator. It does not require external components. + config ESP32S2_RTC_CLK_SRC_INT_RC - bool "Internal 150kHz RC oscillator" + bool "Internal 90kHz RC oscillator" config ESP32S2_RTC_CLK_SRC_EXT_CRYS bool "External 32kHz crystal" + config ESP32S2_RTC_CLK_SRC_EXT_OSC + bool "External 32kHz oscillator at 32K_XP pin" + config ESP32S2_RTC_CLK_SRC_INT_8MD256 + bool "Internal 8MHz oscillator, divided by 256 (~32kHz)" endchoice config ESP32S2_RTC_CLK_CAL_CYCLES diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 7304a6f1e2..270d69b35a 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -44,10 +44,29 @@ #define MHZ (1000000) -static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk); +/* 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); -// g_ticks_us defined in ROMs for PRO CPU -extern uint32_t g_ticks_per_us_pro; static const char *TAG = "clk"; @@ -72,8 +91,12 @@ void esp_clk_init(void) rtc_wdt_protect_on(); #endif -#ifdef CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +#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 @@ -106,28 +129,29 @@ void esp_clk_init(void) int IRAM_ATTR esp_clk_cpu_freq(void) { - return g_ticks_per_us_pro * 1000000; + return ets_get_cpu_frequency() * 1000000; } int IRAM_ATTR esp_clk_apb_freq(void) { - return MIN(g_ticks_per_us_pro, 80) * 1000000; + return MIN(ets_get_cpu_frequency(), 80) * 1000000; } -void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) -{ - /* Update scale factors used by ets_delay_us */ - g_ticks_per_us_pro = ticks_per_us; -} - -static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) +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; - uint32_t wait = 0; - const uint32_t warning_timeout = 3 /* sec */ * 32768 /* Hz */ / (2 * SLOW_CLK_CAL_CYCLES); - bool changing_clock_to_150k = false; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ +#ifdef CONFIG_IDF_TARGET_ESP32 + int retry_32k_xtal = 1; /* don't change the behavior for the ESP32 */ +#else + int retry_32k_xtal = 3; +#endif + do { - if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) { + 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 @@ -136,22 +160,26 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) * will time out, returning 0. */ ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - rtc_clk_32k_enable(true); - cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < 15000000L) { - ESP_EARLY_LOGE(TAG, "RTC: Not found External 32 kHz XTAL. Switching to Internal 150 kHz RC chain"); - slow_clk = RTC_SLOW_FREQ_RTC; - changing_clock_to_150k = true; + 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(slow_clk); - if (changing_clock_to_150k == true && wait > 1) { - // This helps when there are errors when switching the clock from External 32 kHz XTAL to Internal 150 kHz RC chain. - rtc_clk_32k_enable(false); - uint32_t min_bootstrap = 5; // Min bootstrapping for continue switching the clock. - rtc_clk_32k_bootstrap(min_bootstrap); - rtc_clk_32k_enable(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. @@ -162,9 +190,6 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); } - if (++wait % warning_timeout == 0) { - ESP_EARLY_LOGW(TAG, "still waiting for source selection RTC"); - } } while (cal_val == 0); ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); esp_clk_slowclk_cal_set(cal_val); diff --git a/components/soc/soc/esp32s2/include/soc/rtc.h b/components/soc/soc/esp32s2/include/soc/rtc.h index 7953510edc..2c27bd670f 100644 --- a/components/soc/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/soc/esp32s2/include/soc/rtc.h @@ -325,6 +325,11 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq); */ void rtc_clk_32k_enable(bool en); +/** + * @brief Configure 32 kHz XTAL oscillator to accept external clock signal + */ +void rtc_clk_32k_enable_external(void); + /** * @brief Get the state of 32k XTAL oscillator * @return true if 32k XTAL oscillator has been enabled diff --git a/components/soc/src/esp32s2/rtc_clk.c b/components/soc/src/esp32s2/rtc_clk.c index 3e9234258b..75969a8043 100644 --- a/components/soc/src/esp32s2/rtc_clk.c +++ b/components/soc/src/esp32s2/rtc_clk.c @@ -57,6 +57,8 @@ void rtc_clk_32k_enable_internal(x32k_config_t cfg) void rtc_clk_32k_enable(bool enable) { if (enable) { + SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL); + SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL); x32k_config_t cfg = X32K_CONFIG_DEFAULT(); rtc_clk_32k_enable_internal(cfg); } else { @@ -65,8 +67,22 @@ void rtc_clk_32k_enable(bool enable) } } +void rtc_clk_32k_enable_external(void) +{ + SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL); + SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL); + /* TODO: external 32k source may need different settings */ + x32k_config_t cfg = X32K_CONFIG_DEFAULT(); + rtc_clk_32k_enable_internal(cfg); +} + void rtc_clk_32k_bootstrap(uint32_t cycle) { + /* No special bootstrapping needed for ESP32-S2, 'cycle' argument is to keep the signature + * same as for the ESP32. Just enable the XTAL here. + */ + (void) cycle; + rtc_clk_32k_enable(true); } bool rtc_clk_32k_enabled(void) @@ -76,11 +92,8 @@ bool rtc_clk_32k_enabled(void) bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S; /* If xtal xpd software control is on */ bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S; - if (xtal_xpd_sw & !xtal_xpd_st) { - return false; - } else { - return true; - } + bool disabled = xtal_xpd_sw && !xtal_xpd_st; + return !disabled; } void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en) From 383ace9443c10c4818d15ed8cfc3011d3c350bb3 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 13 Feb 2020 15:55:55 +0100 Subject: [PATCH 5/7] rtc_clk_cal: make compatible with the ESP32 --- components/soc/src/esp32s2/rtc_time.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/soc/src/esp32s2/rtc_time.c b/components/soc/src/esp32s2/rtc_time.c index c9e190aa8c..fa3e8fa116 100644 --- a/components/soc/src/esp32s2/rtc_time.c +++ b/components/soc/src/esp32s2/rtc_time.c @@ -38,6 +38,19 @@ */ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) { + /* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of + * the 90k RTC clock regardless of the currenlty selected SLOW_CLK. + * On the ESP32, it used the currently selected SLOW_CLK. + * The following code emulates ESP32 behavior: + */ + if (cal_clk == RTC_CAL_RTC_MUX) { + rtc_slow_freq_t slow_freq = rtc_clk_slow_freq_get(); + if (slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + cal_clk = RTC_CAL_32K_XTAL; + } else if (slow_freq == RTC_SLOW_FREQ_8MD256) { + cal_clk = RTC_CAL_8MD256; + } + } /* Enable requested clock (150k clock is always on) */ int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN); if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) { From a8ad9d6b43dad90c6436213dfd2c28bd5115052b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 17 Feb 2020 17:21:15 +0100 Subject: [PATCH 6/7] esp32s2: use smaller RTC_CLK_CAL_CYCLES by default Reduce the number proportionally to the frequency (160k on ESP32, 90k on ESP32-S2). --- components/esp32s2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index a166c2cdc7..0b9092a03c 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -461,7 +461,7 @@ menu "ESP32S2-specific" config ESP32S2_RTC_CLK_CAL_CYCLES int "Number of cycles for RTC_SLOW_CLK calibration" default 3000 if ESP32S2_RTC_CLK_SRC_EXT_CRYS - default 1024 if ESP32S2_RTC_CLK_SRC_INT_RC + default 576 if ESP32S2_RTC_CLK_SRC_INT_RC range 0 125000 help When the startup code initializes RTC_SLOW_CLK, it can perform From cee7377e3c81a4c7dbdb43d86a44938c151514d1 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 17 Feb 2020 17:21:21 +0100 Subject: [PATCH 7/7] =?UTF-8?q?esp32s2:=20hide=20=E2=80=9CFPGA=E2=80=9D=20?= =?UTF-8?q?as=20an=20option=20for=20CPU=20frequency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit unless IDF_ENV_FPGA is set. --- components/esp32s2/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index 0b9092a03c..abdaef4a8f 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -12,6 +12,7 @@ menu "ESP32S2-specific" CPU frequency to be set on application startup. config ESP32S2_DEFAULT_CPU_FREQ_FPGA + depends on IDF_ENV_FPGA bool "FPGA" config ESP32S2_DEFAULT_CPU_FREQ_80 bool "80 MHz"