From 23e37393a700dbc5bc6cb5562d2ffb6f785c4fd9 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 12 Jul 2022 19:46:23 +0800 Subject: [PATCH] esp32c6: add esp_hw_support --- components/esp_hw_support/CMakeLists.txt | 7 + components/esp_hw_support/Kconfig | 4 +- components/esp_hw_support/cpu.c | 103 +++++++- components/esp_hw_support/esp_clk.c | 5 +- .../esp_hw_support/include/esp_chip_info.h | 1 + components/esp_hw_support/include/esp_mac.h | 2 + .../include/soc/esp32c6/esp_crypto_lock.h | 68 ++++++ .../include/soc/esp32c6/esp_ds.h | 220 +++++++++++++++++ .../include/soc/esp32c6/esp_hmac.h | 92 +++++++ .../esp_hw_support/include/soc/esp32c6/rtc.h | 32 +++ .../include/soc/esp32c6/soc_memprot_types.h | 175 ++++++++++++++ components/esp_hw_support/linker.lf | 7 +- .../port/esp32c6/CMakeLists.txt | 25 ++ .../port/esp32c6/Kconfig.hw_support | 15 ++ .../esp_hw_support/port/esp32c6/Kconfig.mac | 43 ++++ .../esp_hw_support/port/esp32c6/Kconfig.rtc | 40 ++++ .../esp_hw_support/port/esp32c6/chip_info.c | 18 ++ .../port/esp32c6/esp_crypto_lock.c | 75 ++++++ .../esp_hw_support/port/esp32c6/esp_ds.c | 224 +++++++++++++++++ .../esp_hw_support/port/esp32c6/esp_hmac.c | 182 ++++++++++++++ .../esp_hw_support/port/esp32c6/esp_memprot.c | 9 + .../esp_hw_support/port/esp32c6/rtc_clk.c | 226 ++++++++++++++++++ .../port/esp32c6/rtc_clk_init.c | 84 +++++++ .../esp_hw_support/port/esp32c6/rtc_init.c | 7 + .../esp_hw_support/port/esp32c6/rtc_pm.c | 7 + .../esp_hw_support/port/esp32c6/rtc_sleep.c | 7 + .../esp_hw_support/port/esp32c6/rtc_time.c | 103 ++++++++ .../esp_hw_support/port/esp32c6/systimer.c | 22 ++ components/esp_hw_support/rtc_module.c | 24 ++ components/esp_hw_support/sleep_modes.c | 15 ++ 30 files changed, 1836 insertions(+), 6 deletions(-) create mode 100644 components/esp_hw_support/include/soc/esp32c6/esp_crypto_lock.h create mode 100644 components/esp_hw_support/include/soc/esp32c6/esp_ds.h create mode 100644 components/esp_hw_support/include/soc/esp32c6/esp_hmac.h create mode 100644 components/esp_hw_support/include/soc/esp32c6/rtc.h create mode 100644 components/esp_hw_support/include/soc/esp32c6/soc_memprot_types.h create mode 100644 components/esp_hw_support/port/esp32c6/Kconfig.hw_support create mode 100644 components/esp_hw_support/port/esp32c6/Kconfig.rtc create mode 100644 components/esp_hw_support/port/esp32c6/chip_info.c create mode 100644 components/esp_hw_support/port/esp32c6/esp_crypto_lock.c create mode 100644 components/esp_hw_support/port/esp32c6/esp_ds.c create mode 100644 components/esp_hw_support/port/esp32c6/esp_hmac.c create mode 100644 components/esp_hw_support/port/esp32c6/esp_memprot.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_clk.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_clk_init.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_init.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_pm.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_sleep.c create mode 100644 components/esp_hw_support/port/esp32c6/rtc_time.c create mode 100644 components/esp_hw_support/port/esp32c6/systimer.c diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 71e063471c..d002f21150 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -45,6 +45,13 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "port/${target}/systimer.c") endif() + # ESP32C6-TODO + if(CONFIG_IDF_TARGET_ESP32C6) + list(REMOVE_ITEM srcs + "adc_share_hw_ctrl.c" # TODO: IDF-5312 + ) + endif() + else() # Requires "_esp_error_check_failed()" function list(APPEND priv_requires "esp_system") diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 65d4719f02..34db231dec 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -40,7 +40,7 @@ menu "Hardware Settings" config ESP_SLEEP_GPIO_RESET_WORKAROUND bool "light sleep GPIO reset workaround" - default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 + default y if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 # TODO: IDF-5641 (esp32c6) select PM_SLP_DISABLE_GPIO if FREERTOS_USE_TICKLESS_IDLE help esp32c2, esp32c3 and esp32s3 will reset at wake-up if GPIO is received a small electrostatic @@ -165,6 +165,7 @@ menu "Hardware Settings" config MMU_PAGE_MODE string + default "8KB" if MMU_PAGE_SIZE_8KB default "16KB" if MMU_PAGE_SIZE_16KB default "32KB" if MMU_PAGE_SIZE_32KB default "64KB" if MMU_PAGE_SIZE_64KB @@ -176,6 +177,7 @@ menu "Hardware Settings" # use of small flash sizes (reducing the wasted space due to alignment), we # need to use the smallest possible MMU page size for the given flash size. hex + default 0x2000 if MMU_PAGE_SIZE_8KB default 0x4000 if MMU_PAGE_SIZE_16KB default 0x8000 if MMU_PAGE_SIZE_32KB default 0x10000 if MMU_PAGE_SIZE_64KB diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index fb67935002..929aa32ff5 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -9,7 +9,17 @@ #include #include "soc/soc.h" #include "soc/soc_caps.h" + +// TODO: IDF-5645 +#if CONFIG_IDF_TARGET_ESP32C6 +#include "soc/lp_aon_reg.h" +#include "soc/pcr_reg.h" +#define SYSTEM_CPU_PER_CONF_REG PCR_CPU_WAITI_CONF_REG +#define SYSTEM_CPU_WAIT_MODE_FORCE_ON PCR_CPU_WAIT_MODE_FORCE_ON +#else #include "soc/rtc_cntl_reg.h" +#endif + #include "hal/soc_hal.h" #include "hal/mpu_hal.h" #include "esp_bit_defs.h" @@ -81,6 +91,9 @@ void esp_cpu_unstall(int core_id) void esp_cpu_reset(int core_id) { +#if CONFIG_IDF_TARGET_ESP32C6 // 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); #if SOC_CPU_CORES_NUM > 1 /* @@ -93,6 +106,7 @@ void esp_cpu_reset(int core_id) int rtc_cntl_rst_m = RTC_CNTL_SW_PROCPU_RST_M; #endif // SOC_CPU_CORES_NUM > 1 SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_rst_m); +#endif } void esp_cpu_wait_for_intr(void) @@ -100,6 +114,7 @@ void esp_cpu_wait_for_intr(void) #if __XTENSA__ xt_utils_wait_for_intr(); #else + // TODO: IDF-5645 (better to implement with ll) C6 register names converted in the #include section at the top if (esp_cpu_dbgr_is_attached() && DPORT_REG_GET_BIT(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPU_WAIT_MODE_FORCE_ON) == 0) { /* when SYSTEM_CPU_WAIT_MODE_FORCE_ON is disabled in WFI mode SBA access to memory does not work for debugger, so do not enter that mode when debugger is connected */ @@ -125,7 +140,13 @@ static bool is_intr_num_resv(int intr_num) { // Workaround to reserve interrupt number 1 for Wi-Fi, 5,8 for Bluetooth, 6 for "permanently disabled interrupt" // [TODO: IDF-2465] - const uint32_t reserved = BIT(1) | BIT(5) | BIT(6) | BIT(8); + uint32_t reserved = BIT(1) | BIT(5) | BIT(6) | BIT(8); + + // int_num 0,3,4,7 are inavaliable for PULP cpu +#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5728 replace with a better macro name + reserved |= BIT(0) | BIT(3) | BIT(4) | BIT(7); +#endif + if (reserved & BIT(intr_num)) { return true; } @@ -501,6 +522,86 @@ void esp_cpu_configure_region_protection(void) PMP_ENTRY_CFG_SET(14, NONE); PMP_ENTRY_CFG_SET(15, PMP_TOR | NONE); } +#elif CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5642 +void esp_cpu_configure_region_protection(void) +{ + /* Notes on implementation: + * + * 1) Note: ESP32-C6 CPU doesn't support overlapping PMP regions + * + * 2) Therefore, we use TOR (top of range) entries to map the whole address + * space, bottom to top. + * + * 3) There are not enough entries to describe all the memory regions 100% accurately. + * + * 4) This means some gaps (invalid memory) are accessible. Priority for extending regions + * to cover gaps is to extend read-only or read-execute regions or read-only regions only + * (executing unmapped addresses should always fault with invalid instruction, read-only means + * stores will correctly fault even if reads may return some invalid value.) + * + * 5) Entries are grouped in order with some static asserts to try and verify everything is + * correct. + */ + const unsigned NONE = PMP_L | PMP_TOR; + const unsigned RW = PMP_L | PMP_TOR | PMP_R | PMP_W; + const unsigned RX = PMP_L | PMP_TOR | PMP_R | PMP_X; + const unsigned RWX = PMP_L | PMP_TOR | PMP_R | PMP_W | PMP_X; + + // 1. Gap at bottom of address space + PMP_ENTRY_SET(0, SOC_DEBUG_LOW, NONE); + + // 2. Debug region + PMP_ENTRY_SET(1, SOC_DEBUG_HIGH, RWX); + _Static_assert(SOC_DEBUG_LOW < SOC_DEBUG_HIGH, "Invalid CPU debug region"); + + // 3. Gap between debug region & IROM + PMP_ENTRY_SET(2, SOC_IROM_MASK_LOW, NONE); + _Static_assert(SOC_DEBUG_HIGH < SOC_IROM_MASK_LOW, "Invalid PMP entry order"); + + // 4. ROM + PMP_ENTRY_SET(3, SOC_DROM_MASK_HIGH, RX); + _Static_assert(SOC_IROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid ROM region"); + + // 5. Gap between ROM & RAM + PMP_ENTRY_SET(4, SOC_IRAM_LOW, NONE); + _Static_assert(SOC_DROM_MASK_HIGH < SOC_IRAM_LOW, "Invalid PMP entry order"); + + // 6. RAM + PMP_ENTRY_SET(5, SOC_IRAM_HIGH, RWX); + _Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region"); + + // 7. Gap between DRAM and I_Cache + PMP_ENTRY_SET(6, SOC_IROM_LOW, NONE); + _Static_assert(SOC_IRAM_HIGH < SOC_IROM_LOW, "Invalid PMP entry order"); + + // 8. I_Cache (flash) + PMP_ENTRY_SET(7, SOC_IROM_HIGH, RWX); + _Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I_Cache region"); + + // 9. D_Cache (flash) + PMP_ENTRY_SET(8, SOC_DROM_HIGH, RW); + _Static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid D_Cache region"); + + // 10. Gap between D_Cache & LP_RAM + PMP_ENTRY_SET(9, SOC_RTC_IRAM_LOW, NONE); + _Static_assert(SOC_DROM_HIGH < SOC_RTC_IRAM_LOW, "Invalid PMP entry order"); + + // 16. LP memory + PMP_ENTRY_SET(10, SOC_RTC_IRAM_HIGH, RWX); + _Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region"); + + // 17. Gap between LP memory & peripheral addresses + PMP_ENTRY_SET(11, SOC_PERIPHERAL_LOW, NONE); + _Static_assert(SOC_RTC_IRAM_HIGH < SOC_PERIPHERAL_LOW, "Invalid PMP entry order"); + + // 18. Peripheral addresses + PMP_ENTRY_SET(12, SOC_PERIPHERAL_HIGH, RW); + _Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region"); + + // 19. End of address space + PMP_ENTRY_SET(13, UINT32_MAX, NONE); // all but last 4 bytes + PMP_ENTRY_SET(14, UINT32_MAX, PMP_L | PMP_NA4); // last 4 bytes +} #endif /* ---------------------------------------------------- Debugging ------------------------------------------------------ diff --git a/components/esp_hw_support/esp_clk.c b/components/esp_hw_support/esp_clk.c index 2421196646..f15b269721 100644 --- a/components/esp_hw_support/esp_clk.c +++ b/components/esp_hw_support/esp_clk.c @@ -35,6 +35,9 @@ #elif CONFIG_IDF_TARGET_ESP32C2 #include "esp32c2/rom/rtc.h" #include "esp32c2/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#include "esp32c6/rtc.h" #endif #define MHZ (1000000) @@ -76,7 +79,7 @@ int IRAM_ATTR esp_clk_xtal_freq(void) return rtc_clk_xtal_freq_get() * MHZ; } -#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESPS3 void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) { /* Update scale factors used by esp_rom_delay_us */ diff --git a/components/esp_hw_support/include/esp_chip_info.h b/components/esp_hw_support/include/esp_chip_info.h index 8f92e226b1..227d55a0fa 100644 --- a/components/esp_hw_support/include/esp_chip_info.h +++ b/components/esp_hw_support/include/esp_chip_info.h @@ -26,6 +26,7 @@ typedef enum { CHIP_ESP32C3 = 5, //!< ESP32-C3 CHIP_ESP32H2 = 6, //!< ESP32-H2 CHIP_ESP32C2 = 12, //!< ESP32-C2 + CHIP_ESP32C6 = 13, //!< ESP32-C6 } esp_chip_model_t; /* Chip feature flags, used in esp_chip_info_t */ diff --git a/components/esp_hw_support/include/esp_mac.h b/components/esp_hw_support/include/esp_mac.h index 6a7224a317..e4eb06cd09 100644 --- a/components/esp_hw_support/include/esp_mac.h +++ b/components/esp_hw_support/include/esp_mac.h @@ -41,6 +41,8 @@ typedef enum { #define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32H2_UNIVERSAL_MAC_ADDRESSES #elif CONFIG_IDF_TARGET_ESP32C2 #define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32C2_UNIVERSAL_MAC_ADDRESSES +#elif CONFIG_IDF_TARGET_ESP32C6 +#define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32C6_UNIVERSAL_MAC_ADDRESSES #endif /** @endcond */ diff --git a/components/esp_hw_support/include/soc/esp32c6/esp_crypto_lock.h b/components/esp_hw_support/include/soc/esp32c6/esp_crypto_lock.h new file mode 100644 index 0000000000..67a08741b5 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c6/esp_crypto_lock.h @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 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); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/soc/esp32c6/esp_ds.h b/components/esp_hw_support/include/soc/esp32c6/esp_ds.h new file mode 100644 index 0000000000..6393edda6b --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c6/esp_ds.h @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_hmac.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP32C6_ERR_HW_CRYPTO_DS_HMAC_FAIL ESP_ERR_HW_CRYPTO_BASE + 0x1 /*!< HMAC peripheral problem */ +#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_KEY ESP_ERR_HW_CRYPTO_BASE + 0x2 /*!< given HMAC key isn't correct, + HMAC peripheral problem */ +#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_DIGEST ESP_ERR_HW_CRYPTO_BASE + 0x4 /*!< message digest check failed, + result is invalid */ +#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_PADDING ESP_ERR_HW_CRYPTO_BASE + 0x5 /*!< padding check failed, but result + is produced anyway and can be read*/ + +#define ESP_DS_IV_BIT_LEN 128 +#define ESP_DS_IV_LEN (ESP_DS_IV_BIT_LEN / 8) +#define ESP_DS_SIGNATURE_MAX_BIT_LEN 3072 +#define ESP_DS_SIGNATURE_MD_BIT_LEN 256 +#define ESP_DS_SIGNATURE_M_PRIME_BIT_LEN 32 +#define ESP_DS_SIGNATURE_L_BIT_LEN 32 +#define ESP_DS_SIGNATURE_PADDING_BIT_LEN 64 + +/* Length of parameter 'C' stored in flash, in bytes + - Operands Y, M and r_bar; each 3072 bits + - Operand MD (message digest); 256 bits + - Operands M' and L; each 32 bits + - Operand beta (padding value; 64 bits +*/ +#define ESP_DS_C_LEN (((ESP_DS_SIGNATURE_MAX_BIT_LEN * 3 \ + + ESP_DS_SIGNATURE_MD_BIT_LEN \ + + ESP_DS_SIGNATURE_M_PRIME_BIT_LEN \ + + ESP_DS_SIGNATURE_L_BIT_LEN \ + + ESP_DS_SIGNATURE_PADDING_BIT_LEN) / 8)) + +typedef struct esp_ds_context esp_ds_context_t; + +typedef enum { + ESP_DS_RSA_1024 = (1024 / 32) - 1, + ESP_DS_RSA_2048 = (2048 / 32) - 1, + ESP_DS_RSA_3072 = (3072 / 32) - 1 +} esp_digital_signature_length_t; + +/** + * Encrypted private key data. Recommended to store in flash in this format. + * + * @note This struct has to match to one from the ROM code! This documentation is mostly taken from there. + */ +typedef struct esp_digital_signature_data { + /** + * RSA LENGTH register parameters + * (number of words in RSA key & operands, minus one). + * + * Max value 127 (for RSA 3072). + * + * This value must match the length field encrypted and stored in 'c', + * or invalid results will be returned. (The DS peripheral will + * always use the value in 'c', not this value, so an attacker can't + * alter the DS peripheral results this way, it will just truncate or + * extend the message and the resulting signature in software.) + * + * @note In IDF, the enum type length is the same as of type unsigned, so they can be used interchangably. + * See the ROM code for the original declaration of struct \c ets_ds_data_t. + */ + esp_digital_signature_length_t rsa_length; + + /** + * IV value used to encrypt 'c' + */ + uint32_t iv[ESP_DS_IV_BIT_LEN / 32]; + + /** + * Encrypted Digital Signature parameters. Result of AES-CBC encryption + * of plaintext values. Includes an encrypted message digest. + */ + uint8_t c[ESP_DS_C_LEN]; +} esp_ds_data_t; + +/** + * Plaintext parameters used by Digital Signature. + * + * This is only used for encrypting the RSA parameters by calling esp_ds_encrypt_params(). + * Afterwards, the result can be stored in flash or in other persistent memory. + * The encryption is a prerequisite step before any signature operation can be done. + */ +typedef struct { + uint32_t Y[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA exponent + uint32_t M[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA modulus + uint32_t Rb[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA r inverse operand + uint32_t M_prime; //!< RSA M prime operand + uint32_t length; //!< RSA length in words (32 bit) +} esp_ds_p_data_t; + +/** + * @brief Sign the message with a hardware key from specific key slot. + * The function calculates a plain RSA signature with help of the DS peripheral. + * The RSA encryption operation is as follows: + * Z = XY mod M where, + * Z is the signature, X is the input message, + * Y and M are the RSA private key parameters. + * + * This function is a wrapper around \c esp_ds_finish_sign() and \c esp_ds_start_sign(), so do not use them + * in parallel. + * It blocks until the signing is finished and then returns the signature. + * + * @note This function locks the HMAC, SHA, AES and RSA components during its entire execution time. + * + * @param message the message to be signed; its length should be (data->rsa_length + 1)*4 bytes + * @param data the encrypted signing key data (AES encrypted RSA key + IV) + * @param key_id the HMAC key ID determining the HMAC key of the HMAC which will be used to decrypt the + * signing key data + * @param signature the destination of the signature, should be (data->rsa_length + 1)*4 bytes long + * + * @return + * - ESP_OK if successful, the signature was written to the parameter \c signature. + * - ESP_ERR_INVALID_ARG if one of the parameters is NULL or data->rsa_length is too long or 0 + * - ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL if there was an HMAC failure during retrieval of the decryption key + * - ESP_ERR_NO_MEM if there hasn't been enough memory to allocate the context object + * - ESP_ERR_HW_CRYPTO_DS_INVALID_KEY if there's a problem with passing the HMAC key to the DS component + * - ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST if the message digest didn't match; the signature is invalid. + * - ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING if the message padding is incorrect, the signature can be read though + * since the message digest matches. + */ +esp_err_t esp_ds_sign(const void *message, + const esp_ds_data_t *data, + hmac_key_id_t key_id, + void *signature); + +/** + * @brief Start the signing process. + * + * This function yields a context object which needs to be passed to \c esp_ds_finish_sign() to finish the signing + * process. + * The function calculates a plain RSA signature with help of the DS peripheral. + * The RSA encryption operation is as follows: + * Z = XY mod M where, + * Z is the signature, X is the input message, + * Y and M are the RSA private key parameters. + * + * @note This function locks the HMAC, SHA, AES and RSA components, so the user has to ensure to call + * \c esp_ds_finish_sign() in a timely manner. + * + * @param message the message to be signed; its length should be (data->rsa_length + 1)*4 bytes + * @param data the encrypted signing key data (AES encrypted RSA key + IV) + * @param key_id the HMAC key ID determining the HMAC key of the HMAC which will be used to decrypt the + * signing key data + * @param esp_ds_ctx the context object which is needed for finishing the signing process later + * + * @return + * - ESP_OK if successful, the ds operation was started now and has to be finished with \c esp_ds_finish_sign() + * - ESP_ERR_INVALID_ARG if one of the parameters is NULL or data->rsa_length is too long or 0 + * - ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL if there was an HMAC failure during retrieval of the decryption key + * - ESP_ERR_NO_MEM if there hasn't been enough memory to allocate the context object + * - ESP_ERR_HW_CRYPTO_DS_INVALID_KEY if there's a problem with passing the HMAC key to the DS component + */ +esp_err_t esp_ds_start_sign(const void *message, + const esp_ds_data_t *data, + hmac_key_id_t key_id, + esp_ds_context_t **esp_ds_ctx); + +/** + * Return true if the DS peripheral is busy, otherwise false. + * + * @note Only valid if \c esp_ds_start_sign() was called before. + */ +bool esp_ds_is_busy(void); + +/** + * @brief Finish the signing process. + * + * @param signature the destination of the signature, should be (data->rsa_length + 1)*4 bytes long + * @param esp_ds_ctx the context object retreived by \c esp_ds_start_sign() + * + * @return + * - ESP_OK if successful, the ds operation has been finished and the result is written to signature. + * - ESP_ERR_INVALID_ARG if one of the parameters is NULL + * - ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST if the message digest didn't match; the signature is invalid. + * This means that the encrypted RSA key parameters are invalid, indicating that they may have been tampered + * with or indicating a flash error, etc. + * - ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING if the message padding is incorrect, the signature can be read though + * since the message digest matches (see TRM for more details). + */ +esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx); + +/** + * @brief Encrypt the private key parameters. + * + * The encryption is a prerequisite step before any signature operation can be done. + * It is not strictly necessary to use this encryption function, the encryption could also happen on an external + * device. + * + * @param data Output buffer to store encrypted data, suitable for later use generating signatures. + * The allocated memory must be in internal memory and word aligned since it's filled by DMA. Both is asserted + * at run time. + * @param iv Pointer to 16 byte IV buffer, will be copied into 'data'. Should be randomly generated bytes each time. + * @param p_data Pointer to input plaintext key data. The expectation is this data will be deleted after this process + * is done and 'data' is stored. + * @param key Pointer to 32 bytes of key data. Type determined by key_type parameter. The expectation is the + * corresponding HMAC key will be stored to efuse and then permanently erased. + * + * @return + * - ESP_OK if successful, the ds operation has been finished and the result is written to signature. + * - ESP_ERR_INVALID_ARG if one of the parameters is NULL or p_data->rsa_length is too long + */ +esp_err_t esp_ds_encrypt_params(esp_ds_data_t *data, + const void *iv, + const esp_ds_p_data_t *p_data, + const void *key); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/soc/esp32c6/esp_hmac.h b/components/esp_hw_support/include/soc/esp32c6/esp_hmac.h new file mode 100644 index 0000000000..635834d594 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c6/esp_hmac.h @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_HMAC_H_ +#define _ESP_HMAC_H_ + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The possible efuse keys for the HMAC peripheral + */ +typedef enum { + HMAC_KEY0 = 0, + HMAC_KEY1, + HMAC_KEY2, + HMAC_KEY3, + HMAC_KEY4, + HMAC_KEY5, + HMAC_KEY_MAX +} hmac_key_id_t; + +/** + * @brief + * Calculate the HMAC of a given message. + * + * Calculate the HMAC \c hmac of a given message \c message with length \c message_len. + * SHA256 is used for the calculation (fixed on ESP32S2). + * + * @note Uses the HMAC peripheral in "upstream" mode. + * + * @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calcuation. + * The corresponding purpose field of the key block in the efuse must be set to the HMAC upstream purpose value. + * @param message the message for which to calculate the HMAC + * @param message_len message length + * return ESP_ERR_INVALID_STATE if unsuccessful + * @param [out] hmac the hmac result; the buffer behind the provided pointer must be a writeable buffer of 32 bytes + * + * @return + * * ESP_OK, if the calculation was successful, + * * ESP_ERR_INVALID_ARG if message or hmac is a nullptr or if key_id out of range + * * ESP_FAIL, if the hmac calculation failed + */ +esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, + const void *message, + size_t message_len, + uint8_t *hmac); + +/** + * @brief Use HMAC peripheral in Downstream mode to re-enable the JTAG, if it is not permanently disabled by HW. + * In downstream mode, HMAC calculations performed by peripheral are used internally and not provided back to user. + * + * @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calculation. + * The corresponding purpose field of the key block in the efuse must be set to HMAC downstream purpose. + * + * @param token Pre calculated HMAC value of the 32-byte 0x00 using SHA-256 and the known private HMAC key. The key is already + * programmed to a eFuse key block. The key block number is provided as the first parameter to this function. + * + * @return + * * ESP_OK, if the key_purpose of the key_id matches to HMAC downstread mode, + * The API returns success even if calculated HMAC does not match with the provided token. + * However, The JTAG will be re-enabled only if the calculated HMAC value matches with provided token, + * otherwise JTAG will remain disabled. + * * ESP_FAIL, if the key_purpose of the key_id is not set to HMAC downstream purpose + * or JTAG is permanently disabled by EFUSE_HARD_DIS_JTAG eFuse parameter. + * * ESP_ERR_INVALID_ARG, invalid input arguments + * + * @note Return value of the API does not indicate the JTAG status. + */ +esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token); + +/** + * @brief Disable the JTAG which might be enabled using the HMAC downstream mode. This function just clears the result generated + * by calling esp_hmac_jtag_enable() API. + * + * @return + * * ESP_OK return ESP_OK after writing the HMAC_SET_INVALIDATE_JTAG_REG with value 1. + */ +esp_err_t esp_hmac_jtag_disable(void); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_HMAC_H_ diff --git a/components/esp_hw_support/include/soc/esp32c6/rtc.h b/components/esp_hw_support/include/soc/esp32c6/rtc.h new file mode 100644 index 0000000000..dec61ee9cf --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c6/rtc.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file esp32c6/rtc.h + * + * This file contains declarations of rtc related functions. + */ + +/** + * @brief Get current value of RTC counter in microseconds + * + * Note: this function may take up to 1 RTC_SLOW_CLK cycle to execute + * + * @return current value of RTC counter in microseconds + */ +uint64_t esp_rtc_get_time_us(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/soc/esp32c6/soc_memprot_types.h b/components/esp_hw_support/include/soc/esp32c6/soc_memprot_types.h new file mode 100644 index 0000000000..c45dc31dc9 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32c6/soc_memprot_types.h @@ -0,0 +1,175 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +////////////////////////////////////////////////////////// +// ESP32-C6 PMS memory protection types +// + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Memory types recognized by PMS + */ +typedef enum { + MEMPROT_TYPE_NONE = 0x00000000, + MEMPROT_TYPE_IRAM0_SRAM = 0x00000001, + MEMPROT_TYPE_DRAM0_SRAM = 0x00000002, + MEMPROT_TYPE_IRAM0_RTCFAST = 0x00000004, + MEMPROT_TYPE_ALL = 0x7FFFFFFF, + MEMPROT_TYPE_INVALID = 0x80000000, + MEMPROT_TYPE_IRAM0_ANY = MEMPROT_TYPE_IRAM0_SRAM | MEMPROT_TYPE_IRAM0_RTCFAST +} esp_mprot_mem_t; + +/** + * @brief Splitting address (line) type + */ +typedef enum { + MEMPROT_SPLIT_ADDR_NONE = 0x00000000, + MEMPROT_SPLIT_ADDR_IRAM0_DRAM0 = 0x00000001, + MEMPROT_SPLIT_ADDR_IRAM0_LINE_0 = 0x00000002, + MEMPROT_SPLIT_ADDR_IRAM0_LINE_1 = 0x00000004, + MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_0 = 0x00000008, + MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_1 = 0x00000010, + MEMPROT_SPLIT_ADDR_ALL = 0x7FFFFFFF, + MEMPROT_SPLIT_ADDR_INVALID = 0x80000000, + MEMPROT_SPLIT_ADDR_MAIN = MEMPROT_SPLIT_ADDR_IRAM0_DRAM0 +} esp_mprot_split_addr_t; + +/** + * @brief PMS area type (memory space between adjacent splitting addresses or above/below the main splt.address) + */ +typedef enum { + MEMPROT_PMS_AREA_NONE = 0x00000000, + MEMPROT_PMS_AREA_IRAM0_0 = 0x00000001, + MEMPROT_PMS_AREA_IRAM0_1 = 0x00000002, + MEMPROT_PMS_AREA_IRAM0_2 = 0x00000004, + MEMPROT_PMS_AREA_IRAM0_3 = 0x00000008, + MEMPROT_PMS_AREA_DRAM0_0 = 0x00000010, + MEMPROT_PMS_AREA_DRAM0_1 = 0x00000020, + MEMPROT_PMS_AREA_DRAM0_2 = 0x00000040, + MEMPROT_PMS_AREA_DRAM0_3 = 0x00000080, + MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO = 0x00000100, + MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI = 0x00000200, + MEMPROT_PMS_AREA_ALL = 0x7FFFFFFF, + MEMPROT_PMS_AREA_INVALID = 0x80000000 +} esp_mprot_pms_area_t; + +/** +* @brief Memory protection configuration +*/ +typedef struct { + bool invoke_panic_handler; /*!< Register PMS violation interrupt for panic-handling */ + bool lock_feature; /*!< Lock all PMS settings */ + void *split_addr; /*!< Main I/D splitting address */ + uint32_t mem_type_mask; /*!< Memory types required to protect. See esp_mprot_mem_t enum */ +} esp_memp_config_t; + +#define ESP_MEMPROT_DEFAULT_CONFIG() { \ + .invoke_panic_handler = true, \ + .lock_feature = true, \ + .split_addr = NULL, \ + .mem_type_mask = MEMPROT_TYPE_ALL \ +} + +/** + * @brief Converts Memory protection type to string + * + * @param mem_type Memory protection type + */ +static inline const char *esp_mprot_mem_type_to_str(const esp_mprot_mem_t mem_type) +{ + switch (mem_type) { + case MEMPROT_TYPE_NONE: + return "NONE"; + case MEMPROT_TYPE_IRAM0_SRAM: + return "IRAM0_SRAM"; + case MEMPROT_TYPE_DRAM0_SRAM: + return "DRAM0_SRAM"; + case MEMPROT_TYPE_IRAM0_RTCFAST: + return "IRAM0_RTCFAST"; + case MEMPROT_TYPE_IRAM0_ANY: + return "IRAM0_ANY"; + case MEMPROT_TYPE_ALL: + return "ALL"; + default: + return "INVALID"; + } +} + +/** + * @brief Converts Splitting address type to string + * + * @param line_type Split line type + */ +static inline const char *esp_mprot_split_addr_to_str(const esp_mprot_split_addr_t line_type) +{ + switch (line_type) { + case MEMPROT_SPLIT_ADDR_NONE: + return "SPLIT_ADDR_NONE"; + case MEMPROT_SPLIT_ADDR_IRAM0_DRAM0: + return "SPLIT_ADDR_IRAM0_DRAM0"; + case MEMPROT_SPLIT_ADDR_IRAM0_LINE_0: + return "SPLIT_ADDR_IRAM0_LINE_0"; + case MEMPROT_SPLIT_ADDR_IRAM0_LINE_1: + return "SPLIT_ADDR_IRAM0_LINE_1"; + case MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_0: + return "SPLIT_ADDR_DRAM0_DMA_LINE_0"; + case MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_1: + return "SPLIT_ADDR_DRAM0_DMA_LINE_1"; + case MEMPROT_SPLIT_ADDR_ALL: + return "SPLIT_ADDR_ALL"; + default: + return "SPLIT_ADDR_INVALID"; + } +} + +/** + * @brief Converts PMS Area type to string + * + * @param area_type PMS Area type + */ +static inline const char *esp_mprot_pms_area_to_str(const esp_mprot_pms_area_t area_type) +{ + switch (area_type) { + case MEMPROT_PMS_AREA_NONE: + return "PMS_AREA_NONE"; + case MEMPROT_PMS_AREA_IRAM0_0: + return "PMS_AREA_IRAM0_0"; + case MEMPROT_PMS_AREA_IRAM0_1: + return "PMS_AREA_IRAM0_1"; + case MEMPROT_PMS_AREA_IRAM0_2: + return "PMS_AREA_IRAM0_2"; + case MEMPROT_PMS_AREA_IRAM0_3: + return "PMS_AREA_IRAM0_3"; + case MEMPROT_PMS_AREA_DRAM0_0: + return "PMS_AREA_DRAM0_0"; + case MEMPROT_PMS_AREA_DRAM0_1: + return "PMS_AREA_DRAM0_1"; + case MEMPROT_PMS_AREA_DRAM0_2: + return "PMS_AREA_DRAM0_2"; + case MEMPROT_PMS_AREA_DRAM0_3: + return "PMS_AREA_DRAM0_3"; + case MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO: + return "PMS_AREA_IRAM0_RTCFAST_LO"; + case MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI: + return "PMS_AREA_IRAM0_RTCFAST_HI"; + case MEMPROT_PMS_AREA_ALL: + return "PMS_AREA_ALL"; + default: + return "PMS_AREA_INVALID"; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index c63173bf35..005ecf9198 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -13,9 +13,10 @@ entries: cpu: esp_cpu_compare_and_set (noflash) esp_memory_utils (noflash) rtc_clk (noflash) - rtc_init:rtc_vddsdio_set_config (noflash) - rtc_pm (noflash_text) - rtc_sleep (noflash_text) + if IDF_TARGET_ESP32C6 = n: # TODO: IDF-5645 + rtc_init:rtc_vddsdio_set_config (noflash) + rtc_pm (noflash_text) + rtc_sleep (noflash_text) rtc_time (noflash_text) if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y: rtc_wdt (noflash_text) diff --git a/components/esp_hw_support/port/esp32c6/CMakeLists.txt b/components/esp_hw_support/port/esp32c6/CMakeLists.txt index e69de29bb2..95caea4b5e 100644 --- a/components/esp_hw_support/port/esp32c6/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c6/CMakeLists.txt @@ -0,0 +1,25 @@ +set(srcs "rtc_clk_init.c" + "rtc_clk.c" + # "rtc_init.c" // TODO: IDF-5645 + # "rtc_pm.c" // TODO: IDF-5645 + # "rtc_sleep.c" // TODO: IDF-5645 + "rtc_time.c" + "chip_info.c" + ) + +if(NOT BOOTLOADER_BUILD) + # list(APPEND srcs "esp_hmac.c" // TODO: IDF-5355 + # "esp_crypto_lock.c" + # "esp_ds.c") // TODO: IDF-5360 + + if(CONFIG_ESP_SYSTEM_MEMPROT_FEATURE) + list(APPEND srcs "esp_memprot.c" "../esp_memprot_conv.c") + endif() + +endif() + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") + +target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") +target_include_directories(${COMPONENT_LIB} PUBLIC . private_include) +target_include_directories(${COMPONENT_LIB} PRIVATE ../hal) diff --git a/components/esp_hw_support/port/esp32c6/Kconfig.hw_support b/components/esp_hw_support/port/esp32c6/Kconfig.hw_support new file mode 100644 index 0000000000..a47942369f --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/Kconfig.hw_support @@ -0,0 +1,15 @@ +choice ESP32C6_REV_MIN + prompt "Minimum Supported ESP32-C6 Revision" + default ESP32C6_REV_MIN_0 + help + Minimum revision that ESP-IDF would support. + + Only supporting higher chip revisions can reduce binary size. + + config ESP32C6_REV_MIN_0 + bool "Rev 0" +endchoice + +config ESP32C6_REV_MIN + int + default 0 if ESP32C6_REV_MIN_0 diff --git a/components/esp_hw_support/port/esp32c6/Kconfig.mac b/components/esp_hw_support/port/esp32c6/Kconfig.mac index e69de29bb2..2556598e5f 100644 --- a/components/esp_hw_support/port/esp32c6/Kconfig.mac +++ b/components/esp_hw_support/port/esp32c6/Kconfig.mac @@ -0,0 +1,43 @@ +choice ESP32C6_UNIVERSAL_MAC_ADDRESSES + bool "Number of universally administered (by IEEE) MAC address" + default ESP32C6_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-C6 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 ESP32C6_UNIVERSAL_MAC_ADDRESSES_TWO + bool "Two" + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_BT + + config ESP32C6_UNIVERSAL_MAC_ADDRESSES_FOUR + bool "Four" + 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 ESP32C6_UNIVERSAL_MAC_ADDRESSES + int + default 2 if ESP32C6_UNIVERSAL_MAC_ADDRESSES_TWO + default 4 if ESP32C6_UNIVERSAL_MAC_ADDRESSES_FOUR diff --git a/components/esp_hw_support/port/esp32c6/Kconfig.rtc b/components/esp_hw_support/port/esp32c6/Kconfig.rtc new file mode 100644 index 0000000000..4dcb829249 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/Kconfig.rtc @@ -0,0 +1,40 @@ +choice RTC_CLK_SRC + # TODO: IDF-5346 + prompt "RTC clock source" + default RTC_CLK_SRC_INT_RC + help + Choose which clock is used as RTC clock source. + + config RTC_CLK_SRC_INT_RC + bool "Internal 136kHz RC oscillator" + 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_8MD256 + bool "Internal 17.5MHz oscillator, divided by 256" +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_8MD256 + 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_8MD256 + 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: + + - 150000 Hz if internal RC oscillator is used as clock source. For this use value 1024. + - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more. + In case more value will help improve the definition of the launch of the crystal. + If the crystal could not start, it will be switched to internal RC. diff --git a/components/esp_hw_support/port/esp32c6/chip_info.c b/components/esp_hw_support/port/esp32c6/chip_info.c new file mode 100644 index 0000000000..4be74f04bf --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/chip_info.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_chip_info.h" +#include "hal/efuse_hal.h" + +void esp_chip_info(esp_chip_info_t *out_info) +{ + memset(out_info, 0, sizeof(*out_info)); + out_info->model = CHIP_ESP32C6; + out_info->revision = efuse_hal_chip_revision(); + out_info->cores = 1; + out_info->features = CHIP_FEATURE_WIFI_BGN | CHIP_FEATURE_BLE; +} diff --git a/components/esp_hw_support/port/esp32c6/esp_crypto_lock.c b/components/esp_hw_support/port/esp32c6/esp_crypto_lock.c new file mode 100644 index 0000000000..34f307b54c --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/esp_crypto_lock.c @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_crypto_lock.h" + +/* Lock overview: +SHA: peripheral independent, but DMA is shared with AES +AES: peripheral independent, but DMA is shared with SHA +MPI/RSA: independent +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; + +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); +} diff --git a/components/esp_hw_support/port/esp32c6/esp_ds.c b/components/esp_hw_support/port/esp32c6/esp_ds.c new file mode 100644 index 0000000000..7d9228c0a6 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/esp_ds.c @@ -0,0 +1,224 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_private/periph_ctrl.h" +#include "esp_crypto_lock.h" +#include "hal/ds_hal.h" +#include "hal/ds_ll.h" +#include "hal/hmac_hal.h" +#include "esp32c6/rom/digital_signature.h" +#include "esp_timer.h" +#include "esp_ds.h" + +struct esp_ds_context { + const esp_ds_data_t *data; +}; + +/** + * The vtask delay \c esp_ds_sign() is using while waiting for completion of the signing operation. + */ +#define ESP_DS_SIGN_TASK_DELAY_MS 10 + +#define RSA_LEN_MAX 127 + +/* + * esp_digital_signature_length_t is used in esp_ds_data_t in contrast to ets_ds_data_t, where unsigned is used. + * Check esp_digital_signature_length_t's width here because it's converted to unsigned using raw casts. + */ +_Static_assert(sizeof(esp_digital_signature_length_t) == sizeof(unsigned), + "The size of esp_digital_signature_length_t and unsigned has to be the same"); + +/* + * esp_ds_data_t is used in the encryption function but casted to ets_ds_data_t. + * Check esp_ds_data_t's width here because it's converted using raw casts. + */ +_Static_assert(sizeof(esp_ds_data_t) == sizeof(ets_ds_data_t), + "The size of esp_ds_data_t and ets_ds_data_t has to be the same"); + +static void ds_acquire_enable(void) +{ + esp_crypto_ds_lock_acquire(); + + // We also enable SHA and HMAC here. SHA is used by HMAC, HMAC is used by DS. + periph_module_enable(PERIPH_HMAC_MODULE); + periph_module_enable(PERIPH_SHA_MODULE); + periph_module_enable(PERIPH_DS_MODULE); + + hmac_hal_start(); +} + +static void ds_disable_release(void) +{ + ds_hal_finish(); + + periph_module_disable(PERIPH_DS_MODULE); + periph_module_disable(PERIPH_SHA_MODULE); + periph_module_disable(PERIPH_HMAC_MODULE); + + esp_crypto_ds_lock_release(); +} + +esp_err_t esp_ds_sign(const void *message, + const esp_ds_data_t *data, + hmac_key_id_t key_id, + void *signature) +{ + // Need to check signature here, otherwise the signature is only checked when the signing has finished and fails + // but the signing isn't uninitialized and the mutex is still locked. + if (!signature) { + return ESP_ERR_INVALID_ARG; + } + + esp_ds_context_t *context; + esp_err_t result = esp_ds_start_sign(message, data, key_id, &context); + if (result != ESP_OK) { + return result; + } + + while (esp_ds_is_busy()) + vTaskDelay(ESP_DS_SIGN_TASK_DELAY_MS / portTICK_PERIOD_MS); + + return esp_ds_finish_sign(signature, context); +} + +esp_err_t esp_ds_start_sign(const void *message, + const esp_ds_data_t *data, + hmac_key_id_t key_id, + esp_ds_context_t **esp_ds_ctx) +{ + if (!message || !data || !esp_ds_ctx) { + return ESP_ERR_INVALID_ARG; + } + + if (key_id >= HMAC_KEY_MAX) { + return ESP_ERR_INVALID_ARG; + } + + if (!(data->rsa_length == ESP_DS_RSA_1024 + || data->rsa_length == ESP_DS_RSA_2048 + || data->rsa_length == ESP_DS_RSA_3072)) { + return ESP_ERR_INVALID_ARG; + } + + ds_acquire_enable(); + + // initiate hmac + uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_DS, key_id); + if (conf_error) { + ds_disable_release(); + return ESP32C6_ERR_HW_CRYPTO_DS_HMAC_FAIL; + } + + ds_hal_start(); + + // check encryption key from HMAC + int64_t start_time = esp_timer_get_time(); + while (ds_ll_busy() != 0) { + if ((esp_timer_get_time() - start_time) > SOC_DS_KEY_CHECK_MAX_WAIT_US) { + ds_disable_release(); + return ESP32C6_ERR_HW_CRYPTO_DS_INVALID_KEY; + } + } + + esp_ds_context_t *context = malloc(sizeof(esp_ds_context_t)); + if (!context) { + ds_disable_release(); + return ESP_ERR_NO_MEM; + } + + size_t rsa_len = (data->rsa_length + 1) * 4; + ds_hal_write_private_key_params(data->c); + ds_hal_configure_iv(data->iv); + ds_hal_write_message(message, rsa_len); + + // initiate signing + ds_hal_start_sign(); + + context->data = data; + *esp_ds_ctx = context; + + return ESP_OK; +} + +bool esp_ds_is_busy(void) +{ + return ds_hal_busy(); +} + +esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx) +{ + if (!signature || !esp_ds_ctx) { + return ESP_ERR_INVALID_ARG; + } + + const esp_ds_data_t *data = esp_ds_ctx->data; + unsigned rsa_len = (data->rsa_length + 1) * 4; + + while (ds_hal_busy()) { } + + ds_signature_check_t sig_check_result = ds_hal_read_result((uint8_t*) signature, (size_t) rsa_len); + + esp_err_t return_value = ESP_OK; + + if (sig_check_result == DS_SIGNATURE_MD_FAIL || sig_check_result == DS_SIGNATURE_PADDING_AND_MD_FAIL) { + return_value = ESP32C6_ERR_HW_CRYPTO_DS_INVALID_DIGEST; + } + + if (sig_check_result == DS_SIGNATURE_PADDING_FAIL) { + return_value = ESP32C6_ERR_HW_CRYPTO_DS_INVALID_PADDING; + } + + free(esp_ds_ctx); + + hmac_hal_clean(); + + ds_disable_release(); + + return return_value; +} + +esp_err_t esp_ds_encrypt_params(esp_ds_data_t *data, + const void *iv, + const esp_ds_p_data_t *p_data, + const void *key) +{ + if (!p_data) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t result = ESP_OK; + + esp_crypto_ds_lock_acquire(); + periph_module_enable(PERIPH_AES_MODULE); + periph_module_enable(PERIPH_DS_MODULE); + periph_module_enable(PERIPH_SHA_MODULE); + periph_module_enable(PERIPH_HMAC_MODULE); + periph_module_enable(PERIPH_RSA_MODULE); + + ets_ds_data_t *ds_data = (ets_ds_data_t*) data; + const ets_ds_p_data_t *ds_plain_data = (const ets_ds_p_data_t*) p_data; + + ets_ds_result_t ets_result = ets_ds_encrypt_params(ds_data, iv, ds_plain_data, key, ETS_DS_KEY_HMAC); + + if (ets_result == ETS_DS_INVALID_PARAM) { + result = ESP_ERR_INVALID_ARG; + } + + periph_module_disable(PERIPH_RSA_MODULE); + periph_module_disable(PERIPH_HMAC_MODULE); + periph_module_disable(PERIPH_SHA_MODULE); + periph_module_disable(PERIPH_DS_MODULE); + periph_module_disable(PERIPH_AES_MODULE); + esp_crypto_ds_lock_release(); + + return result; +} diff --git a/components/esp_hw_support/port/esp32c6/esp_hmac.c b/components/esp_hw_support/port/esp32c6/esp_hmac.c new file mode 100644 index 0000000000..99a7d95088 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/esp_hmac.c @@ -0,0 +1,182 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: IDF-5355 Copy frome C3 + +#include +#include "esp_private/periph_ctrl.h" +#include "esp32c6/rom/hmac.h" +#include "esp32c6/rom/ets_sys.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_hmac.h" +#include "esp_log.h" +#include "esp_crypto_lock.h" +#include "soc/hwcrypto_reg.h" + +#include "hal/hmac_hal.h" + +#define SHA256_BLOCK_SZ 64 +#define SHA256_PAD_SZ 8 + +static const char *TAG = "esp_hmac"; + +/** + * @brief Apply the HMAC padding without the embedded length. + * + * @note This function does not check the data length, it is the responsibility of the other functions in this + * module to make sure that \c data_len is at most SHA256_BLOCK_SZ - 1 so the padding fits in. + * Otherwise, this function has undefined behavior. + * Note however, that for the actual HMAC implementation on ESP32C6, the length also needs to be applied at the end + * of the block. This function alone deosn't do that. + */ +static void write_and_padd(uint8_t *block, const uint8_t *data, uint16_t data_len) +{ + memcpy(block, data, data_len); + // Apply a one bit, followed by zero bits (refer to the ESP32C6 TRM). + block[data_len] = 0x80; + bzero(block + data_len + 1, SHA256_BLOCK_SZ - data_len - 1); +} + +esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, + const void *message, + size_t message_len, + uint8_t *hmac) +{ + const uint8_t *message_bytes = (const uint8_t *)message; + + if (!message || !hmac) { + return ESP_ERR_INVALID_ARG; + } + if (key_id >= HMAC_KEY_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_crypto_hmac_lock_acquire(); + + // We also enable SHA and DS here. SHA is used by HMAC, DS will otherwise hold SHA in reset state. + periph_module_enable(PERIPH_HMAC_MODULE); + periph_module_enable(PERIPH_SHA_MODULE); + periph_module_enable(PERIPH_DS_MODULE); + + hmac_hal_start(); + + uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_USER, key_id); + if (conf_error) { + esp_crypto_hmac_lock_release(); + return ESP_FAIL; + } + + if (message_len + 1 + SHA256_PAD_SZ <= SHA256_BLOCK_SZ) { + // If message including padding is only one block... + // Last message block, so apply SHA-256 padding rules in software + uint8_t block[SHA256_BLOCK_SZ]; + uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512); + + write_and_padd(block, message_bytes, message_len); + // Final block: append the bit length in this block and signal padding to peripheral + memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len), + &bit_len, sizeof(bit_len)); + hmac_hal_write_one_block_512(block); + } else { + // If message including padding is needs more than one block + + // write all blocks without padding except the last one + size_t remaining_blocks = message_len / SHA256_BLOCK_SZ; + for (int i = 1; i < remaining_blocks; i++) { + hmac_hal_write_block_512(message_bytes); + message_bytes += SHA256_BLOCK_SZ; + hmac_hal_next_block_normal(); + } + + // If message fits into one block but without padding, we must not write another block. + if (remaining_blocks) { + hmac_hal_write_block_512(message_bytes); + message_bytes += SHA256_BLOCK_SZ; + } + + size_t remaining = message_len % SHA256_BLOCK_SZ; + // Last message block, so apply SHA-256 padding rules in software + uint8_t block[SHA256_BLOCK_SZ]; + uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512); + + // If the remaining message and appended padding doesn't fit into a single block, we have to write an + // extra block with the rest of the message and potential padding first. + if (remaining >= SHA256_BLOCK_SZ - SHA256_PAD_SZ) { + write_and_padd(block, message_bytes, remaining); + hmac_hal_next_block_normal(); + hmac_hal_write_block_512(block); + bzero(block, SHA256_BLOCK_SZ); + } else { + write_and_padd(block, message_bytes, remaining); + } + memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len), + &bit_len, sizeof(bit_len)); + hmac_hal_next_block_padding(); + hmac_hal_write_block_512(block); + } + + // Read back result (bit swapped) + hmac_hal_read_result_256(hmac); + + periph_module_disable(PERIPH_DS_MODULE); + periph_module_disable(PERIPH_SHA_MODULE); + periph_module_disable(PERIPH_HMAC_MODULE); + + esp_crypto_hmac_lock_release(); + + return ESP_OK; +} + +static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id) { + return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id; +} + +esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token) +{ + int ets_status; + esp_err_t err = ESP_OK; + + if ((!token) || (key_id >= HMAC_KEY_MAX)) + return ESP_ERR_INVALID_ARG; + + /* Check if JTAG is permanently disabled by HW Disable eFuse */ + if (esp_efuse_read_field_bit(ESP_EFUSE_DIS_PAD_JTAG)) { + ESP_LOGE(TAG, "JTAG disabled permanently."); + return ESP_FAIL; + } + + esp_crypto_hmac_lock_acquire(); + + ets_status = ets_jtag_enable_temporarily(token, convert_key_type(key_id)); + + if (ets_status != ETS_OK) { + // ets_jtag_enable_temporarily returns either ETS_OK or ETS_FAIL + err = ESP_FAIL; + ESP_LOGE(TAG, "JTAG re-enabling failed (%d)", err); + } + + ESP_LOGD(TAG, "HMAC computation in downstream mode is completed."); + + ets_hmac_disable(); + + esp_crypto_hmac_lock_release(); + + return err; +} + +esp_err_t esp_hmac_jtag_disable() +{ + esp_crypto_hmac_lock_acquire(); + + REG_SET_BIT(HMAC_SET_INVALIDATE_JTAG_REG, HMAC_SET_INVALIDATE_JTAG); + + esp_crypto_hmac_lock_release(); + + ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled."); + + return ESP_OK; +} diff --git a/components/esp_hw_support/port/esp32c6/esp_memprot.c b/components/esp_hw_support/port/esp32c6/esp_memprot.c new file mode 100644 index 0000000000..8bb37b54c4 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/esp_memprot.c @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: IDF-5684 +// ESP32C6 has no memory permission management mechanism based on dividing lines, +// TEE-based implementation can be added here diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk.c b/components/esp_hw_support/port/esp32c6/rtc_clk.c new file mode 100644 index 0000000000..fe7aa35b84 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_clk.c @@ -0,0 +1,226 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp32c6/rom/ets_sys.h" +#include "esp32c6/rom/rtc.h" +#include "soc/rtc.h" +#include "esp_hw_log.h" +#include "esp_rom_sys.h" +#include "hal/usb_serial_jtag_ll.h" +#include "hal/clk_tree_ll.h" +#include "hal/regi2c_ctrl_ll.h" +#include "soc/lp_clkrst_reg.h" + +static const char *TAG = "rtc_clk"; + +void rtc_clk_32k_enable(bool enable) +{ + // TODO: IDF-5645 +} + +void rtc_clk_32k_enable_external(void) +{ + // TODO: IDF-5645 +} + +void rtc_clk_32k_bootstrap(uint32_t cycle) +{ + // TODO: IDF-5645 +} + +bool rtc_clk_32k_enabled(void) +{ + // TODO: IDF-5645 + return 0; +} + +void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en) +{ + // TODO: IDF-5645 +} + +bool rtc_clk_8m_enabled(void) +{ + // TODO: IDF-5645 + return 0; +} + +bool rtc_clk_8md256_enabled(void) +{ + // TODO: IDF-5645 + return 0; +} + +void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src) +{ + // TODO: IDF-5645 +} + +soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void) +{ + // TODO: IDF-5645 + return REG_GET_FIELD(LP_CLKRST_LP_CLK_CONF_REG, LP_CLKRST_SLOW_CLK_SEL); +} + +uint32_t rtc_clk_slow_freq_get_hz(void) +{ + // TODO: IDF-5645 + switch (rtc_clk_slow_freq_get()) { + case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K; + case RTC_SLOW_FREQ_32K_XTAL: return RTC_SLOW_CLK_FREQ_32K; + case RTC_SLOW_FREQ_8MD256: return RTC_SLOW_CLK_FREQ_8MD256; + default: return 0; + } +} + +void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src) +{ + // TODO: IDF-5645 +} + +soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void) +{ + // TODO: IDF-5645 + return 0; +} + +#if 0 +static void rtc_clk_bbpll_disable(void) +{ + // TODO: IDF-5645 +} + +static void rtc_clk_bbpll_enable(void) +{ + // TODO: IDF-5645 +} + +static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) +{ + // TODO: IDF-5645 +} + +/** + * 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) +{ + // TODO: IDF-5645 +} +#endif + +bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config) +{ + // TODO: IDF-5645 + return 0; +} + +void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) +{ + // TODO: IDF-5645 +} + +void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) +{ + // TODO: IDF-5645 +} + +void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config) +{ + // TODO: IDF-5645 +} + +void rtc_clk_cpu_freq_set_xtal(void) +{ + ESP_EARLY_LOGW(TAG, "rtc_clk_cpu_freq_set_xtal() has not been implemented yet"); + // TODO: IDF-5645 +} + +#if 0 +/** + * Switch to XTAL frequency. Does not disable the PLL. + */ +static void rtc_clk_cpu_freq_to_xtal(int freq, int div) +{ + // TODO: IDF-5645 +} + +static void rtc_clk_cpu_freq_to_8m(void) +{ + // TODO: IDF-5645 +} +#endif + +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) +{ + ESP_EARLY_LOGW(TAG, "rtc_clk_xtal_freq_get() has not been implemented yet"); + // TODO: IDF-5645 + return 40; +} + +void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq) +{ + // TODO: IDF-5645 +} + +void rtc_clk_apb_freq_update(uint32_t apb_freq) +{ + // TODO: IDF-5645 +} + +uint32_t rtc_clk_apb_freq_get(void) +{ + ESP_EARLY_LOGW(TAG, "rtc_clk_apb_freq_get() has not been implemented yet"); + // TODO: IDF-5645 + return 0; +} + +void rtc_clk_divider_set(uint32_t div) +{ + // TODO: IDF-5645 +} + +void rtc_clk_8m_divider_set(uint32_t div) +{ + // TODO: IDF-5645 +} + +void rtc_dig_clk8m_enable(void) +{ + // TODO: IDF-5645 +} + +void rtc_dig_clk8m_disable(void) +{ + // TODO: IDF-5645 +} + +bool rtc_dig_8m_enabled(void) +{ + // TODO: IDF-5645 + return 0; +} + +#if 0 +static bool rtc_clk_set_bbpll_always_on(void) +{ + // TODO: IDF-5645 + return 0; +} +#endif + +/* Name used in libphy.a:phy_chip_v7.o + * TODO: update the library to use rtc_clk_xtal_freq_get + */ +rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get"))); diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk_init.c b/components/esp_hw_support/port/esp32c6/rtc_clk_init.c new file mode 100644 index 0000000000..73a950930f --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_clk_init.c @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "esp32c6/rom/ets_sys.h" +#include "esp32c6/rom/rtc.h" +#include "esp32c6/rom/uart.h" +#include "soc/rtc.h" +#include "soc/efuse_periph.h" +#include "esp_cpu.h" +#include "hal/regi2c_ctrl_ll.h" +#include "esp_hw_log.h" +#include "sdkconfig.h" +#include "esp_rom_uart.h" + +static const char *TAG = "rtc_clk_init"; + +void rtc_clk_init(rtc_clk_config_t cfg) +{ + ESP_HW_LOGW(TAG, "rtc_clk_init() has not been implemented yet"); +#if 0 // TODO: IDF-5645 + rtc_cpu_freq_config_t old_config, new_config; + + /* Set tuning parameters for 8M and 150k clocks. + * Note: this doesn't attempt to set the clocks to precise frequencies. + * Instead, we calibrate these clocks against XTAL frequency later, when necessary. + * - SCK_DCAP value controls tuning of 150k clock. + * The higher the value of DCAP is, the lower is the frequency. + * - CK8M_DFREQ value controls tuning of 8M clock. + * CLK_8M_DFREQ constant gives the best temperature characteristics. + */ + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap); + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq); + + /* Configure 150k clock division */ + rtc_clk_divider_set(cfg.clk_rtc_clk_div); + + /* Configure 8M clock division */ + rtc_clk_8m_divider_set(cfg.clk_8m_clk_div); + + /* Reset (disable) i2c internal bus for all regi2c registers */ + regi2c_ctrl_ll_i2c_reset(); // TODO: This should be move out from rtc_clk_init + /* Enable the internal bus used to configure BBPLL */ + regi2c_ctrl_ll_i2c_bbpll_enable(); // TODO: This should be moved to bbpll_set_config + + rtc_xtal_freq_t xtal_freq = cfg.xtal_freq; + esp_rom_uart_tx_wait_idle(0); + rtc_clk_xtal_freq_update(xtal_freq); + rtc_clk_apb_freq_update(xtal_freq * MHZ); + + /* Set CPU frequency */ + rtc_clk_cpu_freq_get_config(&old_config); + uint32_t freq_before = old_config.freq_mhz; + bool res = rtc_clk_cpu_freq_mhz_to_config(cfg.cpu_freq_mhz, &new_config); + if (!res) { + 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; + bool need_rc_fast_d256_en = false; + 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_RC_FAST_D256) { + need_rc_fast_d256_en = true; + } + rtc_clk_8m_enable(need_rc_fast_en, need_rc_fast_d256_en); + rtc_clk_fast_src_set(cfg.fast_clk_src); + rtc_clk_slow_src_set(cfg.slow_clk_src); +#endif +} diff --git a/components/esp_hw_support/port/esp32c6/rtc_init.c b/components/esp_hw_support/port/esp32c6/rtc_init.c new file mode 100644 index 0000000000..8a5daa4517 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_init.c @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: IDF-5645 diff --git a/components/esp_hw_support/port/esp32c6/rtc_pm.c b/components/esp_hw_support/port/esp32c6/rtc_pm.c new file mode 100644 index 0000000000..8a5daa4517 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_pm.c @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: IDF-5645 diff --git a/components/esp_hw_support/port/esp32c6/rtc_sleep.c b/components/esp_hw_support/port/esp32c6/rtc_sleep.c new file mode 100644 index 0000000000..8a5daa4517 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_sleep.c @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: IDF-5645 diff --git a/components/esp_hw_support/port/esp32c6/rtc_time.c b/components/esp_hw_support/port/esp32c6/rtc_time.c new file mode 100644 index 0000000000..b5bfa6e7d2 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/rtc_time.c @@ -0,0 +1,103 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp32c6/rom/ets_sys.h" +#include "soc/rtc.h" +// #include "soc/rtc_cntl_reg.h" +#include "hal/clk_tree_ll.h" +#include "soc/timer_group_reg.h" +#include "esp_rom_sys.h" + +/* 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. + */ + +/** + * @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio + * @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 + */ +// TODO: IDF-5645 +static const char *TAG = "rtc_time"; + +uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_clk_cal_internal() has not been implemented yet"); + return 0; +} + +uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_clk_cal_ratio() has not been implemented yet"); + return 0; +} + +uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_clk_cal() has not been implemented yet"); + return 0; +} + +uint64_t rtc_time_us_to_slowclk(uint64_t time_in_us, uint32_t period) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_time_us_to_slowclk() has not been implemented yet"); + return 0; +} + +uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_time_slowclk_to_us() has not been implemented yet"); + return 0; +} + +uint64_t rtc_time_get(void) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_time_get() has not been implemented yet"); + return 0; +} + +uint64_t rtc_light_slp_time_get(void) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_light_slp_time_get() has not been implemented yet"); + return 0; +} + +uint64_t rtc_deep_slp_time_get(void) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_deep_slp_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-5645 + 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) +{ + // TODO: IDF-5645 + ESP_EARLY_LOGW(TAG, "rtc_clk_freq_cal() has not been implemented yet"); + return 0; +} diff --git a/components/esp_hw_support/port/esp32c6/systimer.c b/components/esp_hw_support/port/esp32c6/systimer.c new file mode 100644 index 0000000000..d5ea58b1aa --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/systimer.c @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_private/systimer.h" + +/** + * @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; +} diff --git a/components/esp_hw_support/rtc_module.c b/components/esp_hw_support/rtc_module.c index 640f4c1db6..8a8637c9e3 100644 --- a/components/esp_hw_support/rtc_module.c +++ b/components/esp_hw_support/rtc_module.c @@ -27,6 +27,12 @@ #endif #include "sys/queue.h" +#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 +static const char *TAG = "rtc_module"; +#endif + +#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 + #define NOT_REGISTERED (-1) portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; @@ -90,9 +96,14 @@ out: portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return err; } +#endif // !CONFIG_IDF_TARGET_ESP32C6 TODO: IDF-5645 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 // TODO: IDF-5645 + ESP_LOGW(TAG, "rtc_isr_register() has not been implemented yet"); + return ESP_OK; +#else esp_err_t err = rtc_isr_ensure_installed(); if (err != ESP_OK) { return err; @@ -115,10 +126,15 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t r SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next); portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return ESP_OK; +#endif } esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) { +#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 + ESP_LOGW(TAG, "rtc_isr_deregister() has not been implemented yet"); + return ESP_OK; +#else rtc_isr_handler_t* it; rtc_isr_handler_t* prev = NULL; bool found = false; @@ -141,8 +157,10 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg) } portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock); return found ? ESP_OK : ESP_ERR_INVALID_STATE; +#endif } +#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 /** * @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.) @@ -160,19 +178,25 @@ static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask) { rtc_intr_cache &= ~rtc_intr_mask; } +#endif + IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu) { +#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 if (rtc_isr_cpu == cpu) { rtc_intr_enabled |= RTCCNTL.int_ena.val; RTCCNTL.int_ena.val &= rtc_intr_cache; } +#endif } IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu) { +#if !CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 if (rtc_isr_cpu == cpu) { RTCCNTL.int_ena.val = rtc_intr_enabled; rtc_intr_enabled = 0; } +#endif } diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index e2c35afa0c..a1f59dfb5b 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -78,6 +78,10 @@ #include "esp32c2/rom/cache.h" #include "esp32c2/rom/rtc.h" #include "soc/extmem_reg.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/cache.h" +#include "esp32c6/rom/rtc.h" +#include "soc/extmem_reg.h" #endif // If light sleep time is less than that, don't power down flash @@ -107,6 +111,9 @@ #elif CONFIG_IDF_TARGET_ESP32C2 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) +#elif CONFIG_IDF_TARGET_ESP32C6 +#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)// TODO: IDF-5348 +#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #endif #define LIGHT_SLEEP_TIME_OVERHEAD_US DEFAULT_HARDWARE_OUT_OVERHEAD_US @@ -789,7 +796,11 @@ esp_err_t esp_light_sleep_start(void) rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails +#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5653 + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &LP_WDT}; +#else wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; +#endif bool wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here. if (!wdt_was_enabled) { wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); @@ -1231,6 +1242,9 @@ esp_err_t esp_sleep_disable_bt_wakeup(void) esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) { +#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5645 + return ESP_SLEEP_WAKEUP_UNDEFINED; +#else if (esp_rom_get_reset_reason(0) != RESET_REASON_CORE_DEEP_SLEEP && !s_light_sleep_wakeup) { return ESP_SLEEP_WAKEUP_UNDEFINED; } @@ -1278,6 +1292,7 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) } else { return ESP_SLEEP_WAKEUP_UNDEFINED; } +#endif } esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,