feat(esp32c5): add system related supports

This commit is contained in:
laokaiyao 2024-01-02 11:16:55 +08:00
parent 81aec7b929
commit a48f4760d2
50 changed files with 3481 additions and 27 deletions

View File

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#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

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#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;
}

View File

@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#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
}

View File

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#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;
}

View File

@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/lock.h>
#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);
}

View File

@ -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;
}

View File

@ -0,0 +1,207 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#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, &param);
pmu_hp_system_init(ctx, mode, &param);
}
}
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, &param);
pmu_lp_system_init(ctx, mode, &param);
}
}
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());
}

View File

@ -0,0 +1,447 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#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];
}

View File

@ -0,0 +1,481 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#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

View File

@ -0,0 +1,441 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#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")));

View File

@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#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);
}

View File

@ -0,0 +1,284 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#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);
}
}
}

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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);

View File

@ -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();

View File

@ -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})

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,301 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/time.h>
#include <sys/param.h>
#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
}

View File

@ -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);
}

View File

@ -0,0 +1,122 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#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) {
;
}
}

View File

@ -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"

View File

@ -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

View File

@ -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