From a48f4760d2241abfcdd94a70c3aa79510ec8d7bd Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 2 Jan 2024 11:16:55 +0800 Subject: [PATCH] feat(esp32c5): add system related supports --- .../flash_encryption_secure_features.c | 60 +++ .../test_apps/.build-test-rules.yml | 1 + components/efuse/esp32c5/esp_efuse_fields.c | 56 ++ components/efuse/esp32c5/sources.cmake | 4 + components/esp_hw_support/CMakeLists.txt | 9 + components/esp_hw_support/Kconfig | 12 +- components/esp_hw_support/cpu.c | 4 +- components/esp_hw_support/esp_ds.c | 4 + .../esp_hw_support/include/esp_chip_info.h | 2 +- .../include/soc/esp32c5/.gitkeep | 0 .../include/soc/esp32c5/esp_crypto_lock.h | 80 +++ .../esp_hw_support/include/soc/esp32c5/rtc.h | 32 ++ components/esp_hw_support/modem_clock.c | 2 +- .../port/esp32c5/CMakeLists.txt | 17 + .../port/esp32c5/Kconfig.hw_support | 41 ++ .../esp_hw_support/port/esp32c5/Kconfig.mac | 46 ++ .../esp_hw_support/port/esp32c5/Kconfig.rtc | 37 ++ .../esp_hw_support/port/esp32c5/chip_info.c | 18 + .../port/esp32c5/cpu_region_protect.c | 30 ++ .../port/esp32c5/esp_clk_tree.c | 25 + .../port/esp32c5/esp_crypto_lock.c | 89 ++++ .../esp_hw_support/port/esp32c5/io_mux.c | 33 ++ .../esp_hw_support/port/esp32c5/pmu_init.c | 207 ++++++++ .../esp_hw_support/port/esp32c5/pmu_param.c | 447 ++++++++++++++++ .../port/esp32c5/private_include/pmu_param.h | 481 ++++++++++++++++++ .../esp_hw_support/port/esp32c5/rtc_clk.c | 441 ++++++++++++++++ .../port/esp32c5/rtc_clk_init.c | 116 +++++ .../esp_hw_support/port/esp32c5/rtc_time.c | 284 +++++++++++ .../port/esp32c5/sar_periph_ctrl.c | 125 +++++ .../esp_hw_support/port/esp32c5/systimer.c | 37 ++ components/esp_hw_support/rtc_module.c | 16 +- components/esp_hw_support/sleep_clock.c | 8 +- components/esp_hw_support/sleep_cpu.c | 12 +- components/esp_hw_support/sleep_cpu_asm.S | 4 +- components/esp_hw_support/sleep_modes.c | 8 +- .../esp_hw_support/sleep_system_peripheral.c | 2 +- components/esp_system/Kconfig | 1 + .../esp_system/port/arch/riscv/panic_arch.c | 2 +- components/esp_system/port/brownout.c | 2 +- components/esp_system/port/cpu_start.c | 10 +- .../port/soc/esp32c5/CMakeLists.txt | 8 + .../esp_system/port/soc/esp32c5/Kconfig.cpu | 28 + .../port/soc/esp32c5/Kconfig.system | 46 ++ .../port/soc/esp32c5/cache_err_int.c | 76 +++ components/esp_system/port/soc/esp32c5/clk.c | 301 +++++++++++ .../port/soc/esp32c5/reset_reason.c | 116 +++++ .../port/soc/esp32c5/system_internal.c | 122 +++++ components/esp_system/system_time.c | 2 + components/esp_timer/src/ets_timer_legacy.c | 2 + components/esp_timer/src/system_time.c | 2 + 50 files changed, 3481 insertions(+), 27 deletions(-) create mode 100644 components/bootloader_support/src/esp32c5/flash_encryption_secure_features.c create mode 100644 components/efuse/esp32c5/esp_efuse_fields.c create mode 100644 components/efuse/esp32c5/sources.cmake delete mode 100644 components/esp_hw_support/include/soc/esp32c5/.gitkeep create mode 100644 components/esp_hw_support/include/soc/esp32c5/esp_crypto_lock.h create mode 100644 components/esp_hw_support/include/soc/esp32c5/rtc.h create mode 100644 components/esp_hw_support/port/esp32c5/Kconfig.hw_support create mode 100644 components/esp_hw_support/port/esp32c5/Kconfig.mac create mode 100644 components/esp_hw_support/port/esp32c5/Kconfig.rtc create mode 100644 components/esp_hw_support/port/esp32c5/chip_info.c create mode 100644 components/esp_hw_support/port/esp32c5/esp_crypto_lock.c create mode 100644 components/esp_hw_support/port/esp32c5/pmu_init.c create mode 100644 components/esp_hw_support/port/esp32c5/pmu_param.c create mode 100644 components/esp_hw_support/port/esp32c5/private_include/pmu_param.h create mode 100644 components/esp_hw_support/port/esp32c5/rtc_clk.c create mode 100644 components/esp_hw_support/port/esp32c5/rtc_clk_init.c create mode 100644 components/esp_hw_support/port/esp32c5/rtc_time.c create mode 100644 components/esp_hw_support/port/esp32c5/sar_periph_ctrl.c create mode 100644 components/esp_hw_support/port/esp32c5/systimer.c create mode 100644 components/esp_system/port/soc/esp32c5/cache_err_int.c create mode 100644 components/esp_system/port/soc/esp32c5/clk.c create mode 100644 components/esp_system/port/soc/esp32c5/reset_reason.c create mode 100644 components/esp_system/port/soc/esp32c5/system_internal.c diff --git a/components/bootloader_support/src/esp32c5/flash_encryption_secure_features.c b/components/bootloader_support/src/esp32c5/flash_encryption_secure_features.c new file mode 100644 index 0000000000..615aa8ce7b --- /dev/null +++ b/components/bootloader_support/src/esp32c5/flash_encryption_secure_features.c @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_flash_encrypt.h" +#include "esp_secure_boot.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_log.h" +#include "sdkconfig.h" + +static __attribute__((unused)) const char *TAG = "flash_encrypt"; + +esp_err_t esp_flash_encryption_enable_secure_features(void) +{ +#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC + ESP_LOGI(TAG, "Disable UART bootloader encryption..."); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT); +#else + ESP_LOGW(TAG, "Not disabling UART bootloader encryption"); +#endif + +#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE + ESP_LOGI(TAG, "Disable UART bootloader cache..."); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE); +#else + ESP_LOGW(TAG, "Not disabling UART bootloader cache - SECURITY COMPROMISED"); +#endif + +#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG + ESP_LOGI(TAG, "Disable JTAG..."); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG); +#else + ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); +#endif + + esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT); + +#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS) + // This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot + // otherwise the Flash Encryption key cannot be read protected + esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS); +#endif + +#ifndef CONFIG_SECURE_FLASH_SKIP_WRITE_PROTECTION_CACHE + // Set write-protection for DIS_ICACHE to prevent bricking chip in case it will be set accidentally. + // esp32c5 has DIS_ICACHE. Write-protection bit = 2. + // List of eFuses with the same write protection bit: + // SWAP_UART_SDIO_EN, DIS_ICACHE, DIS_USB_JTAG, DIS_DOWNLOAD_ICACHE, + // DIS_USB_SERIAL_JTAG, DIS_FORCE_DOWNLOAD, DIS_TWAI, JTAG_SEL_ENABLE, + // DIS_PAD_JTAG, DIS_DOWNLOAD_MANUAL_ENCRYPT. + esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_ICACHE); +#endif + + return ESP_OK; +} diff --git a/components/bootloader_support/test_apps/.build-test-rules.yml b/components/bootloader_support/test_apps/.build-test-rules.yml index c4bd999324..e850144738 100644 --- a/components/bootloader_support/test_apps/.build-test-rules.yml +++ b/components/bootloader_support/test_apps/.build-test-rules.yml @@ -5,6 +5,7 @@ components/bootloader_support/test_apps/rtc_custom_section: - if: SOC_RTC_MEM_SUPPORTED == 1 reason: this feature is supported on chips that have RTC memory disable: + # TODO: [ESP32C5] IDF-8653 - if: IDF_TARGET == "esp32c5" temporary: true reason: not supported yet diff --git a/components/efuse/esp32c5/esp_efuse_fields.c b/components/efuse/esp32c5/esp_efuse_fields.c new file mode 100644 index 0000000000..1aaa111a44 --- /dev/null +++ b/components/efuse/esp32c5/esp_efuse_fields.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_efuse.h" +#include "esp_efuse_utility.h" +#include "esp_efuse_table.h" +#include "stdlib.h" +#include "esp_types.h" +#include "esp32c5/rom/efuse.h" +#include "assert.h" +#include "esp_err.h" +#include "esp_log.h" +#include "soc/efuse_periph.h" +#include "sys/param.h" + +static __attribute__((unused)) const char *TAG = "efuse"; + +// TODO: [ESP32C5] IDF-8674 + +// Contains functions that provide access to efuse fields which are often used in IDF. + +// Returns chip package from efuse +uint32_t esp_efuse_get_pkg_ver(void) +{ + uint32_t pkg_ver = 0; + esp_efuse_read_field_blob(ESP_EFUSE_PKG_VERSION, &pkg_ver, ESP_EFUSE_PKG_VERSION[0]->bit_count); + return pkg_ver; +} + + +esp_err_t esp_efuse_set_rom_log_scheme(esp_efuse_rom_log_scheme_t log_scheme) +{ + int cur_log_scheme = 0; + esp_efuse_read_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &cur_log_scheme, 2); + if (!cur_log_scheme) { // not burned yet + return esp_efuse_write_field_blob(ESP_EFUSE_UART_PRINT_CONTROL, &log_scheme, 2); + } else { + return ESP_ERR_INVALID_STATE; + } +} + +esp_err_t esp_efuse_disable_rom_download_mode(void) +{ + return esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE); +} + +esp_err_t esp_efuse_enable_rom_secure_download_mode(void) +{ + if (esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MODE)) { + return ESP_ERR_INVALID_STATE; + } + return esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD); +} diff --git a/components/efuse/esp32c5/sources.cmake b/components/efuse/esp32c5/sources.cmake new file mode 100644 index 0000000000..9dffd72008 --- /dev/null +++ b/components/efuse/esp32c5/sources.cmake @@ -0,0 +1,4 @@ +set(EFUSE_SOC_SRCS "esp_efuse_table.c" + "esp_efuse_fields.c" + "esp_efuse_rtc_calib.c" + "esp_efuse_utility.c") diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 8f7658b4c4..7ad19816a8 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -153,6 +153,15 @@ if(NOT BOOTLOADER_BUILD) "sleep_gpio.c" # TODO: IDF-7528, IDF-7529 ) endif() + if(CONFIG_IDF_TARGET_ESP32C5) + list(REMOVE_ITEM srcs + "sleep_cpu.c" # TODO: [ESP32C5] IDF-8638, IDF-8640 + "sleep_modes.c" # TODO: [ESP32C5] IDF-8638, IDF-8640 + "sleep_wake_stub.c" # TODO: [ESP32C5] IDF-8638, IDF-8640 + "sleep_gpio.c" # TODO: [ESP32C5] IDF-8638, IDF-8640 + "port/esp_clk_tree_common.c" # TODO: [ESP32C5] IDF-8638, IDF-8640 + ) + endif() else() # Requires "_esp_error_check_failed()" function list(APPEND priv_requires "esp_system") diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index e9b8a4b66b..689cdea102 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -247,7 +247,8 @@ menu "Hardware Settings" menu "Main XTAL Config" choice XTAL_FREQ_SEL prompt "Main XTAL frequency" - default XTAL_FREQ_40 if SOC_XTAL_SUPPORT_40M + default XTAL_FREQ_48 if SOC_XTAL_SUPPORT_48M + default XTAL_FREQ_40 if (SOC_XTAL_SUPPORT_40M && !SOC_XTAL_SUPPORT_48M) help This option selects the operating frequency of the XTAL (crystal) clock used to drive the ESP target. The selected value MUST reflect the frequency of the given hardware. @@ -270,6 +271,9 @@ menu "Hardware Settings" config XTAL_FREQ_40 depends on SOC_XTAL_SUPPORT_40M bool "40 MHz" + config XTAL_FREQ_48 + depends on SOC_XTAL_SUPPORT_48M + bool "48 MHz" config XTAL_FREQ_AUTO depends on SOC_XTAL_SUPPORT_AUTO_DETECT bool "Autodetect" @@ -283,6 +287,7 @@ menu "Hardware Settings" default 26 if XTAL_FREQ_26 default 32 if XTAL_FREQ_32 default 40 if XTAL_FREQ_40 + default 48 if XTAL_FREQ_48 default 0 if XTAL_FREQ_AUTO endmenu @@ -332,7 +337,10 @@ menu "Hardware Settings" # Invisible bringup bypass options for esp_hw_support component config ESP_BRINGUP_BYPASS_CPU_CLK_SETTING bool - default y if !SOC_CLK_TREE_SUPPORTED + # TODO: [ESP32C5] IDF-8642 IDF_TARGET_ESP32C5 is added because clock + # is required when bringup on C5 beta3, remove it when clock tree is + # supported + default y if !SOC_CLK_TREE_SUPPORTED && !IDF_TARGET_ESP32C5 default n help This option is only used for new chip bringup, when diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index 7fefa9d432..904b760a6a 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -11,7 +11,7 @@ #include "soc/soc_caps.h" // TODO: IDF-5645 -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 #include "soc/lp_aon_reg.h" #include "soc/pcr_reg.h" #define SYSTEM_CPU_PER_CONF_REG PCR_CPU_WAITI_CONF_REG @@ -107,7 +107,7 @@ void esp_cpu_reset(int core_id) else REG_SET_BIT(LP_CLKRST_HPCPU_RESET_CTRL0_REG, LP_CLKRST_HPCORE1_SW_RESET); #else -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// TODO: IDF-5645 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-5645 SET_PERI_REG_MASK(LP_AON_CPUCORE0_CFG_REG, LP_AON_CPU_CORE0_SW_RESET); #else assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM); diff --git a/components/esp_hw_support/esp_ds.c b/components/esp_hw_support/esp_ds.c index 29f25b7638..75878d028a 100644 --- a/components/esp_hw_support/esp_ds.c +++ b/components/esp_hw_support/esp_ds.c @@ -46,6 +46,10 @@ #include "esp32c6/rom/digital_signature.h" #endif +#if CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rom/digital_signature.h" +#endif + #if CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/digital_signature.h" #endif diff --git a/components/esp_hw_support/include/esp_chip_info.h b/components/esp_hw_support/include/esp_chip_info.h index 3922c0aeb6..98126ff4e5 100644 --- a/components/esp_hw_support/include/esp_chip_info.h +++ b/components/esp_hw_support/include/esp_chip_info.h @@ -27,8 +27,8 @@ typedef enum { CHIP_ESP32C2 = 12, //!< ESP32-C2 CHIP_ESP32C6 = 13, //!< ESP32-C6 CHIP_ESP32H2 = 16, //!< ESP32-H2 + CHIP_ESP32C5 = 17, //!< ESP32-C5 beta3 CHIP_ESP32P4 = 18, //!< ESP32-P4 - CHIP_ESP32C5 = 19, //!< ESP32-C5 CHIP_POSIX_LINUX = 999, //!< The code is running on POSIX/Linux simulator } esp_chip_model_t; diff --git a/components/esp_hw_support/include/soc/esp32c5/.gitkeep b/components/esp_hw_support/include/soc/esp32c5/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/components/esp_hw_support/include/soc/esp32c5/esp_crypto_lock.h b/components/esp_hw_support/include/soc/esp32c5/esp_crypto_lock.h new file mode 100644 index 0000000000..617d0231d8 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c5/esp_crypto_lock.h @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Acquire lock for HMAC cryptography peripheral + * + * Internally also locks the SHA peripheral, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_acquire(void); + +/** + * @brief Release lock for HMAC cryptography peripheral + * + * Internally also releases the SHA peripheral, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_release(void); + +/** + * @brief Acquire lock for DS cryptography peripheral + * + * Internally also locks the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals + */ +void esp_crypto_ds_lock_acquire(void); + +/** + * @brief Release lock for DS cryptography peripheral + * + * Internally also releases the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals + */ +void esp_crypto_ds_lock_release(void); + +/** + * @brief Acquire lock for the SHA and AES cryptography peripheral. + * + */ +void esp_crypto_sha_aes_lock_acquire(void); + +/** + * @brief Release lock for the SHA and AES cryptography peripheral. + * + */ +void esp_crypto_sha_aes_lock_release(void); + + +/** + * @brief Acquire lock for the mpi cryptography peripheral. + * + */ +void esp_crypto_mpi_lock_acquire(void); + +/** + * @brief Release lock for the mpi/rsa cryptography peripheral. + * + */ +void esp_crypto_mpi_lock_release(void); + +/** + * @brief Acquire lock for the ECC cryptography peripheral. + * + */ +void esp_crypto_ecc_lock_acquire(void); + +/** + * @brief Release lock for the ECC cryptography peripheral. + * + */ +void esp_crypto_ecc_lock_release(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/soc/esp32c5/rtc.h b/components/esp_hw_support/include/soc/esp32c5/rtc.h new file mode 100644 index 0000000000..4892a1d179 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c5/rtc.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file esp32c5/rtc.h + * + * This file contains declarations of rtc related functions. + */ + +/** + * @brief Get current value of RTC counter in microseconds + * + * Note: this function may take up to 1 RTC_SLOW_CLK cycle to execute + * + * @return current value of RTC counter in microseconds + */ +uint64_t esp_rtc_get_time_us(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index f175513788..901163dd7f 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -245,8 +245,8 @@ void IRAM_ATTR modem_clock_module_mac_reset(periph_module_t module) case PERIPH_IEEE802154_MODULE: modem_syscon_ll_reset_zbmac(ctx->hal->syscon_dev); break; - default: #endif + default: assert(0); } portEXIT_CRITICAL_SAFE(&ctx->lock); diff --git a/components/esp_hw_support/port/esp32c5/CMakeLists.txt b/components/esp_hw_support/port/esp32c5/CMakeLists.txt index e69de29bb2..f95ebf131d 100644 --- a/components/esp_hw_support/port/esp32c5/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c5/CMakeLists.txt @@ -0,0 +1,17 @@ +set(srcs "rtc_clk_init.c" + "rtc_clk.c" + "rtc_time.c" + "pmu_init.c" + "pmu_param.c" + "chip_info.c" + ) + +if(NOT BOOTLOADER_BUILD) + list(APPEND srcs "sar_periph_ctrl.c" + "esp_crypto_lock.c") +endif() + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") + +target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") +target_include_directories(${COMPONENT_LIB} PUBLIC . private_include) diff --git a/components/esp_hw_support/port/esp32c5/Kconfig.hw_support b/components/esp_hw_support/port/esp32c5/Kconfig.hw_support new file mode 100644 index 0000000000..87910b7d1c --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/Kconfig.hw_support @@ -0,0 +1,41 @@ +choice ESP32C5_REV_MIN + prompt "Minimum Supported ESP32-C5 Revision" + default ESP32C5_REV_MIN_0 + help + Required minimum chip revision. ESP-IDF will check for it and + reject to boot if the chip revision fails the check. + This ensures the chip used will have some modifications (features, or bugfixes). + + The complied binary will only support chips above this revision, + this will also help to reduce binary size. + + config ESP32C5_REV_MIN_0 + bool "Rev v0.0" +endchoice + +config ESP32C5_REV_MIN_FULL + int + default 0 if ESP32C5_REV_MIN_0 + +config ESP_REV_MIN_FULL + int + default ESP32C5_REV_MIN_FULL + + # + # MAX Revision + # + + comment "Maximum Supported ESP32-C5 Revision (Rev v0.99)" + # Maximum revision that IDF supports. + # It can not be changed by user. + # Only Espressif can change it when a new version will be supported in IDF. + # Supports all chips starting from ESP32C5_REV_MIN_FULL to ESP32C5_REV_MAX_FULL + +config ESP32C5_REV_MAX_FULL + int + default 99 + # keep in sync the "Maximum Supported Revision" description with this value + +config ESP_REV_MAX_FULL + int + default ESP32C5_REV_MAX_FULL diff --git a/components/esp_hw_support/port/esp32c5/Kconfig.mac b/components/esp_hw_support/port/esp32c5/Kconfig.mac new file mode 100644 index 0000000000..126ef59b83 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/Kconfig.mac @@ -0,0 +1,46 @@ +choice ESP32C5_UNIVERSAL_MAC_ADDRESSES + bool "Number of universally administered (by IEEE) MAC address" + default ESP32C5_UNIVERSAL_MAC_ADDRESSES_FOUR + help + Configure the number of universally administered (by IEEE) MAC addresses. + + During initialization, MAC addresses for each network interface are generated or derived from a + single base MAC address. + + If the number of universal MAC addresses is four, all four interfaces (WiFi station, WiFi softap, + Bluetooth and Ethernet) receive a universally administered MAC address. These are generated + sequentially by adding 0, 1, 2 and 3 (respectively) to the final octet of the base MAC address. + + If the number of universal MAC addresses is two, only two interfaces (WiFi station and Bluetooth) + receive a universally administered MAC address. These are generated sequentially by adding 0 + and 1 (respectively) to the base MAC address. The remaining two interfaces (WiFi softap and Ethernet) + receive local MAC addresses. These are derived from the universal WiFi station and Bluetooth MAC + addresses, respectively. + + When using the default (Espressif-assigned) base MAC address, either setting can be used. When using + a custom universal MAC address range, the correct setting will depend on the allocation of MAC + addresses in this range (either 2 or 4 per device.) + + Note that ESP32-C5 has no integrated Ethernet MAC. Although it's possible to use the esp_read_mac() + API to return a MAC for Ethernet, this can only be used with an external MAC peripheral. + + config ESP32C5_UNIVERSAL_MAC_ADDRESSES_TWO + bool "Two" + select ESP_MAC_UNIVERSAL_MAC_ADDRESSES_TWO + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_BT + + config ESP32C5_UNIVERSAL_MAC_ADDRESSES_FOUR + bool "Four" + select ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR + select ESP_MAC_ADDR_UNIVERSE_IEEE802154 + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_WIFI_AP + select ESP_MAC_ADDR_UNIVERSE_BT + select ESP_MAC_ADDR_UNIVERSE_ETH +endchoice + +config ESP32C5_UNIVERSAL_MAC_ADDRESSES + int + default 2 if ESP32C5_UNIVERSAL_MAC_ADDRESSES_TWO + default 4 if ESP32C5_UNIVERSAL_MAC_ADDRESSES_FOUR diff --git a/components/esp_hw_support/port/esp32c5/Kconfig.rtc b/components/esp_hw_support/port/esp32c5/Kconfig.rtc new file mode 100644 index 0000000000..9c756e882c --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/Kconfig.rtc @@ -0,0 +1,37 @@ +choice RTC_CLK_SRC + prompt "RTC clock source" + default RTC_CLK_SRC_INT_RC32K + help + Choose which clock is used as RTC clock source. + + config RTC_CLK_SRC_EXT_CRYS + bool "External 32kHz crystal" + select ESP_SYSTEM_RTC_EXT_XTAL + config RTC_CLK_SRC_EXT_OSC + bool "External 32kHz oscillator at 32K_XP pin" + select ESP_SYSTEM_RTC_EXT_OSC + config RTC_CLK_SRC_INT_RC32K + bool "Internal 32kHz RC oscillator" +endchoice + +config RTC_CLK_CAL_CYCLES + int "Number of cycles for RTC_SLOW_CLK calibration" + default 3000 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC || RTC_CLK_SRC_INT_RC32K + default 1024 if RTC_CLK_SRC_INT_RC + range 0 27000 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC || RTC_CLK_SRC_INT_RC32K + range 0 32766 if RTC_CLK_SRC_INT_RC + help + When the startup code initializes RTC_SLOW_CLK, it can perform + calibration by comparing the RTC_SLOW_CLK frequency with main XTAL + frequency. This option sets the number of RTC_SLOW_CLK cycles measured + by the calibration routine. Higher numbers increase calibration + precision, which may be important for applications which spend a lot of + time in deep sleep. Lower numbers reduce startup time. + + When this option is set to 0, clock calibration will not be performed at + startup, and approximate clock frequencies will be assumed: + + - 136000 Hz if internal RC oscillator is used as clock source. For this use value 1024. + - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more. + In case more value will help improve the definition of the launch of the crystal. + If the crystal could not start, it will be switched to internal RC. diff --git a/components/esp_hw_support/port/esp32c5/chip_info.c b/components/esp_hw_support/port/esp32c5/chip_info.c new file mode 100644 index 0000000000..04b7ba1113 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/chip_info.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_chip_info.h" +#include "hal/efuse_hal.h" + +void esp_chip_info(esp_chip_info_t *out_info) +{ + memset(out_info, 0, sizeof(*out_info)); + out_info->model = CHIP_ESP32C5; + out_info->revision = efuse_hal_chip_revision(); + out_info->cores = 1; + out_info->features = CHIP_FEATURE_WIFI_BGN | CHIP_FEATURE_BLE; +} diff --git a/components/esp_hw_support/port/esp32c5/cpu_region_protect.c b/components/esp_hw_support/port/esp32c5/cpu_region_protect.c index e69de29bb2..807cc90abf 100644 --- a/components/esp_hw_support/port/esp32c5/cpu_region_protect.c +++ b/components/esp_hw_support/port/esp32c5/cpu_region_protect.c @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "soc/soc.h" +#include "esp_cpu.h" +#include "esp_fault.h" + +#ifdef BOOTLOADER_BUILD +// Without L bit set +#define CONDITIONAL_NONE 0x0 +#define CONDITIONAL_RX PMP_R | PMP_X +#define CONDITIONAL_RW PMP_R | PMP_W +#define CONDITIONAL_RWX PMP_R | PMP_W | PMP_X +#else +// With L bit set +#define CONDITIONAL_NONE NONE +#define CONDITIONAL_RX RX +#define CONDITIONAL_RW RW +#define CONDITIONAL_RWX RWX +#endif + +void esp_cpu_configure_region_protection(void) +{ +// TODO: [ESP32C5] IDF-8833 +} diff --git a/components/esp_hw_support/port/esp32c5/esp_clk_tree.c b/components/esp_hw_support/port/esp32c5/esp_clk_tree.c index e69de29bb2..b5ccf2ccbd 100644 --- a/components/esp_hw_support/port/esp32c5/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32c5/esp_clk_tree.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_clk_tree.h" +#include "esp_err.h" +#include "esp_check.h" +#include "soc/rtc.h" +#include "hal/clk_tree_hal.h" +#include "hal/clk_tree_ll.h" +#include "esp_private/esp_clk_tree_common.h" + +static const char *TAG = "esp_clk_tree"; + +esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision, +uint32_t *freq_value) +{ + // TODO: [ESP32C5] IDF-8642 + ESP_LOGW(TAG, "esp_clk_tree_src_get_freq_hz() has not implemented yet"); + *freq_value = 0; + return ESP_OK; +} diff --git a/components/esp_hw_support/port/esp32c5/esp_crypto_lock.c b/components/esp_hw_support/port/esp32c5/esp_crypto_lock.c new file mode 100644 index 0000000000..d5192c8589 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/esp_crypto_lock.c @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_crypto_lock.h" + +/* Lock overview: +SHA: peripheral independent, but DMA is shared with AES +AES: peripheral independent, but DMA is shared with SHA +MPI/RSA: independent +ECC: independent +HMAC: needs SHA +DS: needs HMAC (which needs SHA), AES and MPI +*/ + +/* Lock for DS peripheral */ +static _lock_t s_crypto_ds_lock; + +/* Lock for HMAC peripheral */ +static _lock_t s_crypto_hmac_lock; + +/* Lock for the MPI/RSA peripheral, also used by the DS peripheral */ +static _lock_t s_crypto_mpi_lock; + +/* Single lock for SHA and AES, sharing a reserved GDMA channel */ +static _lock_t s_crypto_sha_aes_lock; + +/* Lock for ECC peripheral */ +static _lock_t s_crypto_ecc_lock; + +void esp_crypto_hmac_lock_acquire(void) +{ + _lock_acquire(&s_crypto_hmac_lock); + esp_crypto_sha_aes_lock_acquire(); +} + +void esp_crypto_hmac_lock_release(void) +{ + esp_crypto_sha_aes_lock_release(); + _lock_release(&s_crypto_hmac_lock); +} + +void esp_crypto_ds_lock_acquire(void) +{ + _lock_acquire(&s_crypto_ds_lock); + esp_crypto_hmac_lock_acquire(); + esp_crypto_mpi_lock_acquire(); +} + +void esp_crypto_ds_lock_release(void) +{ + esp_crypto_mpi_lock_release(); + esp_crypto_hmac_lock_release(); + _lock_release(&s_crypto_ds_lock); +} + +void esp_crypto_sha_aes_lock_acquire(void) +{ + _lock_acquire(&s_crypto_sha_aes_lock); +} + +void esp_crypto_sha_aes_lock_release(void) +{ + _lock_release(&s_crypto_sha_aes_lock); +} + +void esp_crypto_mpi_lock_acquire(void) +{ + _lock_acquire(&s_crypto_mpi_lock); +} + +void esp_crypto_mpi_lock_release(void) +{ + _lock_release(&s_crypto_mpi_lock); +} + +void esp_crypto_ecc_lock_acquire(void) +{ + _lock_acquire(&s_crypto_ecc_lock); +} + +void esp_crypto_ecc_lock_release(void) +{ + _lock_release(&s_crypto_ecc_lock); +} diff --git a/components/esp_hw_support/port/esp32c5/io_mux.c b/components/esp_hw_support/port/esp32c5/io_mux.c index e69de29bb2..6e9cd84303 100644 --- a/components/esp_hw_support/port/esp32c5/io_mux.c +++ b/components/esp_hw_support/port/esp32c5/io_mux.c @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "esp_private/io_mux.h" +#include "hal/gpio_ll.h" + +static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED; +static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) + +esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) +{ + bool clk_conflict = false; + // check is the IO MUX has been set to another clock source + portENTER_CRITICAL(&s_io_mux_spinlock); + if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { + clk_conflict = true; + } else { + s_io_mux_clk_src = clk_src; + } + portEXIT_CRITICAL(&s_io_mux_spinlock); + + if (clk_conflict) { + return ESP_ERR_INVALID_STATE; + } + + gpio_ll_iomux_set_clk_src(clk_src); + + return ESP_OK; +} diff --git a/components/esp_hw_support/port/esp32c5/pmu_init.c b/components/esp_hw_support/port/esp32c5/pmu_init.c new file mode 100644 index 0000000000..f45c223e15 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/pmu_init.c @@ -0,0 +1,207 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/pmu_struct.h" +#include "hal/pmu_hal.h" +#include "pmu_param.h" +#include "esp_private/esp_pmu.h" +#include "soc/regi2c_dig_reg.h" +#include "regi2c_ctrl.h" + +static __attribute__((unused)) const char *TAG = "pmu_init"; + +typedef struct { + const pmu_hp_system_power_param_t *power; + const pmu_hp_system_clock_param_t *clock; + const pmu_hp_system_digital_param_t *digital; + const pmu_hp_system_analog_param_t *analog; + const pmu_hp_system_retention_param_t *retent; +} pmu_hp_system_param_t; + +typedef struct { + const pmu_lp_system_power_param_t *power; + const pmu_lp_system_analog_param_t *analog; +} pmu_lp_system_param_t; + +pmu_context_t * __attribute__((weak)) IRAM_ATTR PMU_instance(void) +{ + /* It should be explicitly defined in the internal RAM, because this + * instance will be used in pmu_sleep.c */ + static DRAM_ATTR pmu_hal_context_t pmu_hal = { .dev = &PMU }; + static DRAM_ATTR pmu_sleep_machine_constant_t pmu_mc = PMU_SLEEP_MC_DEFAULT(); + static DRAM_ATTR pmu_context_t pmu_context = { .hal = &pmu_hal, .mc = (void *)&pmu_mc }; + return &pmu_context; +} + +void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_param_t *param) +{ + const pmu_hp_system_power_param_t *power = param->power; + const pmu_hp_system_clock_param_t *clock = param->clock; + const pmu_hp_system_digital_param_t *dig = param->digital; + const pmu_hp_system_analog_param_t *anlg = param->analog; + const pmu_hp_system_retention_param_t *ret = param->retent; + + assert(ctx->hal); + /* Default configuration of hp-system power in active, modem and sleep modes */ + pmu_ll_hp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val); + pmu_ll_hp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); + pmu_ll_hp_set_xtal_xpd (ctx->hal->dev, mode, power->xtal.xpd_xtal); + + /* Default configuration of hp-system clock in active, modem and sleep modes */ + pmu_ll_hp_set_icg_func (ctx->hal->dev, mode, clock->icg_func); + pmu_ll_hp_set_icg_apb (ctx->hal->dev, mode, clock->icg_apb); + pmu_ll_hp_set_icg_modem (ctx->hal->dev, mode, clock->icg_modem.code); + pmu_ll_hp_set_sysclk_nodiv (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_nodiv); + pmu_ll_hp_set_icg_sysclk_enable (ctx->hal->dev, mode, clock->sysclk.icg_sysclk_en); + pmu_ll_hp_set_sysclk_slp_sel (ctx->hal->dev, mode, clock->sysclk.sysclk_slp_sel); + pmu_ll_hp_set_icg_sysclk_slp_sel(ctx->hal->dev, mode, clock->sysclk.icg_slp_sel); + pmu_ll_hp_set_dig_sysclk (ctx->hal->dev, mode, clock->sysclk.dig_sysclk_sel); + + /* Default configuration of hp-system digital sub-system in active, modem + * and sleep modes */ + pmu_ll_hp_set_uart_wakeup_enable(ctx->hal->dev, mode, dig->syscntl.uart_wakeup_en); + pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, mode, dig->syscntl.lp_pad_hold_all); + pmu_ll_hp_set_hold_all_hp_pad (ctx->hal->dev, mode, dig->syscntl.hp_pad_hold_all); + pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, mode, dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_pause_watchdog (ctx->hal->dev, mode, dig->syscntl.dig_pause_wdt); + pmu_ll_hp_set_cpu_stall (ctx->hal->dev, mode, dig->syscntl.dig_cpu_stall); + + /* Default configuration of hp-system analog sub-system in active, modem and + * sleep modes */ + pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); + pmu_ll_hp_set_dbg_atten (ctx->hal->dev, mode, anlg->bias.dbg_atten); + pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur); + pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep); + pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_mem_xpd); + pmu_ll_hp_set_regulator_sleep_logic_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_logic_xpd); + pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); + pmu_ll_hp_set_regulator_sleep_memory_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_mem_dbias); + pmu_ll_hp_set_regulator_sleep_logic_dbias (ctx->hal->dev, mode, anlg->regulator0.slp_logic_dbias); + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias); + pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b); + + /* Default configuration of hp-system retention sub-system in active, modem + * and sleep modes */ + pmu_ll_hp_set_retention_param(ctx->hal->dev, mode, ret->retention.val); + pmu_ll_hp_set_backup_icg_func(ctx->hal->dev, mode, ret->backup_clk); + + /* Some PMU initial parameter configuration */ + pmu_ll_imm_update_dig_icg_modem_code(ctx->hal->dev, true); + pmu_ll_imm_update_dig_icg_switch(ctx->hal->dev, true); + + pmu_ll_hp_set_sleep_protect_mode(ctx->hal->dev, PMU_SLEEP_PROTECT_HP_LP_SLEEP); +} + +void pmu_lp_system_init(pmu_context_t *ctx, pmu_lp_mode_t mode, pmu_lp_system_param_t *param) +{ + const pmu_lp_system_power_param_t *power = param->power; + const pmu_lp_system_analog_param_t *anlg = param->analog; + + assert(ctx->hal); + /* Default configuration of lp-system power in active and sleep modes */ + pmu_ll_lp_set_dig_power(ctx->hal->dev, mode, power->dig_power.val); + pmu_ll_lp_set_clk_power(ctx->hal->dev, mode, power->clk_power.val); + pmu_ll_lp_set_xtal_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, power->xtal.xpd_xtal); + + /* Default configuration of lp-system analog sub-system in active and + * sleep modes */ + pmu_ll_lp_set_bias_xpd (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.xpd_bias); + pmu_ll_lp_set_dbg_atten (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.dbg_atten); + pmu_ll_lp_set_current_power_off (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.pd_cur); + pmu_ll_lp_set_bias_sleep_enable (ctx->hal->dev, PMU_MODE_LP_SLEEP, anlg->bias.bias_sleep); + pmu_ll_lp_set_regulator_slp_xpd (ctx->hal->dev, mode, anlg->regulator0.slp_xpd); + pmu_ll_lp_set_regulator_xpd (ctx->hal->dev, mode, anlg->regulator0.xpd); + pmu_ll_lp_set_regulator_sleep_dbias(ctx->hal->dev, mode, anlg->regulator0.slp_dbias); + pmu_ll_lp_set_regulator_dbias (ctx->hal->dev, mode, anlg->regulator0.dbias); + pmu_ll_lp_set_regulator_driver_bar (ctx->hal->dev, mode, anlg->regulator1.drv_b); +} + +static inline void pmu_power_domain_force_default(pmu_context_t *ctx) +{ + assert(ctx); + // for bypass reserved power domain + const pmu_hp_power_domain_t pmu_hp_domains[] = { + PMU_HP_PD_TOP, + PMU_HP_PD_HP_AON, + PMU_HP_PD_CPU, + PMU_HP_PD_WIFI + }; + + for (uint8_t idx = 0; idx < (sizeof(pmu_hp_domains) / sizeof(pmu_hp_power_domain_t)); idx++) { + pmu_ll_hp_set_power_force_reset (ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_isolate (ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_power_up (ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_no_reset (ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_no_isolate(ctx->hal->dev, pmu_hp_domains[idx], false); + pmu_ll_hp_set_power_force_power_down(ctx->hal->dev, pmu_hp_domains[idx], false); + } + /* Isolate all memory banks while sleeping, avoid memory leakage current */ + pmu_ll_hp_set_memory_no_isolate (ctx->hal->dev, 0); + + pmu_ll_lp_set_power_force_reset (ctx->hal->dev, false); + pmu_ll_lp_set_power_force_isolate (ctx->hal->dev, false); + pmu_ll_lp_set_power_force_power_up (ctx->hal->dev, false); + pmu_ll_lp_set_power_force_no_reset (ctx->hal->dev, false); + pmu_ll_lp_set_power_force_no_isolate(ctx->hal->dev, false); + pmu_ll_lp_set_power_force_power_down(ctx->hal->dev, false); +} + +static inline void pmu_hp_system_param_default(pmu_hp_mode_t mode, pmu_hp_system_param_t *param) +{ + param->power = pmu_hp_system_power_param_default(mode); + param->clock = pmu_hp_system_clock_param_default(mode); + param->digital = pmu_hp_system_digital_param_default(mode); + param->analog = pmu_hp_system_analog_param_default(mode); + param->retent = pmu_hp_system_retention_param_default(mode); +} + +static void pmu_hp_system_init_default(pmu_context_t *ctx) +{ + assert(ctx); + pmu_hp_system_param_t param = { 0 }; + for (pmu_hp_mode_t mode = PMU_MODE_HP_ACTIVE; mode < PMU_MODE_HP_MAX; mode++) { + pmu_hp_system_param_default(mode, ¶m); + pmu_hp_system_init(ctx, mode, ¶m); + } +} + +static inline void pmu_lp_system_param_default(pmu_lp_mode_t mode, pmu_lp_system_param_t *param) +{ + param->power = pmu_lp_system_power_param_default(mode); + param->analog = pmu_lp_system_analog_param_default(mode); +} + +static void pmu_lp_system_init_default(pmu_context_t *ctx) +{ + assert(ctx); + pmu_lp_system_param_t param; + for (pmu_lp_mode_t mode = PMU_MODE_LP_ACTIVE; mode < PMU_MODE_LP_MAX; mode++) { + pmu_lp_system_param_default(mode, ¶m); + pmu_lp_system_init(ctx, mode, ¶m); + } +} + +void pmu_init(void) +{ + /* Peripheral reg i2c power up */ + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB); + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_RTC_DREG, 1); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_DIG_DREG, 1); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_DIG_REG, 0); + + pmu_hp_system_init_default(PMU_instance()); + pmu_lp_system_init_default(PMU_instance()); + + pmu_power_domain_force_default(PMU_instance()); +} diff --git a/components/esp_hw_support/port/esp32c5/pmu_param.c b/components/esp_hw_support/port/esp32c5/pmu_param.c new file mode 100644 index 0000000000..3a8d6aacf1 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/pmu_param.c @@ -0,0 +1,447 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "soc/soc.h" +#include "pmu_param.h" +#include "soc/pmu_icg_mapping.h" +#include "esp_private/esp_pmu.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#define PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 0, \ + .mem_dslp = 0, \ + .mem_pd_en = 0, \ + .wifi_pd_en = 0, \ + .cpu_pd_en = 0, \ + .aon_pd_en = 0, \ + .top_pd_en = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 0, \ + .i2c_retention = 0, \ + .xpd_bb_i2c = 1, \ + .xpd_bbpll_i2c = 1, \ + .xpd_bbpll = 1 \ + }, \ + .xtal = { \ + .xpd_xtal = 1 \ + } \ +} + +#define PMU_HP_MODEM_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 0, \ + .mem_dslp = 0, \ + .mem_pd_en = 0, \ + .wifi_pd_en = 0, \ + .cpu_pd_en = 1, \ + .aon_pd_en = 0, \ + .top_pd_en = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 0, \ + .i2c_retention = 0, \ + .xpd_bb_i2c = 1, \ + .xpd_bbpll_i2c = 1, \ + .xpd_bbpll = 1 \ + }, \ + .xtal = { \ + .xpd_xtal = 1 \ + } \ +} + +#define PMU_HP_SLEEP_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .vdd_spi_pd_en = 1, \ + .mem_dslp = 0, \ + .mem_pd_en = 0, \ + .wifi_pd_en = 1, \ + .cpu_pd_en = 0, \ + .aon_pd_en = 0, \ + .top_pd_en = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 1, \ + .i2c_retention = 1, \ + .xpd_bb_i2c = 1, \ + .xpd_bbpll_i2c = 0, \ + .xpd_bbpll = 0, \ + }, \ + .xtal = { \ + .xpd_xtal = 0 \ + } \ +} + +const pmu_hp_system_power_param_t * pmu_hp_system_power_param_default(pmu_hp_mode_t mode) +{ + static const pmu_hp_system_power_param_t hp_power[] = { + PMU_HP_ACTIVE_POWER_CONFIG_DEFAULT(), + PMU_HP_MODEM_POWER_CONFIG_DEFAULT(), + PMU_HP_SLEEP_POWER_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(hp_power)); + return &hp_power[mode]; +} + +#define PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT() { \ + .icg_func = 0xffffffff, \ + .icg_apb = 0xffffffff, \ + .icg_modem = { \ + .code = PMU_HP_ICG_MODEM_CODE_ACTIVE \ + }, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 1, \ + .sysclk_slp_sel = 0, \ + .icg_slp_sel = 0, \ + .dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \ + } \ +} + +#define PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT() { \ + .icg_func = 0, \ + .icg_apb = 0, \ + .icg_modem = { \ + .code = PMU_HP_ICG_MODEM_CODE_MODEM \ + }, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 1, \ + .sysclk_slp_sel = 1, \ + .icg_slp_sel = 1, \ + .dig_sysclk_sel = PMU_HP_SYSCLK_PLL \ + } \ +} + +#define PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT() { \ + .icg_func = 0, \ + .icg_apb = 0, \ + .icg_modem = { \ + .code = PMU_HP_ICG_MODEM_CODE_SLEEP \ + }, \ + .sysclk = { \ + .dig_sysclk_nodiv = 0, \ + .icg_sysclk_en = 0, \ + .sysclk_slp_sel = 1, \ + .icg_slp_sel = 1, \ + .dig_sysclk_sel = PMU_HP_SYSCLK_XTAL \ + } \ +} + +const pmu_hp_system_clock_param_t * pmu_hp_system_clock_param_default(pmu_hp_mode_t mode) +{ + static const pmu_hp_system_clock_param_t hp_clock[] = { + PMU_HP_ACTIVE_CLOCK_CONFIG_DEFAULT(), + PMU_HP_MODEM_CLOCK_CONFIG_DEFAULT(), + PMU_HP_SLEEP_CLOCK_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(hp_clock)); + return &hp_clock[mode]; +} + +#define PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT() { \ + .syscntl = { \ + .uart_wakeup_en = 0, \ + .lp_pad_hold_all = 0, \ + .hp_pad_hold_all = 0, \ + .dig_pad_slp_sel = 0, \ + .dig_pause_wdt = 0, \ + .dig_cpu_stall = 0 \ + } \ +} + +#define PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT() { \ + .syscntl = { \ + .uart_wakeup_en = 1, \ + .lp_pad_hold_all = 0, \ + .hp_pad_hold_all = 0, \ + .dig_pad_slp_sel = 0, \ + .dig_pause_wdt = 1, \ + .dig_cpu_stall = 1 \ + } \ +} + +#define PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT() { \ + .syscntl = { \ + .uart_wakeup_en = 1, \ + .lp_pad_hold_all = 0, \ + .hp_pad_hold_all = 0, \ + .dig_pad_slp_sel = 1, \ + .dig_pause_wdt = 1, \ + .dig_cpu_stall = 1 \ + } \ +} + +const pmu_hp_system_digital_param_t * pmu_hp_system_digital_param_default(pmu_hp_mode_t mode) +{ + static const pmu_hp_system_digital_param_t hp_digital[] = { + PMU_HP_ACTIVE_DIGITAL_CONFIG_DEFAULT(), + PMU_HP_MODEM_DIGITAL_CONFIG_DEFAULT(), + PMU_HP_SLEEP_DIGITAL_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(hp_digital)); + return &hp_digital[mode]; +} + +#define PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 1, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .lp_dbias_vol = 0xd, \ + .hp_dbias_vol = 0x1c,\ + .dbias_sel = 1, \ + .dbias_init = 1, \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 0, \ + .slp_logic_dbias = 0, \ + .dbias = HP_CALI_DBIAS \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 0, \ + .slp_logic_dbias = 0, \ + .dbias = HP_CALI_DBIAS \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0x0, \ + .pd_cur = 0, \ + .bias_sleep = 0 \ + }, \ + .regulator0 = { \ + .slp_mem_xpd = 0, \ + .slp_logic_xpd = 0, \ + .xpd = 1, \ + .slp_mem_dbias = 0, \ + .slp_logic_dbias = 0, \ + .dbias = 1 \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +const pmu_hp_system_analog_param_t * pmu_hp_system_analog_param_default(pmu_hp_mode_t mode) +{ + static const pmu_hp_system_analog_param_t hp_analog[] = { + PMU_HP_ACTIVE_ANALOG_CONFIG_DEFAULT(), + PMU_HP_MODEM_ANALOG_CONFIG_DEFAULT(), + PMU_HP_SLEEP_ANALOG_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(hp_analog)); + return &hp_analog[mode]; +} + +#define PMU_HP_RETENTION_REGDMA_CONFIG(dir, entry) ((((dir)<<2) | (entry & 0x3)) & 0x7) + +#define PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_sleep2active_backup_modem_clk_code = 2, \ + .hp_modem2active_backup_modem_clk_code = 2, \ + .hp_active_retention_mode = 0, \ + .hp_sleep2active_retention_en = 0, \ + .hp_modem2active_retention_en = 0, \ + .hp_sleep2active_backup_clk_sel = 0, \ + .hp_modem2active_backup_clk_sel = 1, \ + .hp_sleep2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 0), \ + .hp_modem2active_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 2), \ + .hp_sleep2active_backup_en = 0, \ + .hp_modem2active_backup_en = 0, \ + }, \ + .backup_clk = ( \ + BIT(PMU_ICG_FUNC_ENA_REGDMA) | \ + BIT(PMU_ICG_FUNC_ENA_TG0) | \ + BIT(PMU_ICG_FUNC_ENA_TG1) | \ + BIT(PMU_ICG_FUNC_ENA_HPBUS) | \ + BIT(PMU_ICG_FUNC_ENA_MSPI) | \ + BIT(PMU_ICG_FUNC_ENA_IOMUX) | \ + BIT(PMU_ICG_FUNC_ENA_SPI2) | \ + BIT(PMU_ICG_FUNC_ENA_UART0) | \ + BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \ + ) \ +} + +#define PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_sleep2modem_backup_modem_clk_code = 1, \ + .hp_modem_retention_mode = 0, \ + .hp_sleep2modem_retention_en = 0, \ + .hp_sleep2modem_backup_clk_sel = 0, \ + .hp_sleep2modem_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(0, 1), \ + .hp_sleep2modem_backup_en = 0, \ + }, \ + .backup_clk = ( \ + BIT(PMU_ICG_FUNC_ENA_REGDMA) | \ + BIT(PMU_ICG_FUNC_ENA_TG0) | \ + BIT(PMU_ICG_FUNC_ENA_TG1) | \ + BIT(PMU_ICG_FUNC_ENA_HPBUS) | \ + BIT(PMU_ICG_FUNC_ENA_MSPI) | \ + BIT(PMU_ICG_FUNC_ENA_IOMUX) | \ + BIT(PMU_ICG_FUNC_ENA_SPI2) | \ + BIT(PMU_ICG_FUNC_ENA_UART0) | \ + BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \ + ) \ +} + +#define PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT() { \ + .retention = { \ + .hp_modem2sleep_backup_modem_clk_code = 0, \ + .hp_active2sleep_backup_modem_clk_code = 2, \ + .hp_sleep_retention_mode = 0, \ + .hp_modem2sleep_retention_en = 0, \ + .hp_active2sleep_retention_en = 0, \ + .hp_modem2sleep_backup_clk_sel = 0, \ + .hp_active2sleep_backup_clk_sel = 0, \ + .hp_modem2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 1), \ + .hp_active2sleep_backup_mode = PMU_HP_RETENTION_REGDMA_CONFIG(1, 0), \ + .hp_modem2sleep_backup_en = 0, \ + .hp_active2sleep_backup_en = 0, \ + }, \ + .backup_clk = ( \ + BIT(PMU_ICG_FUNC_ENA_REGDMA) | \ + BIT(PMU_ICG_FUNC_ENA_TG0) | \ + BIT(PMU_ICG_FUNC_ENA_TG1) | \ + BIT(PMU_ICG_FUNC_ENA_HPBUS) | \ + BIT(PMU_ICG_FUNC_ENA_MSPI) | \ + BIT(PMU_ICG_FUNC_ENA_IOMUX) | \ + BIT(PMU_ICG_FUNC_ENA_SPI2) | \ + BIT(PMU_ICG_FUNC_ENA_UART0) | \ + BIT(PMU_ICG_FUNC_ENA_SYSTIMER) \ + ) \ +} + +const pmu_hp_system_retention_param_t * pmu_hp_system_retention_param_default(pmu_hp_mode_t mode) +{ + static const pmu_hp_system_retention_param_t hp_retention[] = { + PMU_HP_ACTIVE_RETENTION_CONFIG_DEFAULT(), + PMU_HP_MODEM_RETENTION_CONFIG_DEFAULT(), + PMU_HP_SLEEP_RETENTION_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(hp_retention)); + return &hp_retention[mode]; +} + + +/** LP system default parameter */ + +#if CONFIG_ESP_SYSTEM_RTC_EXT_XTAL +# define PMU_SLOW_CLK_USE_EXT_XTAL (1) +#else +# define PMU_SLOW_CLK_USE_EXT_XTAL (0) +#endif + +#define PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .mem_dslp = 0, \ + .peri_pd_en = 0, \ + }, \ + .clk_power = { \ + .xpd_xtal32k = PMU_SLOW_CLK_USE_EXT_XTAL, \ + .xpd_rc32k = 1, \ + .xpd_fosc = 1, \ + .pd_osc = 0 \ + } \ +} + +#define PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() { \ + .dig_power = { \ + .mem_dslp = 1, \ + .peri_pd_en = 0, \ + }, \ + .clk_power = { \ + .xpd_xtal32k = 0, \ + .xpd_rc32k = 0, \ + .xpd_fosc = 0, \ + .pd_osc = 0 \ + }, \ + .xtal = { \ + .xpd_xtal = 0 \ + } \ +} + +const pmu_lp_system_power_param_t * pmu_lp_system_power_param_default(pmu_lp_mode_t mode) +{ + static const pmu_lp_system_power_param_t lp_power[] = { + PMU_LP_ACTIVE_POWER_CONFIG_DEFAULT(), + PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(lp_power)); + return &lp_power[mode]; +} + +#define PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT() { \ + .regulator0 = { \ + .slp_xpd = 0, \ + .xpd = 1, \ + .slp_dbias = 0, \ + .dbias = LP_CALI_DBIAS \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +#define PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT() { \ + .bias = { \ + .xpd_bias = 0, \ + .dbg_atten = 0, \ + .pd_cur = 1, \ + .bias_sleep = 1, \ + }, \ + .regulator0 = { \ + .slp_xpd = 0, \ + .xpd = 1, \ + .slp_dbias = 0, \ + .dbias = 12 \ + }, \ + .regulator1 = { \ + .drv_b = 0x0 \ + } \ +} + +const pmu_lp_system_analog_param_t * pmu_lp_system_analog_param_default(pmu_lp_mode_t mode) +{ + static const pmu_lp_system_analog_param_t lp_analog[] = { + PMU_LP_ACTIVE_ANALOG_CONFIG_DEFAULT(), + PMU_LP_SLEEP_ANALOG_CONFIG_DEFAULT() + }; + assert(mode < ARRAY_SIZE(lp_analog)); + return &lp_analog[mode]; +} diff --git a/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h new file mode 100644 index 0000000000..b4c14c0eaa --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h @@ -0,0 +1,481 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "soc/soc_caps.h" +#if SOC_PMU_SUPPORTED +#include "soc/pmu_struct.h" +#include "hal/pmu_hal.h" +#endif + +// TODO: [ESP32C5] IDF-8643 + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HP_CALI_DBIAS 25 +#define LP_CALI_DBIAS 26 + +#if SOC_PMU_SUPPORTED + +// FOR XTAL FORCE PU IN SLEEP +#define PMU_PD_CUR_SLEEP_ON 0 +#define PMU_BIASSLP_SLEEP_ON 0 + +// FOR BOTH LIGHTSLEEP & DEEPSLEEP +#define PMU_PD_CUR_SLEEP_DEFAULT 1 +#define PMU_BIASSLP_SLEEP_DEFAULT 1 +#define PMU_LP_XPD_SLEEP_DEFAULT 1 +#define PMU_LP_SLP_XPD_SLEEP_DEFAULT 0 +#define PMU_LP_SLP_DBIAS_SLEEP_DEFAULT 0 + +// FOR LIGHTSLEEP +#define PMU_HP_DRVB_LIGHTSLEEP 0 +#define PMU_LP_DRVB_LIGHTSLEEP 0 +#define PMU_HP_XPD_LIGHTSLEEP 1 + +#define PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT 0 +#define PMU_HP_DBIAS_LIGHTSLEEP_0V6 1 +#define PMU_LP_DBIAS_LIGHTSLEEP_0V7 12 + +// FOR DEEPSLEEP +#define PMU_DBG_HP_DEEPSLEEP 0 +#define PMU_HP_XPD_DEEPSLEEP 0 +#define PMU_LP_DRVB_DEEPSLEEP 0 + +#define PMU_DBG_ATTEN_DEEPSLEEP_DEFAULT 12 +#define PMU_LP_DBIAS_DEEPSLEEP_0V7 23 + +typedef struct { + pmu_hp_dig_power_reg_t dig_power; + pmu_hp_clk_power_reg_t clk_power; + pmu_hp_xtal_reg_t xtal; +} pmu_hp_system_power_param_t; + +const pmu_hp_system_power_param_t* pmu_hp_system_power_param_default(pmu_hp_mode_t mode); + +typedef struct { + uint32_t icg_func; + uint32_t icg_apb; + pmu_hp_icg_modem_reg_t icg_modem; + pmu_hp_sysclk_reg_t sysclk; +} pmu_hp_system_clock_param_t; + +const pmu_hp_system_clock_param_t* pmu_hp_system_clock_param_default(pmu_hp_mode_t mode); + +typedef struct { + pmu_hp_sys_cntl_reg_t syscntl; +} pmu_hp_system_digital_param_t; + +const pmu_hp_system_digital_param_t* pmu_hp_system_digital_param_default(pmu_hp_mode_t mode); + +typedef struct { + pmu_hp_bias_reg_t bias; + pmu_hp_regulator0_reg_t regulator0; + pmu_hp_regulator1_reg_t regulator1; +} pmu_hp_system_analog_param_t; + +const pmu_hp_system_analog_param_t* pmu_hp_system_analog_param_default(pmu_hp_mode_t mode); + +typedef struct { + pmu_hp_backup_reg_t retention; + uint32_t backup_clk; +} pmu_hp_system_retention_param_t; + +const pmu_hp_system_retention_param_t* pmu_hp_system_retention_param_default(pmu_hp_mode_t mode); + +typedef struct { + pmu_lp_dig_power_reg_t dig_power; + pmu_lp_clk_power_reg_t clk_power; + pmu_lp_xtal_reg_t xtal; +} pmu_lp_system_power_param_t; + +const pmu_lp_system_power_param_t* pmu_lp_system_power_param_default(pmu_lp_mode_t mode); + + + +typedef struct { + pmu_lp_bias_reg_t bias; + pmu_lp_regulator0_reg_t regulator0; + pmu_lp_regulator1_reg_t regulator1; +} pmu_lp_system_analog_param_t; + +const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mode_t mode); + + + +/* Following software configuration instance type from pmu_struct.h used for the PMU state machine in sleep flow*/ +typedef union { + struct { + uint32_t reserved0 : 21; + uint32_t vdd_spi_pd_en: 1; + uint32_t mem_dslp : 1; + uint32_t mem_pd_en : 4; + uint32_t wifi_pd_en : 1; + uint32_t reserved1 : 1; + uint32_t cpu_pd_en : 1; + uint32_t aon_pd_en : 1; + uint32_t top_pd_en : 1; + }; + struct { + uint32_t reserved2 : 26; + uint32_t i2c_iso_en : 1; + uint32_t i2c_retention: 1; + uint32_t xpd_bb_i2c : 1; + uint32_t xpd_bbpll_i2c: 1; + uint32_t xpd_bbpll : 1; + uint32_t reserved3 : 1; + }; + struct { + uint32_t reserved4 : 31; + uint32_t xpd_xtal : 1; + }; + uint32_t val; +} pmu_hp_power_t; + +typedef union { + struct { + uint32_t reserved0 : 30; + uint32_t mem_dslp : 1; + uint32_t peri_pd_en: 1; + }; + struct { + uint32_t reserved1 : 28; + uint32_t xpd_xtal32k: 1; + uint32_t xpd_rc32k : 1; + uint32_t xpd_fosc : 1; + uint32_t pd_osc : 1; + }; + struct { + uint32_t reserved2 : 31; + uint32_t xpd_xtal : 1; + }; + uint32_t val; +} pmu_lp_power_t; + +typedef struct { + struct { + uint32_t reserved0 : 25; + uint32_t xpd_bias : 1; + uint32_t dbg_atten : 4; + uint32_t pd_cur : 1; + uint32_t bias_sleep: 1; + }; + struct { + uint32_t reserved1 : 16; + uint32_t slp_mem_xpd : 1; + uint32_t slp_logic_xpd : 1; + uint32_t xpd : 1; + uint32_t slp_mem_dbias : 4; + uint32_t slp_logic_dbias: 4; + uint32_t dbias : 5; + }; + struct { + uint32_t reserved2: 8; + uint32_t drv_b : 24; + }; +} pmu_hp_analog_t; + +typedef struct { + struct { + uint32_t reserved0 : 25; + uint32_t xpd_bias : 1; + uint32_t dbg_atten : 4; + uint32_t pd_cur : 1; + uint32_t bias_sleep: 1; + }; + struct { + uint32_t reserved1: 21; + uint32_t slp_xpd : 1; + uint32_t xpd : 1; + uint32_t slp_dbias: 4; + uint32_t dbias : 5; + }; + struct { + uint32_t reserved2: 28; + uint32_t drv_b : 4; + }; +} pmu_lp_analog_t; + +typedef struct { + uint32_t modem_wakeup_wait_cycle; + uint16_t analog_wait_target_cycle; + uint16_t digital_power_down_wait_cycle; + uint16_t digital_power_supply_wait_cycle; + uint16_t digital_power_up_wait_cycle; + uint16_t pll_stable_wait_cycle; + uint8_t modify_icg_cntl_wait_cycle; + uint8_t switch_icg_cntl_wait_cycle; + uint8_t min_slp_slow_clk_cycle; +} pmu_hp_param_t; + +typedef struct { + uint16_t digital_power_supply_wait_cycle; + uint8_t min_slp_slow_clk_cycle; + uint8_t analog_wait_target_cycle; + uint8_t digital_power_down_wait_cycle; + uint8_t digital_power_up_wait_cycle; +} pmu_lp_param_t; + +typedef struct { + union { + uint16_t xtal_stable_wait_slow_clk_cycle; + uint16_t xtal_stable_wait_cycle; + }; +} pmu_hp_lp_param_t; + +#define PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES (10) +#define PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES (10) + +#define PMU_HP_WAKEUP_DELAY_CYCLES (0) +#define PMU_HP_XTAL_STABLE_WAIT_CYCLES (3155) /* Not used, Fast OSC as PMU work clock source is about 201 us, corresponding to PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES */ +#define PMU_HP_PLL_STABLE_WAIT_CYCLES (2) +#define PMU_HP_ANALOG_WAIT_TARGET_CYCLES (2419) /* Fast OSC as PMU work clock source is about 154 us */ +#define PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32) +#define PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES (32) +#define PMU_HP_MODEM_WAKEUP_WAIT_CYCLES (20700) /* Fast OSC as PMU work clock source is about 1318.6 us */ + +#define PMU_LP_WAKEUP_DELAY_CYCLES (0) +#define PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES (30) /* Slow OSC as PMU slow clock source is about 201 us */ +#define PMU_LP_ANALOG_WAIT_TARGET_CYCLES (23) /* Slow OSC as PMU slow clock source is about 154 us */ +#define PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */ +#define PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES (32) /* Fast OSC as PMU work clock source is about 2 us */ + +#define PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US (500) /* Slow OSC as PMU slow clock source in deepsleep is about 500 us */ + +typedef struct { + struct { + pmu_hp_power_t dig_power; + pmu_hp_power_t clk_power; + pmu_hp_power_t xtal; + } hp_sys; + struct { + pmu_lp_power_t dig_power; + pmu_lp_power_t clk_power; + pmu_lp_power_t xtal; + } lp_sys[PMU_MODE_LP_MAX]; +} pmu_sleep_power_config_t; + +#define PMU_SLEEP_POWER_CONFIG_DEFAULT(pd_flags) { \ + .hp_sys = { \ + .dig_power = { \ + .vdd_spi_pd_en = ((pd_flags) & PMU_SLEEP_PD_VDDSDIO) ? 1 : 0, \ + .wifi_pd_en = ((pd_flags) & PMU_SLEEP_PD_MODEM) ? 1 : 0, \ + .cpu_pd_en = ((pd_flags) & PMU_SLEEP_PD_CPU) ? 1 : 0, \ + .aon_pd_en = ((pd_flags) & PMU_SLEEP_PD_HP_AON) ? 1 : 0, \ + .top_pd_en = ((pd_flags) & PMU_SLEEP_PD_TOP) ? 1 : 0, \ + .mem_pd_en = 0, \ + .mem_dslp = 0 \ + }, \ + .clk_power = { \ + .i2c_iso_en = 1, \ + .i2c_retention = 1, \ + .xpd_bb_i2c = 0, \ + .xpd_bbpll_i2c = 0, \ + .xpd_bbpll = 0 \ + }, \ + .xtal = { \ + .xpd_xtal = ((pd_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_ACTIVE] = { \ + .dig_power = { \ + .peri_pd_en = 0, \ + .mem_dslp = 0 \ + }, \ + .clk_power = { \ + .xpd_xtal32k = ((pd_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1, \ + .xpd_rc32k = ((pd_flags) & PMU_SLEEP_PD_RC32K) ? 0 : 1, \ + .xpd_fosc = 1 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .dig_power = { \ + .peri_pd_en = ((pd_flags) & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ + .mem_dslp = 1 \ + }, \ + .clk_power = { \ + .xpd_xtal32k = ((pd_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1, \ + .xpd_rc32k = ((pd_flags) & PMU_SLEEP_PD_RC32K) ? 0 : 1, \ + .xpd_fosc = ((pd_flags) & PMU_SLEEP_PD_RC_FAST) ? 0 : 1 \ + }, \ + .xtal = { \ + .xpd_xtal = ((pd_flags) & PMU_SLEEP_PD_XTAL) ? 0 : 1, \ + } \ + } \ +} + +typedef struct { + pmu_hp_sys_cntl_reg_t syscntl; +} pmu_sleep_digital_config_t; + +#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = ((pd_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ + } \ +} + +typedef struct { + struct { + pmu_hp_analog_t analog; + } hp_sys; + struct { + pmu_lp_analog_t analog; + } lp_sys[PMU_MODE_LP_MAX]; +} pmu_sleep_analog_config_t; + +#define PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags) { \ + .hp_sys = { \ + .analog = { \ + .drv_b = PMU_HP_DRVB_LIGHTSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .xpd = PMU_HP_XPD_LIGHTSLEEP, \ + .dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT, \ + .dbias = PMU_HP_DBIAS_LIGHTSLEEP_0V6 \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .analog = { \ + .drv_b = PMU_LP_DRVB_DEEPSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .slp_xpd = PMU_LP_SLP_XPD_SLEEP_DEFAULT, \ + .slp_dbias = PMU_LP_SLP_DBIAS_SLEEP_DEFAULT, \ + .xpd = PMU_LP_XPD_SLEEP_DEFAULT, \ + .dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT, \ + .dbias = PMU_LP_DBIAS_LIGHTSLEEP_0V7 \ + } \ + } \ +} + +#define PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags) { \ + .hp_sys = { \ + .analog = { \ + .pd_cur = PMU_PD_CUR_SLEEP_ON, \ + .bias_sleep = PMU_BIASSLP_SLEEP_ON, \ + .xpd = PMU_HP_XPD_DEEPSLEEP, \ + .dbg_atten = PMU_DBG_HP_DEEPSLEEP \ + } \ + }, \ + .lp_sys[PMU_MODE_LP_SLEEP] = { \ + .analog = { \ + .drv_b = PMU_LP_DRVB_DEEPSLEEP, \ + .pd_cur = PMU_PD_CUR_SLEEP_DEFAULT, \ + .bias_sleep = PMU_BIASSLP_SLEEP_DEFAULT, \ + .slp_xpd = PMU_LP_SLP_XPD_SLEEP_DEFAULT, \ + .slp_dbias = PMU_LP_SLP_DBIAS_SLEEP_DEFAULT, \ + .xpd = PMU_LP_XPD_SLEEP_DEFAULT, \ + .dbg_atten = PMU_DBG_ATTEN_DEEPSLEEP_DEFAULT, \ + .dbias = PMU_LP_DBIAS_DEEPSLEEP_0V7 \ + } \ + } \ +} + +typedef struct { + pmu_hp_param_t hp_sys; + pmu_lp_param_t lp_sys; + pmu_hp_lp_param_t hp_lp; +} pmu_sleep_param_config_t; + +#define PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags) { \ + .hp_sys = { \ + .min_slp_slow_clk_cycle = PMU_HP_SLEEP_MIN_SLOW_CLK_CYCLES, \ + .analog_wait_target_cycle = PMU_HP_ANALOG_WAIT_TARGET_CYCLES, \ + .digital_power_supply_wait_cycle = PMU_HP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \ + .digital_power_up_wait_cycle = PMU_HP_DIGITAL_POWER_UP_WAIT_CYCLES, \ + .modem_wakeup_wait_cycle = PMU_HP_MODEM_WAKEUP_WAIT_CYCLES, \ + .pll_stable_wait_cycle = PMU_HP_PLL_STABLE_WAIT_CYCLES \ + }, \ + .lp_sys = { \ + .min_slp_slow_clk_cycle = PMU_LP_SLEEP_MIN_SLOW_CLK_CYCLES, \ + .analog_wait_target_cycle = PMU_LP_ANALOG_WAIT_TARGET_CYCLES, \ + .digital_power_supply_wait_cycle = PMU_LP_DIGITAL_POWER_SUPPLY_WAIT_CYCLES, \ + .digital_power_up_wait_cycle = PMU_LP_DIGITAL_POWER_UP_WAIT_CYCLES \ + }, \ + .hp_lp = { \ + .xtal_stable_wait_slow_clk_cycle = PMU_LP_XTAL_STABLE_WAIT_SLOW_CLK_CYCLES \ + } \ +} + +typedef struct { + pmu_sleep_power_config_t power; + pmu_sleep_digital_config_t digital; + pmu_sleep_analog_config_t analog; + pmu_sleep_param_config_t param; +} pmu_sleep_config_t; + +typedef struct pmu_sleep_machine_constant { + struct { + uint16_t min_slp_time_us; /* Mininum sleep protection time (unit: microsecond) */ + uint8_t wakeup_wait_cycle; /* Modem wakeup signal (WiFi MAC and BEACON wakeup) waits for the slow & fast clock domain synchronization and the wakeup signal triggers the PMU FSM switching wait cycle (unit: slow clock cycle) */ + uint8_t reserved0; + uint16_t reserved1; + uint16_t analog_wait_time_us; /* LP LDO power up wait time (unit: microsecond) */ + uint16_t xtal_wait_stable_time_us; /* Main XTAL stabilization wait time (unit: microsecond) */ + uint8_t clk_switch_cycle; /* Clock switch to FOSC (unit: slow clock cycle) */ + uint8_t clk_power_on_wait_cycle; /* Clock power on wait cycle (unit: slow clock cycle) */ + uint16_t power_supply_wait_time_us; /* (unit: microsecond) */ + uint16_t power_up_wait_time_us; /* (unit: microsecond) */ + } lp; + struct { + uint16_t min_slp_time_us; /* Mininum sleep protection time (unit: microsecond) */ + uint16_t clock_domain_sync_time_us; /* The Slow OSC clock domain synchronizes time with the Fast OSC domain, at least 4 slow clock cycles (unit: microsecond) */ + uint16_t system_dfs_up_work_time_us; /* System DFS up scaling work time (unit: microsecond) */ + uint16_t analog_wait_time_us; /* HP LDO power up wait time (unit: microsecond) */ + uint16_t power_supply_wait_time_us; /* (unit: microsecond) */ + uint16_t power_up_wait_time_us; /* (unit: microsecond) */ + uint16_t regdma_s2m_work_time_us; /* Modem Subsystem (S2M switch) REGDMA restore time (unit: microsecond) */ + uint16_t regdma_s2a_work_time_us; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (S2A switch) restore time (unit: microsecond) */ + uint16_t regdma_m2a_work_time_us; /* Digital Peripheral (M2A switch) REGDMA restore time (unit: microsecond) */ + uint16_t regdma_a2s_work_time_us; /* SOC System (Digital Peripheral + Modem Subsystem) REGDMA (A2S switch) backup time (unit: microsecond) */ + uint16_t regdma_rf_on_work_time_us; /* The REGDMA work time of RF enable (unit: microsecond) */ + uint16_t regdma_rf_off_work_time_us; /* The REGDMA work time of RF disable (unit: microsecond) */ + uint16_t xtal_wait_stable_time_us; /* Main XTAL stabilization wait time (unit: microsecond) */ + uint16_t pll_wait_stable_time_us; /* PLL stabilization wait time (unit: microsecond) */ + } hp; +} pmu_sleep_machine_constant_t; + +#define PMU_SLEEP_MC_DEFAULT() { \ + .lp = { \ + .min_slp_time_us = 450, \ + .wakeup_wait_cycle = 4, \ + .analog_wait_time_us = 154, \ + .xtal_wait_stable_time_us = 250, \ + .clk_switch_cycle = 1, \ + .clk_power_on_wait_cycle = 1, \ + .power_supply_wait_time_us = 2, \ + .power_up_wait_time_us = 2 \ + }, \ + .hp = { \ + .min_slp_time_us = 450, \ + .clock_domain_sync_time_us = 150, \ + .system_dfs_up_work_time_us = 124, \ + .analog_wait_time_us = 154, \ + .power_supply_wait_time_us = 2, \ + .power_up_wait_time_us = 2, \ + .regdma_s2m_work_time_us = 172, \ + .regdma_s2a_work_time_us = 480, \ + .regdma_m2a_work_time_us = 278, \ + .regdma_a2s_work_time_us = 382, \ + .regdma_rf_on_work_time_us = 70, \ + .regdma_rf_off_work_time_us = 23, \ + .xtal_wait_stable_time_us = 250, \ + .pll_wait_stable_time_us = 1 \ + } \ +} + +#endif // SOC_PMU_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32c5/rtc_clk.c b/components/esp_hw_support/port/esp32c5/rtc_clk.c new file mode 100644 index 0000000000..dbd235fd4a --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/rtc_clk.c @@ -0,0 +1,441 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp32c5/rom/rtc.h" +#include "soc/rtc.h" +#include "esp_private/rtc_clk.h" +#include "esp_hw_log.h" +#include "esp_rom_sys.h" +#include "hal/clk_tree_ll.h" +#include "hal/regi2c_ctrl_ll.h" +#include "soc/io_mux_reg.h" +#include "soc/lp_aon_reg.h" +#include "esp_private/sleep_event.h" + +#ifdef BOOTLOADER_BUILD +#include "hal/modem_lpcon_ll.h" +#else +#include "esp_private/esp_modem_clock.h" +#endif + +static const char *TAG = "rtc_clk"; + +// Current PLL frequency, in 480MHz. Zero if PLL is not enabled. +static int s_cur_pll_freq; + +static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it only tracks whether the 48MHz PHY clock is in-use by USB Serial/JTAG + +void rtc_clk_bbpll_add_consumer(void) +{ + s_bbpll_digi_consumers_ref_count += 1; +} + +void rtc_clk_bbpll_remove_consumer(void) +{ + s_bbpll_digi_consumers_ref_count -= 1; +} + +void rtc_clk_32k_enable(bool enable) +{ + if (enable) { + clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL); + } else { + clk_ll_xtal32k_disable(); + } +} + +void rtc_clk_32k_enable_external(void) +{ + // EXT_OSC_SLOW_GPIO_NUM == GPIO_NUM_0 + PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG); + REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(EXT_OSC_SLOW_GPIO_NUM)); + clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL); +} + +void rtc_clk_32k_bootstrap(uint32_t cycle) +{ + /* No special bootstrapping needed for ESP32-C5, '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) +{ + return clk_ll_xtal32k_is_enabled(); +} + +void rtc_clk_rc32k_enable(bool enable) +{ + if (enable) { + clk_ll_rc32k_enable(); + esp_rom_delay_us(SOC_DELAY_RC32K_ENABLE); + } else { + clk_ll_rc32k_disable(); + } +} + +void rtc_clk_8m_enable(bool clk_8m_en) +{ + if (clk_8m_en) { + clk_ll_rc_fast_enable(); + esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE); + } else { + clk_ll_rc_fast_disable(); + } +} + +bool rtc_clk_8m_enabled(void) +{ + return clk_ll_rc_fast_is_enabled(); +} + +void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src) +{ + clk_ll_rtc_slow_set_src(clk_src); + esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH); +} + +soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void) +{ + return clk_ll_rtc_slow_get_src(); +} + +uint32_t rtc_clk_slow_freq_get_hz(void) +{ + switch (rtc_clk_slow_src_get()) { + // case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX; + case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX; + case SOC_RTC_SLOW_CLK_SRC_RC32K: return SOC_CLK_RC32K_FREQ_APPROX; + case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW: return SOC_CLK_OSC_SLOW_FREQ_APPROX; + default: return 0; + } +} + +void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src) +{ + clk_ll_rtc_fast_set_src(clk_src); + esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH); +} + +soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void) +{ + return clk_ll_rtc_fast_get_src(); +} + +static void rtc_clk_bbpll_disable(void) +{ + clk_ll_bbpll_disable(); + s_cur_pll_freq = 0; +} + +static void rtc_clk_bbpll_enable(void) +{ + clk_ll_bbpll_enable(); +} + +static void rtc_clk_enable_i2c_ana_master_clock(bool enable) +{ +#ifdef BOOTLOADER_BUILD + modem_lpcon_ll_enable_i2c_master_clock(&MODEM_LPCON, enable); +#else + if (enable) { + modem_clock_module_enable(PERIPH_ANA_I2C_MASTER_MODULE); + } else { + modem_clock_module_disable(PERIPH_ANA_I2C_MASTER_MODULE); + } +#endif +} + +static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) +{ + assert((pll_freq == CLK_LL_PLL_160M_FREQ_MHZ) || \ + (pll_freq == CLK_LL_PLL_240M_FREQ_MHZ)); + /* Digital part */ + clk_ll_bbpll_set_freq_mhz(CLK_LL_PLL_480M_FREQ_MHZ); + /* Analog part */ + rtc_clk_enable_i2c_ana_master_clock(true); + /* BBPLL CALIBRATION START */ + regi2c_ctrl_ll_bbpll_calibration_start(); + clk_ll_bbpll_set_config(CLK_LL_PLL_480M_FREQ_MHZ, xtal_freq); + /* WAIT CALIBRATION DONE */ + while(!regi2c_ctrl_ll_bbpll_calibration_is_done()); + /* BBPLL CALIBRATION STOP */ + regi2c_ctrl_ll_bbpll_calibration_stop(); + rtc_clk_enable_i2c_ana_master_clock(false); + s_cur_pll_freq = CLK_LL_PLL_480M_FREQ_MHZ; +} + +/** + * Switch to use XTAL as the CPU clock source. + * Must satisfy: cpu_freq = XTAL_FREQ / div. + * Does not disable the PLL. + */ +static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +{ + /* Configure clk mspi fast to XTAL*/ + clk_ll_mspi_fast_sel_clk(SOC_MOD_CLK_XTAL); + clk_ll_mspi_fast_set_divider(1); + + clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL); + clk_ll_ahb_set_divider(div); + clk_ll_cpu_set_divider(div); + esp_rom_set_cpu_ticks_per_us(cpu_freq); +} + +static void rtc_clk_cpu_freq_to_8m(void) +{ + /* Configure clk mspi fast to XTAL*/ + clk_ll_mspi_fast_sel_clk(SOC_MOD_CLK_XTAL); + clk_ll_mspi_fast_set_divider(1); + + clk_ll_ahb_set_divider(1); + clk_ll_cpu_set_divider(1); + clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); + esp_rom_set_cpu_ticks_per_us(20); +} + +/** + * Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL. + * PLL must already be enabled. + * @param cpu_freq new CPU frequency + */ +static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) +{ + rtc_cpu_freq_config_t cfg; + rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &cfg); + // Set AHB always be 40MHz + clk_ll_ahb_set_divider(cfg.source_freq_mhz / 40); + clk_ll_cpu_set_divider(cfg.div); + clk_ll_cpu_set_src(cfg.source); + esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); + + /* Configure clk mspi fast to 80m*/ + clk_ll_mspi_fast_set_divider(6); + clk_ll_mspi_fast_sel_clk(MSPI_CLK_SRC_SPLL); +} + +bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config) +{ + uint32_t source_freq_mhz; + soc_cpu_clk_src_t source; + uint32_t divider; // divider = freq of SOC_ROOT_CLK / freq of CPU_CLK + uint32_t real_freq_mhz; + + uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get(); + if (freq_mhz == 48 || freq_mhz == 24 || freq_mhz == 16 || freq_mhz == 12 || freq_mhz == 8) { + divider = xtal_freq / freq_mhz; + source_freq_mhz = xtal_freq; + source = SOC_CPU_CLK_SRC_XTAL; + real_freq_mhz = freq_mhz; + } else if (freq_mhz == 240 || freq_mhz == 120) { + real_freq_mhz = freq_mhz; + source = SOC_CPU_CLK_SRC_PLL_F240; + source_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ; + divider = CLK_LL_PLL_240M_FREQ_MHZ / freq_mhz; + }else if (freq_mhz == 160 || freq_mhz == 80 || freq_mhz == 40) { + real_freq_mhz = freq_mhz; + source = SOC_CPU_CLK_SRC_PLL_F160; + source_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ; + divider = CLK_LL_PLL_160M_FREQ_MHZ / freq_mhz; + } 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; +} + +__attribute__((weak)) void rtc_clk_set_cpu_switch_to_bbpll(int event_id) +{ +} + +void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) +{ + soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src(); + if (config->source == SOC_CPU_CLK_SRC_XTAL) { + /* Configure clk mspi fast to 80m*/ + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); + if (((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240)) && !s_bbpll_digi_consumers_ref_count) { + // We don't turn off the bbpll if some consumers depend on bbpll + rtc_clk_bbpll_disable(); + } + } else if ((config->source == SOC_CPU_CLK_SRC_PLL_F160) || (config->source == SOC_CPU_CLK_SRC_PLL_F240)) { + if ((old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F160) && (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL_F240)) { + rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_EN_START); + 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); + rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_EN_STOP); + } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) { + rtc_clk_cpu_freq_to_8m(); + if (((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160) || (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240)) && !s_bbpll_digi_consumers_ref_count) { + // We don't turn off the bbpll if some consumers depend on bbpll + rtc_clk_bbpll_disable(); + } + } +} + +void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) +{ + soc_cpu_clk_src_t source = clk_ll_cpu_get_src(); + uint32_t source_freq_mhz; + uint32_t div; // div = freq of SOC_ROOT_CLK / freq of CPU_CLK + uint32_t freq_mhz; + switch (source) { + case SOC_CPU_CLK_SRC_XTAL: { + div = clk_ll_cpu_get_divider(); + source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get(); + freq_mhz = source_freq_mhz / div; + break; + } + case SOC_CPU_CLK_SRC_PLL_F160: { + div = clk_ll_cpu_get_divider(); + source_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ; + freq_mhz = source_freq_mhz / div; + break; + } + case SOC_CPU_CLK_SRC_PLL_F240: { + div = clk_ll_cpu_get_divider(); + source_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ; + freq_mhz = source_freq_mhz / div; + break; + } + case SOC_CPU_CLK_SRC_RC_FAST: + div = clk_ll_cpu_get_divider(); + source_freq_mhz = 20; + freq_mhz = source_freq_mhz / div; + break; + default: + ESP_HW_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 == SOC_CPU_CLK_SRC_XTAL) { + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); + } else if (((config->source == SOC_CPU_CLK_SRC_PLL_F160) || (config->source == SOC_CPU_CLK_SRC_PLL_F240)) && + s_cur_pll_freq == config->source_freq_mhz) { + rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz); + } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) { + rtc_clk_cpu_freq_to_8m(); + } else { + /* fallback */ + rtc_clk_cpu_freq_set_config(config); + } +} + +void rtc_clk_cpu_freq_set_xtal(void) +{ + rtc_clk_cpu_set_to_default_config(); + // We don't turn off the bbpll if some consumers depend on bbpll + if (!s_bbpll_digi_consumers_ref_count) { + rtc_clk_bbpll_disable(); + } +} + +void rtc_clk_cpu_set_to_default_config(void) +{ + int freq_mhz = (int)rtc_clk_xtal_freq_get(); + + rtc_clk_cpu_freq_to_xtal(freq_mhz, 1); +} + +void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) +{ + rtc_clk_cpu_freq_to_pll_mhz(cpu_freq_mhz); + clk_ll_cpu_clk_src_lock_release(); +} + +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) +{ + return CONFIG_XTAL_FREQ; +} + +void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq) +{ + clk_ll_xtal_store_freq_mhz(xtal_freq); +} + +static uint32_t rtc_clk_ahb_freq_get(void) +{ + soc_cpu_clk_src_t source = clk_ll_cpu_get_src(); + uint32_t soc_root_freq_mhz; + uint32_t divider; + switch (source) { + case SOC_CPU_CLK_SRC_XTAL: + soc_root_freq_mhz = rtc_clk_xtal_freq_get(); + divider = clk_ll_ahb_get_divider(); + break; + case SOC_CPU_CLK_SRC_PLL_F160: + soc_root_freq_mhz = CLK_LL_PLL_160M_FREQ_MHZ; + divider = clk_ll_ahb_get_divider(); + break; + case SOC_CPU_CLK_SRC_PLL_F240: + soc_root_freq_mhz = CLK_LL_PLL_240M_FREQ_MHZ; + divider = clk_ll_ahb_get_divider(); + break; + case SOC_CPU_CLK_SRC_RC_FAST: + soc_root_freq_mhz = 20; + divider = clk_ll_ahb_get_divider(); + break; + default: + // Unknown SOC_ROOT clock source + soc_root_freq_mhz = 0; + divider = 1; + ESP_HW_LOGE(TAG, "Invalid SOC_ROOT_CLK"); + break; + } + return soc_root_freq_mhz / divider; +} + +uint32_t rtc_clk_apb_freq_get(void) +{ + return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ; +} + +void rtc_dig_clk8m_enable(void) +{ + clk_ll_rc_fast_digi_enable(); + esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + clk_ll_rc_fast_digi_disable(); + esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH); +} + +bool rtc_dig_8m_enabled(void) +{ + return clk_ll_rc_fast_digi_is_enabled(); +} + +/* Name used in libphy.a:phy_chip_v7.o + * TODO: update the library to use rtc_clk_xtal_freq_get + */ +rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get"))); diff --git a/components/esp_hw_support/port/esp32c5/rtc_clk_init.c b/components/esp_hw_support/port/esp32c5/rtc_clk_init.c new file mode 100644 index 0000000000..afaa53475f --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/rtc_clk_init.c @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "esp32c5/rom/ets_sys.h" +#include "esp32c5/rom/rtc.h" +#include "esp32c5/rom/uart.h" +#include "soc/rtc.h" +#include "esp_cpu.h" +#include "regi2c_ctrl.h" +#include "soc/lp_clkrst_reg.h" +#include "soc/regi2c_dig_reg.h" +#include "esp_hw_log.h" +#include "sdkconfig.h" +#include "esp_rom_uart.h" +#include "esp_private/esp_pmu.h" +#include "hal/clk_tree_ll.h" +// #include "hal/pmu_ll.h" +#include "hal/modem_syscon_ll.h" +#include "hal/modem_lpcon_ll.h" +#include "soc/pmu_reg.h" +#include "pmu_param.h" + +static const char *TAG = "rtc_clk_init"; + +/** + * Initialize the ICG map of some modem clock domains in the PMU_ACTIVE state + * + * A pre-initialization interface is used to initialize the ICG map of the + * MODEM_APB, I2C_MST and LP_APB clock domains in the PMU_ACTIVE state, and + * disable the clock gating of these clock domains in the PMU_ACTIVE state, + * because the system clock source (PLL) in the system boot up process needs + * to use the i2c master peripheral. + * + * ICG map of all modem clock domains under different power states (PMU_ACTIVE, + * PMU_MODEM and PMU_SLEEP) will be initialized in esp_perip_clk_init(). + */ +static void rtc_clk_modem_clock_domain_active_state_icg_map_preinit(void) +{ + /* Configure modem ICG code in PMU_ACTIVE state */ + pmu_ll_hp_set_icg_modem(&PMU, PMU_MODE_HP_ACTIVE, PMU_HP_ICG_MODEM_CODE_ACTIVE); + + /* Disable clock gating for MODEM_APB, I2C_MST and LP_APB clock domains in PMU_ACTIVE state */ + modem_syscon_ll_set_modem_apb_icg_bitmap(&MODEM_SYSCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); + modem_lpcon_ll_set_i2c_master_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); + modem_lpcon_ll_set_lp_apb_icg_bitmap(&MODEM_LPCON, BIT(PMU_HP_ICG_MODEM_CODE_ACTIVE)); + + /* Software trigger force update modem ICG code and ICG switch */ + pmu_ll_imm_update_dig_icg_modem_code(&PMU, true); + pmu_ll_imm_update_dig_icg_switch(&PMU, true); +} + + +void rtc_clk_init(rtc_clk_config_t cfg) +{ + rtc_cpu_freq_config_t old_config, new_config; + + rtc_clk_modem_clock_domain_active_state_icg_map_preinit(); + + /* Set tuning parameters for RC_FAST, RC_SLOW, and RC32K 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 RC_SLOW clock. + * The higher the value of DCAP is, the lower is the frequency. + * - CK8M_DFREQ value controls tuning of RC_FAST clock. + * CLK_8M_DFREQ constant gives the best temperature characteristics. + * - RC32K_DFREQ value controls tuning of RC32K clock. + */ + REG_SET_FIELD(LP_CLKRST_FOSC_CNTL_REG, LP_CLKRST_FOSC_DFREQ, cfg.clk_8m_dfreq); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_SCK_DCAP, cfg.slow_clk_dcap); + REG_SET_FIELD(LP_CLKRST_RC32K_CNTL_REG, LP_CLKRST_RC32K_DFREQ, cfg.rc32k_dfreq); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_RTC_DREG, 1); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_ENIF_DIG_DREG, 1); + REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, HP_CALI_DBIAS); + REG_SET_FIELD(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, LP_CALI_DBIAS); + + clk_ll_rc_fast_tick_conf(); + + rtc_xtal_freq_t xtal_freq = cfg.xtal_freq; + esp_rom_uart_tx_wait_idle(0); + rtc_clk_xtal_freq_update(xtal_freq); + + /* 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) { + ESP_HW_LOGE(TAG, "invalid CPU frequency value"); + abort(); + } + rtc_clk_cpu_freq_set_config(&new_config); + + /* Re-calculate the ccount to make time calculation correct. */ + esp_cpu_set_cycle_count( (uint64_t)esp_cpu_get_cycle_count() * cfg.cpu_freq_mhz / freq_before ); + + /* Slow & fast clocks setup */ + // We will not power off RC_FAST in bootloader stage even if it is not being used as any + // cpu / rtc_fast / rtc_slow clock sources, this is because RNG always needs it in the bootloader stage. + bool need_rc_fast_en = true; + if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + rtc_clk_32k_enable(true); + } else if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + rtc_clk_32k_enable_external(); + } else if (cfg.slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) { + rtc_clk_rc32k_enable(true); + } + rtc_clk_8m_enable(need_rc_fast_en); + rtc_clk_fast_src_set(cfg.fast_clk_src); + rtc_clk_slow_src_set(cfg.slow_clk_src); +} diff --git a/components/esp_hw_support/port/esp32c5/rtc_time.c b/components/esp_hw_support/port/esp32c5/rtc_time.c new file mode 100644 index 0000000000..49be74760b --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/rtc_time.c @@ -0,0 +1,284 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp32c5/rom/ets_sys.h" +#include "soc/rtc.h" +#include "soc/lp_timer_reg.h" +#include "hal/lp_timer_hal.h" +#include "hal/clk_tree_ll.h" +#include "hal/timer_ll.h" +#include "soc/timer_group_reg.h" +#include "esp_rom_sys.h" +#include "assert.h" +#include "hal/efuse_hal.h" +#include "soc/chip_revision.h" +#include "esp_private/periph_ctrl.h" + +static const char *TAG = "rtc_time"; + +// TODO: [ESP32C5] IDF-8667 + +/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0. + * This feature counts the number of XTAL clock cycles within a given number of + * RTC_SLOW_CLK cycles. + * + * Slow clock calibration feature has two modes of operation: one-off and cycling. + * In cycling mode (which is enabled by default on SoC reset), counting of XTAL + * cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled + * using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed + * once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is + * enabled using TIMG_RTC_CALI_START bit. + */ + +/* On ESP32C5, TIMG_RTC_CALI_CLK_SEL can config to 0, 1, 2, 3 + * 0 or 3: calibrate RC_SLOW clock + * 1: calibrate RC_FAST clock + * 2: calibrate 32K clock, which 32k depends on reg_32k_sel: 0: Internal 32 kHz RC oscillator, 1: External 32 kHz XTAL, 2: External 32kHz clock input by lp_pad_gpio0 + */ +#define TIMG_RTC_CALI_CLK_SEL_RC_SLOW 0 +#define TIMG_RTC_CALI_CLK_SEL_RC_FAST 1 +#define TIMG_RTC_CALI_CLK_SEL_32K 2 + +/** + * @brief Clock calibration function used by rtc_clk_cal + * + * Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0. + * This feature counts the number of XTAL clock cycles within a given number of + * RTC_SLOW_CLK cycles. + * + * Slow clock calibration feature has two modes of operation: one-off and cycling. + * In cycling mode (which is enabled by default on SoC reset), counting of XTAL + * cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled + * using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed + * once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is + * enabled using TIMG_RTC_CALI_START bit. + * + * @param cal_clk which clock to calibrate + * @param slowclk_cycles number of slow clock cycles to count + * @return number of XTAL clock cycles within the given number of slow clock cycles + */ +static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V); + + uint32_t cali_clk_sel = 0; + soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get(); + soc_rtc_slow_clk_src_t old_32k_cal_clk_sel = clk_ll_32k_calibration_get_target(); + if (cal_clk == RTC_CAL_RTC_MUX) { + cal_clk = (rtc_cal_sel_t)slow_clk_src; + } + if (cal_clk == RTC_CAL_RC_FAST) { + cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST; +#if !CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8642 Seems RC_SLOW can't be calibrated + } else if (cal_clk == RTC_CAL_RC_SLOW) { + cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW; +#endif // !CONFIG_IDF_TARGET_ESP32C5 + } else { + cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K; + clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk); + } + + + /* Enable requested clock (150k clock is always on) */ + // All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock + // Only enable if orignally was disabled, and set back to the disable state after calibration is done + // If the clock is already on, then do nothing + bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled(); + if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) { + clk_ll_xtal32k_digi_enable(); + } + + bool rc_fast_enabled = clk_ll_rc_fast_is_enabled(); + bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled(); + if (cal_clk == RTC_CAL_RC_FAST) { + if (!rc_fast_enabled) { + rtc_clk_8m_enable(true); + } + if (!dig_rc_fast_enabled) { + rtc_dig_clk8m_enable(); + } + } + + bool rc32k_enabled = clk_ll_rc32k_is_enabled(); + bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled(); + if (cal_clk == RTC_CAL_RC32K) { + if (!rc32k_enabled) { + rtc_clk_rc32k_enable(true); + } + if (!dig_rc32k_enabled) { + clk_ll_rc32k_digi_enable(); + } + } + + /* There may be another calibration process already running during we call this function, + * so we should wait the last process is done. + */ + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING)) { + /** + * Set a small timeout threshold to accelerate the generation of timeout. + * The internal circuit will be reset when the timeout occurs and will not affect the next calibration. + */ + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, 1); + while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY) + && !GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)); + } + + /* Prepare calibration */ + REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cali_clk_sel); + CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING); + REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles); + /* Figure out how long to wait for calibration to finish */ + + /* Set timeout reg and expect time delay*/ + uint32_t expected_freq; + if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_32K) { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX; + } else if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX; + } else { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_150K_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX; + } + uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq); + /* Start calibration */ + CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); + SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); + + /* Wait for calibration to finish up to another us_time_estimate */ + esp_rom_delay_us(us_time_estimate); + uint32_t cal_val; + while (true) { + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) { + cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE); + + /*The Fosc CLK of calibration circuit is divided by 32 for ECO1. + So we need to multiply the frequency of the Fosc for ECO1 and above chips by 32 times. + And ensure that this modification will not affect ECO0.*/ + if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) { + if (cal_clk == RTC_CAL_RC_FAST) { + cal_val = cal_val >> 5; + } + } + break; + } + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) { + cal_val = 0; + break; + } + } + CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); + + /* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */ + if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) { + clk_ll_xtal32k_digi_disable(); + } + + if (cal_clk == RTC_CAL_RC_FAST) { + if (!dig_rc_fast_enabled) { + rtc_dig_clk8m_disable(); + } + if (!rc_fast_enabled) { + rtc_clk_8m_enable(false); + } + } + + if (cal_clk == RTC_CAL_RC32K) { + if (!dig_rc32k_enabled) { + clk_ll_rc32k_digi_disable(); + } + if (!rc32k_enabled) { + rtc_clk_rc32k_enable(false); + } + } + + // Always set back the calibration 32kHz clock selection + if (old_32k_cal_clk_sel != SOC_RTC_SLOW_CLK_SRC_INVALID) { + clk_ll_32k_calibration_set_target(old_32k_cal_clk_sel); + } + + return cal_val; +} + +static bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 = 0.05% error range + return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta)); +} + +uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); + + /*The Fosc CLK of calibration circuit is divided by 32 for ECO1. + So we need to divide the calibrate cycles of the FOSC for ECO1 and above chips by 32 to + avoid excessive calibration time.*/ + if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) { + if (cal_clk == RTC_CAL_RC_FAST) { + slowclk_cycles = slowclk_cycles >> 5; + } + } + + uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles); + + if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid(xtal_freq, slowclk_cycles, xtal_cycles)) { + return 0; + } + + uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles; + uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider; + uint32_t period = (uint32_t)(period_64 & UINT32_MAX); + return period; +} + +uint64_t rtc_time_us_to_slowclk(uint64_t time_in_us, uint32_t period) +{ + /* Overflow will happen in this function if time_in_us >= 2^45, which is about 400 days. + * TODO: fix overflow. + */ + return (time_in_us << RTC_CLK_CAL_FRACT) / period; +} + +uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) +{ + return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT; +} + +uint64_t rtc_time_get(void) +{ + // return lp_timer_hal_get_cycle_count(); + ESP_EARLY_LOGW(TAG, "rtc_time_get has not been implemented yet"); + return 0; +} + +void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any more +{ + // TODO: IDF-5781 + ESP_EARLY_LOGW(TAG, "rtc_clk_wait_for_slow_cycle() has not been implemented yet"); +} + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} + +/// @brief if the calibration is used, we need to enable the timer group0 first +__attribute__((constructor)) +static void enable_timer_group0_for_calibration(void) +{ + PERIPH_RCC_ACQUIRE_ATOMIC(PERIPH_TIMG0_MODULE, ref_count) { + if (ref_count == 0) { + timer_ll_enable_bus_clock(0, true); + timer_ll_reset_register(0); + } + } +} diff --git a/components/esp_hw_support/port/esp32c5/sar_periph_ctrl.c b/components/esp_hw_support/port/esp32c5/sar_periph_ctrl.c new file mode 100644 index 0000000000..d6b9d50906 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/sar_periph_ctrl.c @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * SAR related peripherals are interdependent. This file + * provides a united control to these registers, as multiple + * components require these controls. + * + * Related peripherals are: + * - ADC + * - PWDET + */ + +#include "sdkconfig.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +// #include "esp_private/sar_periph_ctrl.h" +// #include "esp_private/esp_modem_clock.h" +// #include "hal/sar_ctrl_ll.h" + +static const char *TAG = "sar_periph_ctrl"; +extern portMUX_TYPE rtc_spinlock; + +// TODO: [ESP32C5] IDF-8701, IDF-8703, IDF-8727 + +void sar_periph_ctrl_init(void) +{ + // sar_ctrl_ll_force_power_ctrl_from_pwdet(true); + + //Add other periph power control initialisation here + ESP_EARLY_LOGW(TAG, "sar_periph_ctrl_init has not implemented on C5 yet"); +} + +void sar_periph_ctrl_power_enable(void) +{ + // portENTER_CRITICAL_SAFE(&rtc_spinlock); + // sar_ctrl_ll_force_power_ctrl_from_pwdet(true); + // portEXIT_CRITICAL_SAFE(&rtc_spinlock); + ESP_EARLY_LOGW(TAG, "sar_periph_ctrl_power_enable has not implemented on C5 yet"); +} + +void sar_periph_ctrl_power_disable(void) +{ + // portENTER_CRITICAL_SAFE(&rtc_spinlock); + // sar_ctrl_ll_force_power_ctrl_from_pwdet(false); + // portEXIT_CRITICAL_SAFE(&rtc_spinlock); + ESP_EARLY_LOGW(TAG, "sar_periph_ctrl_power_disable has not implemented on C5 yet"); +} + +/** + * This gets incremented when s_sar_power_acquire() is called, + * and decremented when s_sar_power_release() is called. + * PWDET is powered down when the value reaches zero. + * Should be modified within critical section. + */ +static int s_pwdet_power_on_cnt; + +static void s_sar_power_acquire(void) +{ + // modem_clock_module_enable(PERIPH_MODEM_ADC_COMMON_FE_MODULE); + portENTER_CRITICAL_SAFE(&rtc_spinlock); + s_pwdet_power_on_cnt++; + if (s_pwdet_power_on_cnt == 1) { + // sar_ctrl_ll_set_power_mode_from_pwdet(SAR_CTRL_LL_POWER_ON); + } + portEXIT_CRITICAL_SAFE(&rtc_spinlock); + ESP_EARLY_LOGW(TAG, "s_sar_power_acquire has not implemented on C5 yet"); +} + +static void s_sar_power_release(void) +{ + portENTER_CRITICAL_SAFE(&rtc_spinlock); + s_pwdet_power_on_cnt--; + if (s_pwdet_power_on_cnt < 0) { + portEXIT_CRITICAL(&rtc_spinlock); + ESP_LOGE(TAG, "%s called, but s_pwdet_power_on_cnt == 0", __func__); + abort(); + } else if (s_pwdet_power_on_cnt == 0) { + // sar_ctrl_ll_set_power_mode_from_pwdet(SAR_CTRL_LL_POWER_FSM); + } + portEXIT_CRITICAL_SAFE(&rtc_spinlock); + ESP_EARLY_LOGW(TAG, "s_sar_power_release has not implemented on C5 yet"); + // modem_clock_module_disable(PERIPH_MODEM_ADC_COMMON_FE_MODULE); +} + + +/*------------------------------------------------------------------------------ +* PWDET Power +*----------------------------------------------------------------------------*/ +void sar_periph_ctrl_pwdet_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_pwdet_power_release(void) +{ + s_sar_power_release(); +} + + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +void sar_periph_ctrl_adc_oneshot_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_adc_oneshot_power_release(void) +{ + s_sar_power_release(); +} + +void sar_periph_ctrl_adc_continuous_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_adc_continuous_power_release(void) +{ + s_sar_power_release(); +} diff --git a/components/esp_hw_support/port/esp32c5/systimer.c b/components/esp_hw_support/port/esp32c5/systimer.c new file mode 100644 index 0000000000..f217295de2 --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/systimer.c @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "esp_private/systimer.h" + +#if CONFIG_XTAL_FREQ_40 +/** + * @brief systimer's clock source is fixed to XTAL (40MHz), and has a fixed fractional divider (2.5). + * So the resolution of the systimer is 40MHz/2.5 = 16MHz. + */ + +uint64_t systimer_ticks_to_us(uint64_t ticks) +{ + return ticks / 16; +} + +uint64_t systimer_us_to_ticks(uint64_t us) +{ + return us * 16; +} +#elif CONFIG_XTAL_FREQ_48 +uint64_t systimer_ticks_to_us(uint64_t ticks) +{ + return ticks * 5 / 96; +} + +uint64_t systimer_us_to_ticks(uint64_t us) +{ + return us * 96 / 5; +} +#else +#error "Unsupported XTAL frequency by systimer" +#endif // CONFIG_XTAL_FREQ_xx diff --git a/components/esp_hw_support/rtc_module.c b/components/esp_hw_support/rtc_module.c index 3e7e44bce8..aed8e0e78e 100644 --- a/components/esp_hw_support/rtc_module.c +++ b/components/esp_hw_support/rtc_module.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,14 +26,14 @@ #endif #include "sys/queue.h" -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4// TODO: IDF-8008 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 static const char *TAG = "rtc_module"; #endif // rtc_spinlock is used by other peripheral drivers portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 #define NOT_REGISTERED (-1) @@ -101,7 +101,7 @@ out: esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask, uint32_t flags) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 ESP_EARLY_LOGW(TAG, "rtc_isr_register() has not been implemented yet"); return ESP_OK; #else @@ -132,7 +132,7 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t r esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) { -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 ESP_EARLY_LOGW(TAG, "rtc_isr_deregister() has not been implemented yet"); return ESP_OK; #else @@ -161,7 +161,7 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) #endif } -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 /** * @brief This helper function can be used to avoid the interrupt to be triggered with cache disabled. * There are lots of different signals on RTC module (i.e. sleep_wakeup, wdt, brownout_detect, etc.) @@ -184,7 +184,7 @@ static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask) IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu) { -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 if (rtc_isr_cpu == cpu) { rtc_intr_enabled |= RTCCNTL.int_ena.val; RTCCNTL.int_ena.val &= rtc_intr_cache; @@ -194,7 +194,7 @@ IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu) IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu) { -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-8008 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8008 if (rtc_isr_cpu == cpu) { RTCCNTL.int_ena.val = rtc_intr_enabled; rtc_intr_enabled = 0; diff --git a/components/esp_hw_support/sleep_clock.c b/components/esp_hw_support/sleep_clock.c index ab60b0980f..bc81b0385d 100644 --- a/components/esp_hw_support/sleep_clock.c +++ b/components/esp_hw_support/sleep_clock.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,7 +33,7 @@ esp_err_t sleep_clock_system_retention_init(void) { #if CONFIG_IDF_TARGET_ESP32C6 #define N_REGS_PCR() (((PCR_SRAM_POWER_CONF_REG - DR_REG_PCR_BASE) / 4) + 1) -#elif CONFIG_IDF_TARGET_ESP32H2 +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 #define N_REGS_PCR() (((PCR_PWDET_SAR_CLK_CONF_REG - DR_REG_PCR_BASE) / 4) + 1) #endif const static sleep_retention_entries_config_t pcr_regs_retention[] = { @@ -53,7 +53,11 @@ void sleep_clock_system_retention_deinit(void) esp_err_t sleep_clock_modem_retention_init(void) { +#if CONFIG_IDF_TARGET_ESP32C5 + #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_RF2_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) +#else #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) +#endif #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) #endif diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index f77c4e336c..5de60e6a29 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,6 +47,14 @@ #include "soc/plic_reg.h" #include "soc/clint_reg.h" #include "esp32c6/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rom/rtc.h" +#include "riscv/rvsleep-frames.h" +#include "soc/intpri_reg.h" +#include "soc/cache_reg.h" +#include "soc/clic_reg.h" +#include "soc/clint_reg.h" +#include "esp32c5/rom/cache.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" #include "riscv/rvsleep-frames.h" @@ -329,7 +337,7 @@ static inline void * cpu_domain_cache_config_sleep_frame_alloc_and_init(void) #if CONFIG_IDF_TARGET_ESP32C6 { .start = EXTMEM_L1_CACHE_CTRL_REG, .end = EXTMEM_L1_CACHE_CTRL_REG + 4 }, { .start = EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = EXTMEM_L1_CACHE_WRAP_AROUND_CTRL_REG + 4 } -#elif CONFIG_IDF_TARGET_ESP32H2 +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 { .start = CACHE_L1_CACHE_CTRL_REG, .end = CACHE_L1_CACHE_CTRL_REG + 4 }, { .start = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG, .end = CACHE_L1_CACHE_WRAP_AROUND_CTRL_REG + 4 } #endif diff --git a/components/esp_hw_support/sleep_cpu_asm.S b/components/esp_hw_support/sleep_cpu_asm.S index 65d0e6de06..788035d11b 100644 --- a/components/esp_hw_support/sleep_cpu_asm.S +++ b/components/esp_hw_support/sleep_cpu_asm.S @@ -9,7 +9,7 @@ #include "soc/soc_caps.h" #include "sdkconfig.h" -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5 #include "soc/lp_aon_reg.h" #include "soc/extmem_reg.h" #endif @@ -115,7 +115,7 @@ rv_core_critical_regs_save: csrr t0, mscratch sw t0, RV_SLP_CTX_T0(t3) -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C5 /* writeback dcache is required here!!! */ la t0, EXTMEM_CACHE_SYNC_MAP_REG li t1, 0x10 diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 4fbe9edf99..545698c240 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -81,6 +81,9 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/rtc.h" #include "hal/gpio_ll.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rom/rtc.h" +#include "hal/gpio_ll.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" #include "esp32h2/rom/cache.h" @@ -131,6 +134,9 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) +#elif CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8638, IDF-8640 +#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) +#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) #elif CONFIG_IDF_TARGET_ESP32H2 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)// TODO: IDF-6267 #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 4bf9be2e7c..d4fa793ee3 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -125,7 +125,7 @@ esp_err_t sleep_sys_periph_tg0_retention_init(void) esp_err_t sleep_sys_periph_iomux_retention_init(void) { -#if CONFIG_IDF_TARGET_ESP32C6 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8638, IDF-8640 #define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_SPID_U - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC34_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) #define N_REGS_IOMUX_2() (((GPIO_FUNC124_IN_SEL_CFG_REG - GPIO_STATUS_NEXT_REG) / 4) + 1) diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index e0b42653d2..0f944aaac4 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -345,6 +345,7 @@ menu "ESP System Settings" prompt "UART console baud rate" if ESP_CONSOLE_UART_CUSTOM depends on ESP_CONSOLE_UART default 74880 if (IDF_TARGET_ESP32C2 && XTAL_FREQ_26) + default 138240 if (IDF_TARGET_ESP32C5_BETA3_VERSION && XTAL_FREQ_48) default 115200 range 1200 4000000 if !PM_ENABLE range 1200 1000000 if PM_ENABLE diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index a4f64dbdc7..03336a2fec 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -8,7 +8,7 @@ #include "spi_flash_mmap.h" -#if CONFIG_IDF_TARGET_ESP32P4 +#if CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 #include "soc/cache_reg.h" #else #include "soc/extmem_reg.h" diff --git a/components/esp_system/port/brownout.c b/components/esp_system/port/brownout.c index 568e1044dd..37b4fae49f 100644 --- a/components/esp_system/port/brownout.c +++ b/components/esp_system/port/brownout.c @@ -73,7 +73,7 @@ void esp_brownout_init(void) brownout_hal_config(&cfg); brownout_ll_intr_clear(); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8647 // TODO IDF-6606: LP_RTC_TIMER interrupt source is shared by lp_timer and brownout detector, but lp_timer interrupt // is not used now. An interrupt allocator is needed when lp_timer intr gets supported. esp_intr_alloc(ETS_LP_RTC_TIMER_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_brownout_isr_handler, NULL, NULL); diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index cddcdf980e..f4167b124c 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,10 @@ #include "esp32c6/rtc.h" #include "esp32c6/rom/cache.h" #include "esp_memprot.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rtc.h" +#include "esp32c5/rom/cache.h" +#include "esp_memprot.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" #include "esp32h2/rom/cache.h" @@ -688,12 +692,12 @@ void IRAM_ATTR call_start_cpu0(void) #endif #endif -#if !CONFIG_IDF_TARGET_ESP32P4 //TODO: IDF-7529 +#if !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 //TODO: IDF-7529, IDF-8638 // Need to unhold the IOs that were hold right before entering deep sleep, which are used as wakeup pins if (rst_reas[0] == RESET_REASON_CORE_DEEP_SLEEP) { esp_deep_sleep_wakeup_io_reset(); } -#endif //#if !CONFIG_IDF_TARGET_ESP32P4 +#endif //#if !CONFIG_IDF_TARGET_ESP32P4 & !CONFIG_IDF_TARGET_ESP32C5 #if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP esp_cache_err_int_init(); diff --git a/components/esp_system/port/soc/esp32c5/CMakeLists.txt b/components/esp_system/port/soc/esp32c5/CMakeLists.txt index e69de29bb2..4764e7e4d4 100644 --- a/components/esp_system/port/soc/esp32c5/CMakeLists.txt +++ b/components/esp_system/port/soc/esp32c5/CMakeLists.txt @@ -0,0 +1,8 @@ +set(srcs "clk.c" + "reset_reason.c" + "system_internal.c" + "cache_err_int.c") + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/soc/esp32c5/Kconfig.cpu b/components/esp_system/port/soc/esp32c5/Kconfig.cpu index e69de29bb2..bd6b177c23 100644 --- a/components/esp_system/port/soc/esp32c5/Kconfig.cpu +++ b/components/esp_system/port/soc/esp32c5/Kconfig.cpu @@ -0,0 +1,28 @@ +choice ESP_DEFAULT_CPU_FREQ_MHZ + prompt "CPU frequency" + default ESP_DEFAULT_CPU_FREQ_MHZ_40 if IDF_ENV_FPGA + default ESP_DEFAULT_CPU_FREQ_MHZ_240 + help + CPU frequency to be set on application startup. + + config ESP_DEFAULT_CPU_FREQ_MHZ_40 + bool "40 MHz" + depends on IDF_ENV_FPGA + config ESP_DEFAULT_CPU_FREQ_MHZ_80 + bool "80 MHz" + config ESP_DEFAULT_CPU_FREQ_MHZ_120 + bool "120 MHz" + config ESP_DEFAULT_CPU_FREQ_MHZ_160 + bool "160 MHz" + config ESP_DEFAULT_CPU_FREQ_MHZ_240 + bool "240 MHz" +endchoice + +config ESP_DEFAULT_CPU_FREQ_MHZ + int + default 40 if ESP_DEFAULT_CPU_FREQ_MHZ_40 + default 60 if ESP_DEFAULT_CPU_FREQ_MHZ_60 + default 80 if ESP_DEFAULT_CPU_FREQ_MHZ_80 + default 120 if ESP_DEFAULT_CPU_FREQ_MHZ_120 + default 160 if ESP_DEFAULT_CPU_FREQ_MHZ_160 + default 240 if ESP_DEFAULT_CPU_FREQ_MHZ_240 diff --git a/components/esp_system/port/soc/esp32c5/Kconfig.system b/components/esp_system/port/soc/esp32c5/Kconfig.system index e69de29bb2..756610417d 100644 --- a/components/esp_system/port/soc/esp32c5/Kconfig.system +++ b/components/esp_system/port/soc/esp32c5/Kconfig.system @@ -0,0 +1,46 @@ +menu "Brownout Detector" + config ESP_BROWNOUT_DET + bool "Hardware brownout detect & reset" + depends on !IDF_ENV_FPGA && SOC_BOD_SUPPORTED + default y + help + The ESP32-C5 has a built-in brownout detector which can detect if the voltage is lower than + a specific value. If this happens, it will reset the chip in order to prevent unintended + behaviour. + + choice ESP_BROWNOUT_DET_LVL_SEL + prompt "Brownout voltage level" + depends on ESP_BROWNOUT_DET + default ESP_BROWNOUT_DET_LVL_SEL_7 + help + TODO: [ESP32C5] IDF-8647 + The brownout detector will reset the chip when the supply voltage is approximately + below this level. Note that there may be some variation of brownout voltage level + between each chip. + + #The voltage levels here are estimates, more work needs to be done to figure out the exact voltages + #of the brownout threshold levels. + config ESP_BROWNOUT_DET_LVL_SEL_7 + bool "2.51V" + config ESP_BROWNOUT_DET_LVL_SEL_6 + bool "2.64V" + config ESP_BROWNOUT_DET_LVL_SEL_5 + bool "2.76V" + config ESP_BROWNOUT_DET_LVL_SEL_4 + bool "2.92V" + config ESP_BROWNOUT_DET_LVL_SEL_3 + bool "3.10V" + config ESP_BROWNOUT_DET_LVL_SEL_2 + bool "3.27V" + endchoice + + config ESP_BROWNOUT_DET_LVL + int + default 2 if ESP_BROWNOUT_DET_LVL_SEL_2 + default 3 if ESP_BROWNOUT_DET_LVL_SEL_3 + default 4 if ESP_BROWNOUT_DET_LVL_SEL_4 + default 5 if ESP_BROWNOUT_DET_LVL_SEL_5 + default 6 if ESP_BROWNOUT_DET_LVL_SEL_6 + default 7 if ESP_BROWNOUT_DET_LVL_SEL_7 + +endmenu diff --git a/components/esp_system/port/soc/esp32c5/cache_err_int.c b/components/esp_system/port/soc/esp32c5/cache_err_int.c new file mode 100644 index 0000000000..4382ac2e7a --- /dev/null +++ b/components/esp_system/port/soc/esp32c5/cache_err_int.c @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + The cache has an interrupt that can be raised as soon as an access to a cached + region (flash) is done without the cache being enabled. We use that here + to panic the CPU, which from a debugging perspective is better than grabbing bad + data from the bus. +*/ +#include "esp_rom_sys.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "soc/soc.h" +#include "riscv/interrupt.h" +#include "hal/cache_ll.h" + +static const char *TAG = "CACHE_ERR"; + +const char cache_error_msg[] = "Cache access error"; + +const char *esp_cache_err_panic_string(void) +{ + const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + + /* Return the error string if a cache error is active */ + const char* err_str = access_err_status ? cache_error_msg : NULL; + + return err_str; +} + +bool esp_cache_err_has_active_err(void) +{ + return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + +void esp_cache_err_int_init(void) +{ + const uint32_t core_id = 0; + + /* Disable cache interrupts if enabled. */ + ESP_INTR_DISABLE(ETS_CACHEERR_INUM); + + /** + * Bind all cache errors to ETS_CACHEERR_INUM interrupt. we will deal with + * them in handler by different types + * + * On ESP32C5 boards, the cache is a shared one but buses are still + * distinct. So, we have an bus0 and a bus1 sharing the same cache. + * This error can occur if a bus performs a request but the cache + * is disabled. + */ + esp_rom_route_intr_matrix(core_id, ETS_CACHE_INTR_SOURCE, ETS_CACHEERR_INUM); + + /* Set the type and priority to cache error interrupts. */ + esprv_intc_int_set_type(ETS_CACHEERR_INUM, INTR_TYPE_LEVEL); + esprv_intc_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); + + ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); + /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + /* Then enable cache access error interrupts. */ + cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + + /* Enable the interrupts for cache error. */ + ESP_INTR_ENABLE(ETS_CACHEERR_INUM); +} + +int esp_cache_err_get_cpuid(void) +{ + return 0; +} diff --git a/components/esp_system/port/soc/esp32c5/clk.c b/components/esp_system/port/soc/esp32c5/clk.c new file mode 100644 index 0000000000..37b8c59d04 --- /dev/null +++ b/components/esp_system/port/soc/esp32c5/clk.c @@ -0,0 +1,301 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_clk_internal.h" +#include "esp32c5/rom/ets_sys.h" +#include "esp32c5/rom/uart.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/i2s_reg.h" +#include "esp_cpu.h" +#include "hal/wdt_hal.h" +#include "hal/modem_lpcon_ll.h" +#include "esp_private/esp_modem_clock.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk.h" +#include "esp_private/esp_pmu.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_RTC_CLK_CAL_CYCLES + +#define MHZ (1000000) + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); + +static const char *TAG = "clk"; + +// TODO: [ESP32C5] IDF-8642 + __attribute__((weak)) void esp_clk_init(void) +{ +#if SOC_PMU_SUPPORTED + pmu_init(); +#endif + + assert((rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M) || (rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_48M)); + + modem_lpcon_ll_set_pwr_tick_target(&MODEM_LPCON, rtc_clk_xtal_freq_get() - 1); + + rtc_clk_8m_enable(true); + rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +#elif defined(CONFIG_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_OSC_SLOW); +#elif defined(CONFIG_RTC_CLK_SRC_INT_RC32K) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_RC32K); +#else + abort(); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP_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 + esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + if (res) { + rtc_clk_cpu_freq_set_config(&new_config); + } + + // Re calculate the ccount to make time calculation correct. + esp_cpu_set_cycle_count( (uint64_t)esp_cpu_get_cycle_count() * new_freq_mhz / old_freq_mhz ); +} + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src) +{ + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = 3; + + do { + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K || rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + rtc_cal_sel_t cal_sel = 0; + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + rtc_clk_32k_enable(true); + cal_sel = RTC_CAL_32K_XTAL; + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + rtc_clk_32k_enable_external(); + cal_sel = RTC_CAL_32K_OSC_SLOW; + } + // 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(cal_sel, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0) { + if (retry_32k_xtal-- > 0) { + continue; + } +#if CONFIG_IDF_TARGET_ESP32C5 + ESP_EARLY_LOGW(TAG, "32 kHz clock not found, switching to internal 32 kHz oscillator"); + rtc_slow_clk_src = SOC_RTC_SLOW_CLK_SRC_RC32K; +#else + ESP_EARLY_LOGW(TAG, "32 kHz clock not found, switching to internal 150 kHz oscillator"); + rtc_slow_clk_src = SOC_RTC_SLOW_CLK_SRC_RC_SLOW; +#endif + } + } + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) { + rtc_clk_rc32k_enable(true); + } + rtc_clk_slow_src_set(rtc_slow_clk_src); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +__attribute__((weak)) void esp_perip_clk_init(void) +{ +#if 0 // TODO: [ESP32C5] IDF-8844 + /* During system initialization, the low-power clock source of the modem + * (WiFi, BLE or Coexist) follows the configuration of the slow clock source + * of the system. If the WiFi, BLE or Coexist module needs a higher + * precision sleep clock (for example, the BLE needs to use the main XTAL + * oscillator (40 MHz) to provide the clock during the sleep process in some + * scenarios), the module needs to switch to the required clock source by + * itself. */ //TODO - WIFI-5233 + soc_rtc_slow_clk_src_t rtc_slow_clk_src = rtc_clk_slow_src_get(); + modem_clock_lpclk_src_t modem_lpclk_src = (modem_clock_lpclk_src_t) ( \ + (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? MODEM_CLOCK_LPCLK_SRC_XTAL32K \ + : (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) ? MODEM_CLOCK_LPCLK_SRC_RC32K \ + : (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) ? MODEM_CLOCK_LPCLK_SRC_EXT32K \ + : MODEM_CLOCK_LPCLK_SRC_RC32K); + + modem_clock_select_lp_clock_source(PERIPH_WIFI_MODULE, modem_lpclk_src, 0); +#endif + + ESP_EARLY_LOGW(TAG, "esp_perip_clk_init() has not been implemented yet"); +#if 0 // TODO: [ESP32C5] IDF-8844 + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + uint32_t common_perip_clk1 = 0; + + soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if (rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_SW || + rst_reason == RESET_REASON_CPU0_RTC_WDT || rst_reason == RESET_REASON_CPU0_MWDT1) { + common_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN0_REG); + hwcrypto_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN1_REG); + wifi_bt_sdio_clk = ~READ_PERI_REG(SYSTEM_WIFI_CLK_EN_REG); + } else { + common_perip_clk = SYSTEM_WDG_CLK_EN | + SYSTEM_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_LEDC_CLK_EN | + SYSTEM_TIMERGROUP1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_TWAI_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + + common_perip_clk1 = 0; + hwcrypto_perip_clk = SYSTEM_CRYPTO_AES_CLK_EN | + SYSTEM_CRYPTO_SHA_CLK_EN | + SYSTEM_CRYPTO_RSA_CLK_EN; + wifi_bt_sdio_clk = SYSTEM_WIFI_CLK_WIFI_EN | + SYSTEM_WIFI_CLK_BT_EN_M | + SYSTEM_WIFI_CLK_UNUSED_BIT5 | + SYSTEM_WIFI_CLK_UNUSED_BIT12; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= SYSTEM_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_UHCI1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_I2C_EXT1_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + common_perip_clk1 = 0; + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + // TOCK(check replacement) + // REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + // REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + + /* Disable some peripheral clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN0_REG, common_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, common_perip_clk); + + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, common_perip_clk1); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, common_perip_clk1); + + /* Disable hardware crypto clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); + + /* Set WiFi light sleep clock source to RTC slow clock */ + REG_SET_FIELD(SYSTEM_BT_LPCK_DIV_INT_REG, SYSTEM_BT_LPCK_DIV_NUM, 0); + CLEAR_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_8M); + SET_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_RTC_SLOW); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +#endif +} diff --git a/components/esp_system/port/soc/esp32c5/reset_reason.c b/components/esp_system/port/soc/esp32c5/reset_reason.c new file mode 100644 index 0000000000..1f9402586b --- /dev/null +++ b/components/esp_system/port/soc/esp32c5/reset_reason.c @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_system.h" +#include "esp_rom_sys.h" +#include "esp_private/system_internal.h" +#include "soc/rtc_periph.h" +#include "esp32c5/rom/rtc.h" + +static void esp_reset_reason_clear_hint(void); + +static esp_reset_reason_t s_reset_reason; + +// TODO: [ESP32C5] IDF-8660 + +static esp_reset_reason_t get_reset_reason(soc_reset_reason_t rtc_reset_reason, esp_reset_reason_t reset_reason_hint) +{ + switch (rtc_reset_reason) { + case RESET_REASON_CHIP_POWER_ON: + return ESP_RST_POWERON; + + case RESET_REASON_CPU0_SW: + case RESET_REASON_CORE_SW: + if (reset_reason_hint == ESP_RST_PANIC || + reset_reason_hint == ESP_RST_BROWNOUT || + reset_reason_hint == ESP_RST_TASK_WDT || + reset_reason_hint == ESP_RST_INT_WDT) { + return reset_reason_hint; + } + return ESP_RST_SW; + + case RESET_REASON_CORE_DEEP_SLEEP: + return ESP_RST_DEEPSLEEP; + + case RESET_REASON_CORE_MWDT0: + return ESP_RST_TASK_WDT; + + case RESET_REASON_CORE_MWDT1: + return ESP_RST_INT_WDT; + + case RESET_REASON_CORE_RTC_WDT: + case RESET_REASON_SYS_RTC_WDT: + case RESET_REASON_SYS_SUPER_WDT: + case RESET_REASON_CPU0_RTC_WDT: + case RESET_REASON_CPU0_MWDT0: + case RESET_REASON_CPU0_MWDT1: + return ESP_RST_WDT; + + case RESET_REASON_SYS_BROWN_OUT: + return ESP_RST_BROWNOUT; + + case RESET_REASON_CORE_USB_UART: + case RESET_REASON_CORE_USB_JTAG: + return ESP_RST_USB; + + default: + return ESP_RST_UNKNOWN; + } +} + +static void __attribute__((constructor)) esp_reset_reason_init(void) +{ + esp_reset_reason_t hint = esp_reset_reason_get_hint(); + s_reset_reason = get_reset_reason(esp_rom_get_reset_reason(PRO_CPU_NUM), hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } +} + +esp_reset_reason_t esp_reset_reason(void) +{ + return s_reset_reason; +} + +/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG, + * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the + * deep sleep wake stub entry address and for reset reason hint, since wake stub + * is only used for deep sleep reset, and in this case the reason provided by + * esp_rom_get_reset_reason is unambiguous. + * + * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG): + * the value is replicated in low and high half-words. In addition to that, + * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains + * deep sleep wake stub address. + */ + +#define RST_REASON_BIT 0x80000000 +#define RST_REASON_MASK 0x7FFF +#define RST_REASON_SHIFT 16 + +/* in IRAM, can be called from panic handler */ +void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + assert((hint & (~RST_REASON_MASK)) == 0); + uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT; + REG_WRITE(RTC_RESET_CAUSE_REG, val); +} + +/* in IRAM, can be called from panic handler */ +esp_reset_reason_t esp_reset_reason_get_hint(void) +{ + uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG); + uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK; + uint32_t low = reset_reason_hint & RST_REASON_MASK; + if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) { + return ESP_RST_UNKNOWN; + } + return (esp_reset_reason_t) low; +} +static inline void esp_reset_reason_clear_hint(void) +{ + REG_WRITE(RTC_RESET_CAUSE_REG, 0); +} diff --git a/components/esp_system/port/soc/esp32c5/system_internal.c b/components/esp_system/port/soc/esp32c5/system_internal.c new file mode 100644 index 0000000000..ea56bfead8 --- /dev/null +++ b/components/esp_system/port/soc/esp32c5/system_internal.c @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_private/system_internal.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_rom_sys.h" +#include "riscv/rv_utils.h" +#include "esp_rom_uart.h" +#include "soc/gpio_reg.h" +#include "esp_cpu.h" +#include "soc/rtc.h" +#include "esp_private/rtc_clk.h" +#include "soc/rtc_periph.h" +#include "soc/uart_reg.h" +#include "hal/clk_tree_ll.h" +#include "hal/wdt_hal.h" +#include "hal/modem_syscon_ll.h" +#include "hal/modem_lpcon_ll.h" +#include "esp_private/cache_err_int.h" + +#include "esp32c5/rom/cache.h" +#include "esp32c5/rom/rtc.h" +#include "soc/pcr_reg.h" + +void IRAM_ATTR esp_system_reset_modules_on_exit(void) +{ + // Flush any data left in UART FIFOs before reset the UART peripheral + esp_rom_uart_tx_wait_idle(0); + esp_rom_uart_tx_wait_idle(1); + + modem_syscon_ll_reset_all(&MODEM_SYSCON); + modem_lpcon_ll_reset_all(&MODEM_LPCON); + + // Set SPI Flash Freq to 40M + clk_ll_mspi_fast_sel_clk(MSPI_CLK_SRC_XTAL); + clk_ll_mspi_fast_set_divider(1); + + // Set Peripheral clk rst + SET_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); + SET_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + SET_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); + SET_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); + SET_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); + SET_PERI_REG_MASK(PCR_GDMA_CONF_REG, PCR_GDMA_RST_EN); + SET_PERI_REG_MASK(PCR_SDIO_SLAVE_CONF_REG, PCR_SDIO_SLAVE_RST_EN); + SET_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); + SET_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); + + // Clear Peripheral clk rst + CLEAR_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); + CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + CLEAR_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); + CLEAR_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); + CLEAR_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); + CLEAR_PERI_REG_MASK(PCR_GDMA_CONF_REG, PCR_GDMA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_SDIO_SLAVE_CONF_REG, PCR_SDIO_SLAVE_RST_EN); + CLEAR_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); + CLEAR_PERI_REG_MASK(PCR_PWM_CONF_REG, PCR_PWM_RST_EN); +} + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void IRAM_ATTR esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + + // C5 is a single core SoC, no need to reset and stall the other CPU + + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + + // Disable cache + Cache_Disable_ICache(); + + // Reset wifi/bluetooth/ethernet/sdio (bb/mac) + // Moved to module internal + // SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, + // SYSTEM_SDIO_RST | // SDIO_HINF_HINF_SDIO_RST? + // SYSTEM_EMAC_RST | SYSTEM_MACPWR_RST | // TODO: IDF-5325 (ethernet) + // REG_WRITE(SYSTEM_CORE_RST_EN_REG, 0); + + esp_system_reset_modules_on_exit(); + + // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_set_to_default_config(); +#endif + + // Reset PRO CPU + esp_rom_software_reset_cpu(0); + while (true) { + ; + } +} diff --git a/components/esp_system/system_time.c b/components/esp_system/system_time.c index f712239948..668ddeb88c 100644 --- a/components/esp_system/system_time.c +++ b/components/esp_system/system_time.c @@ -29,6 +29,8 @@ #include "esp32h2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32P4 #include "esp32p4/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rtc.h" #endif #include "esp_private/startup_internal.h" diff --git a/components/esp_timer/src/ets_timer_legacy.c b/components/esp_timer/src/ets_timer_legacy.c index dc80901a43..a37b88f253 100644 --- a/components/esp_timer/src/ets_timer_legacy.c +++ b/components/esp_timer/src/ets_timer_legacy.c @@ -34,6 +34,8 @@ #include "esp32c2/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/esp_timer/src/system_time.c b/components/esp_timer/src/system_time.c index 253ea56c76..0cd4e118f7 100644 --- a/components/esp_timer/src/system_time.c +++ b/components/esp_timer/src/system_time.c @@ -29,6 +29,8 @@ #include "esp32c2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C5 +#include "esp32c5/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32P4