Merge branch 'feature/add_esp32h2_target' into 'master'

esp32h2: add esp32h2 build target

See merge request espressif/esp-idf!13944
This commit is contained in:
Michael (XIAO Xufeng)
2021-07-01 14:46:37 +00:00
363 changed files with 80073 additions and 141 deletions

View File

@@ -11,6 +11,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
config IDF_ENV_FPGA config IDF_ENV_FPGA
# This option is for internal use only # This option is for internal use only
bool bool
default "y" if IDF_TARGET="esp32h2" # ESP32H2-TODO: IDF-3378
option env="IDF_ENV_FPGA" option env="IDF_ENV_FPGA"
config IDF_TARGET_ARCH_RISCV config IDF_TARGET_ARCH_RISCV
@@ -51,6 +52,12 @@ mainmenu "Espressif IoT Development Framework Configuration"
select FREERTOS_UNICORE select FREERTOS_UNICORE
select IDF_TARGET_ARCH_RISCV select IDF_TARGET_ARCH_RISCV
config IDF_TARGET_ESP32H2
bool
default "y" if IDF_TARGET="esp32h2"
select FREERTOS_UNICORE
select IDF_TARGET_ARCH_RISCV
config IDF_TARGET_LINUX config IDF_TARGET_LINUX
bool bool
default "y" if IDF_TARGET="linux" default "y" if IDF_TARGET="linux"
@@ -61,6 +68,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
default 0x0002 if IDF_TARGET_ESP32S2 default 0x0002 if IDF_TARGET_ESP32S2
default 0x0005 if IDF_TARGET_ESP32C3 default 0x0005 if IDF_TARGET_ESP32C3
default 0x0009 if IDF_TARGET_ESP32S3 default 0x0009 if IDF_TARGET_ESP32S3
default 0x000A if IDF_TARGET_ESP32H2 # ESP32H2-TODO: IDF-3475
default 0xFFFF default 0xFFFF
menu "SDK tool configuration" menu "SDK tool configuration"
@@ -70,6 +78,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
default "xtensa-esp32s2-elf-" if IDF_TARGET_ESP32S2 default "xtensa-esp32s2-elf-" if IDF_TARGET_ESP32S2
default "xtensa-esp32s3-elf-" if IDF_TARGET_ESP32S3 default "xtensa-esp32s3-elf-" if IDF_TARGET_ESP32S3
default "riscv32-esp-elf-" if IDF_TARGET_ESP32C3 default "riscv32-esp-elf-" if IDF_TARGET_ESP32C3
default "riscv32-esp-elf-" if IDF_TARGET_ESP32H2
help help
The prefix/path that is used to call the toolchain. The default setting assumes The prefix/path that is used to call the toolchain. The default setting assumes

View File

@@ -4,7 +4,7 @@ idf_component_register(SRCS "bootloader_start.c"
idf_build_get_property(target IDF_TARGET) idf_build_get_property(target IDF_TARGET)
set(scripts "ld/${target}/bootloader.ld") set(scripts "ld/${target}/bootloader.ld")
if(NOT CONFIG_IDF_TARGET_ESP32C3) if(NOT CONFIG_IDF_TARGET_ESP32C3 AND NOT CONFIG_IDF_TARGET_ESP32H2)
list(APPEND scripts "ld/${target}/bootloader.rom.ld") list(APPEND scripts "ld/${target}/bootloader.rom.ld")
endif() endif()

View File

@@ -0,0 +1,189 @@
/** Simplified memory map for the bootloader.
* Make sure the bootloader can load into main memory without overwriting itself.
* We put 2nd bootloader in the high address space (before ROM stack/data/bss).
* See memory usage for ROM bootloader at the end of this file.
*/
MEMORY
{
iram_seg (RWX) : org = 0x403CE000, len = 0x2000
iram_loader_seg (RWX) : org = 0x403D0000, len = 0x6000
dram_seg (RW) : org = 0x3FCD6000, len = 0x4000
}
/* Default entry point: */
ENTRY(call_start_cpu0);
SECTIONS
{
.iram_loader.text :
{
. = ALIGN (16);
_loader_text_start = ABSOLUTE(.);
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
*liblog.a:(.literal .text .literal.* .text.*)
*libgcc.a:(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_disable .text.bootloader_random_disable)
*libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable)
*libbootloader_support.a:bootloader_efuse_esp32h2.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libesp_hw_support.a:rtc_clk.*(.literal .text .literal.* .text.*)
*libesp_hw_support.a:rtc_time.*(.literal .text .literal.* .text.*)
*libesp_hw_support.a:regi2c_ctrl.*(.literal .text .literal.* .text.*)
*libefuse.a:*.*(.literal .text .literal.* .text.*)
*(.fini.literal)
*(.fini)
*(.gnu.version)
_loader_text_end = ABSOLUTE(.);
} > iram_loader_seg
.iram.text :
{
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
*(.init)
} > iram_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_dram_start = ABSOLUTE(.);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram_seg
.dram0.data :
{
_data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
_data_end = ABSOLUTE(.);
} > dram_seg
.dram0.rodata :
{
_rodata_start = ABSOLUTE(.);
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
*(.eh_frame)
. = (. + 3) & ~ 3;
/* C++ constructor and destructor tables, properly ordered: */
__init_array_start = ABSOLUTE(.);
KEEP (*crtbegin.*(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.*) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__init_array_end = ABSOLUTE(.);
KEEP (*crtbegin.*(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
_rodata_end = ABSOLUTE(.);
/* Literals are also RO data. */
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_dram_end = ABSOLUTE(.);
} > dram_seg
.iram.text :
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.iram .iram.*) /* catch stray IRAM_ATTR */
*(.fini.literal)
*(.fini)
*(.gnu.version)
/** CPU will try to prefetch up to 16 bytes of
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
* safe access to up to 16 bytes after the last real instruction, add
* dummy bytes to ensure this
*/
. += 16;
_text_end = ABSOLUTE(.);
_etext = .;
} > iram_seg
}
/**
* Appendix: Memory Usage of ROM bootloader
*
* +--------+--------------+------+ 0x3FCC_B900
* | ^ |
* | | |
* | | data/bss |
* | | |
* | v |
* +------------------------------+ 0x3FCD_D210
* | ^ |
* | | |
* | | stack |
* | | |
* | v |
* +------------------------------+ 0x3FCD_F210
*/

View File

@@ -31,12 +31,15 @@ endif
COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \ COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \
src/bootloader_flash_config_esp32s3.o \ src/bootloader_flash_config_esp32s3.o \
src/bootloader_flash_config_esp32c3.o \ src/bootloader_flash_config_esp32c3.o \
src/bootloader_flash_config_esp32h2.o \
src/bootloader_efuse_esp32s2.o \ src/bootloader_efuse_esp32s2.o \
src/bootloader_efuse_esp32s3.o \ src/bootloader_efuse_esp32s3.o \
src/bootloader_efuse_esp32c3.o \ src/bootloader_efuse_esp32c3.o \
src/bootloader_efuse_esp32h2.o \
src/bootloader_random_esp32s2.o \ src/bootloader_random_esp32s2.o \
src/bootloader_random_esp32s3.o \ src/bootloader_random_esp32s3.o \
src/bootloader_random_esp32c3.o src/bootloader_random_esp32c3.o \
src/bootloader_random_esp32h2.o
ifdef IS_BOOTLOADER_BUILD ifdef IS_BOOTLOADER_BUILD
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME

View File

@@ -17,6 +17,8 @@
#include "esp32s3/rom/rtc.h" #include "esp32s3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h" #include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -16,6 +16,7 @@ typedef enum {
ESP_CHIP_ID_ESP32S2 = 0x0002, /*!< chip ID: ESP32-S2 */ ESP_CHIP_ID_ESP32S2 = 0x0002, /*!< chip ID: ESP32-S2 */
ESP_CHIP_ID_ESP32C3 = 0x0005, /*!< chip ID: ESP32-C3 */ ESP_CHIP_ID_ESP32C3 = 0x0005, /*!< chip ID: ESP32-C3 */
ESP_CHIP_ID_ESP32S3 = 0x0009, /*!< chip ID: ESP32-S3 */ ESP_CHIP_ID_ESP32S3 = 0x0009, /*!< chip ID: ESP32-S3 */
ESP_CHIP_ID_ESP32H2 = 0x000A, /*!< chip ID: ESP32-H2 */ // ESP32H2-TODO: IDF-3475
ESP_CHIP_ID_INVALID = 0xFFFF /*!< Invalid chip ID (we defined it to make sure the esp_chip_id_t is 2 bytes size) */ ESP_CHIP_ID_INVALID = 0xFFFF /*!< Invalid chip ID (we defined it to make sure the esp_chip_id_t is 2 bytes size) */
} __attribute__((packed)) esp_chip_id_t; } __attribute__((packed)) esp_chip_id_t;

View File

@@ -25,6 +25,9 @@
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/efuse.h" #include "esp32s3/rom/efuse.h"
#include "esp32s3/rom/secure_boot.h" #include "esp32s3/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/efuse.h"
#include "esp32h2/rom/secure_boot.h"
#endif #endif
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED #ifdef CONFIG_SECURE_BOOT_V1_ENABLED

View File

@@ -22,6 +22,8 @@
#include "esp32s3/rom/rtc.h" #include "esp32s3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h" #include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#endif #endif
#include "esp_rom_uart.h" #include "esp_rom_uart.h"

View File

@@ -17,6 +17,8 @@
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h" #include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#endif #endif
#include "esp_rom_crc.h" #include "esp_rom_crc.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"

View File

@@ -22,6 +22,9 @@
#include "esp32c3/rom/uart.h" #include "esp32c3/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/uart.h" #include "esp32s3/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/ets_sys.h"
#include "esp32h2/rom/uart.h"
#endif #endif
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_rom_uart.h" #include "esp_rom_uart.h"

View File

@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "soc/efuse_reg.h"
uint8_t bootloader_common_get_chip_revision(void)
{
// should return the same value as esp_efuse_get_chip_ver()
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_WAFER_VERSION);
}
uint32_t bootloader_common_get_chip_ver_pkg(void)
{
// should return the same value as esp_efuse_get_pkg_ver()
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
}

View File

@@ -29,6 +29,8 @@
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h" #include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#endif #endif
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
@@ -124,6 +126,10 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
#include "esp32c3/rom/spi_flash.h" #include "esp32c3/rom/spi_flash.h"
#include "esp32c3/rom/cache.h" #include "esp32c3/rom/cache.h"
#include "soc/cache_memory.h" #include "soc/cache_memory.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#include "esp32h2/rom/cache.h"
#include "soc/cache_memory.h"
#endif #endif
static const char *TAG = "bootloader_flash"; static const char *TAG = "bootloader_flash";
@@ -188,6 +194,9 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
uint32_t autoload = Cache_Suspend_ICache(); uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All(); Cache_Invalidate_ICache_All();
#elif CONFIG_IDF_TARGET_ESP32H2
uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All();
#endif #endif
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d size=%x src_addr=%x src_addr_aligned=%x", ESP_LOGD(TAG, "mmu set paddr=%08x count=%d size=%x src_addr=%x src_addr_aligned=%x",
src_addr & MMU_FLASH_MASK, count, size, src_addr, src_addr_aligned ); src_addr & MMU_FLASH_MASK, count, size, src_addr, src_addr_aligned );
@@ -195,7 +204,7 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count); int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count);
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0); int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
#else // S3, C3 #else // S3, C3, H2
int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0); int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
#endif #endif
if (e != 0) { if (e != 0) {
@@ -208,6 +217,8 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
return NULL; return NULL;
} }
@@ -219,6 +230,8 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
mapped = true; mapped = true;
@@ -248,6 +261,10 @@ void bootloader_munmap(const void *mapping)
Cache_Suspend_ICache(); Cache_Suspend_ICache();
Cache_Invalidate_ICache_All(); Cache_Invalidate_ICache_All();
Cache_MMU_Init(); Cache_MMU_Init();
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Suspend_ICache();
Cache_Invalidate_ICache_All();
Cache_MMU_Init();
#endif #endif
mapped = false; mapped = false;
current_read_mapping = UINT32_MAX; current_read_mapping = UINT32_MAX;
@@ -279,6 +296,8 @@ static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, s
uint32_t autoload = Cache_Suspend_DCache(); uint32_t autoload = Cache_Suspend_DCache();
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
uint32_t autoload = Cache_Suspend_ICache(); uint32_t autoload = Cache_Suspend_ICache();
#elif CONFIG_IDF_TARGET_ESP32H2
uint32_t autoload = Cache_Suspend_ICache();
#endif #endif
esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size); esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size);
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@@ -289,6 +308,8 @@ static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, s
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
return spi_to_esp_err(r); return spi_to_esp_err(r);
@@ -316,6 +337,9 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
uint32_t autoload = Cache_Suspend_ICache(); uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All(); Cache_Invalidate_ICache_All();
#elif CONFIG_IDF_TARGET_ESP32H2
uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All();
#endif #endif
ESP_LOGD(TAG, "mmu set block paddr=0x%08x (was 0x%08x)", map_at, current_read_mapping); ESP_LOGD(TAG, "mmu set block paddr=0x%08x (was 0x%08x)", map_at, current_read_mapping);
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@@ -326,6 +350,8 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0); int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0); int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
#elif CONFIG_IDF_TARGET_ESP32H2
int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
#endif #endif
if (e != 0) { if (e != 0) {
ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e); ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
@@ -337,6 +363,8 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
return ESP_FAIL; return ESP_FAIL;
} }
@@ -349,6 +377,8 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
} }
map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at)); map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at));

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp32h2/rom/gpio.h"
#include "esp32h2/rom/spi_flash.h"
#include "esp32h2/rom/efuse.h"
#include "soc/gpio_periph.h"
#include "soc/efuse_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_80M:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_40M:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_26M:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_20M:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_flash_set_dummy_out(void)
{
REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
}
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
}

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "bootloader_random.h"
#include "esp_log.h"
#include "soc/syscon_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/apb_saradc_reg.h"
#include "soc/system_reg.h"
#include "regi2c_ctrl.h"
// ESP32H2-TODO: IDF-3381
void bootloader_random_enable(void)
{
}
void bootloader_random_disable(void)
{
}

View File

@@ -45,6 +45,18 @@
#include "esp32c3/rom/secure_boot.h" #include "esp32c3/rom/secure_boot.h"
#include "soc/extmem_reg.h" #include "soc/extmem_reg.h"
#include "soc/cache_memory.h" #include "soc/cache_memory.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/cache.h"
#include "esp32h2/rom/efuse.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp32h2/rom/spi_flash.h"
#include "esp32h2/rom/crc.h"
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/uart.h"
#include "esp32h2/rom/gpio.h"
#include "esp32h2/rom/secure_boot.h"
#include "soc/extmem_reg.h"
#include "soc/cache_memory.h"
#else // CONFIG_IDF_TARGET_* #else // CONFIG_IDF_TARGET_*
#error "Unsupported IDF_TARGET" #error "Unsupported IDF_TARGET"
#endif #endif
@@ -700,6 +712,9 @@ static void set_cache_and_start_app(
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
uint32_t autoload = Cache_Suspend_ICache(); uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All(); Cache_Invalidate_ICache_All();
#elif CONFIG_IDF_TARGET_ESP32H2
uint32_t autoload = Cache_Suspend_ICache();
Cache_Invalidate_ICache_All();
#endif #endif
/* Clear the MMU entries that are already set up, /* Clear the MMU entries that are already set up,
@@ -726,6 +741,8 @@ static void set_cache_and_start_app(
rc = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count, 0); rc = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count, 0);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
rc = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count, 0); rc = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count, 0);
#elif CONFIG_IDF_TARGET_ESP32H2
rc = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count, 0);
#endif #endif
ESP_LOGV(TAG, "rc=%d", rc); ESP_LOGV(TAG, "rc=%d", rc);
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@@ -753,6 +770,8 @@ static void set_cache_and_start_app(
rc = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0); rc = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
rc = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0); rc = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0);
#elif CONFIG_IDF_TARGET_ESP32H2
rc = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0);
#endif #endif
ESP_LOGV(TAG, "rc=%d", rc); ESP_LOGV(TAG, "rc=%d", rc);
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@@ -776,6 +795,9 @@ static void set_cache_and_start_app(
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS); REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS);
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS); REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS);
#elif CONFIG_IDF_TARGET_ESP32H2
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS);
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS);
#endif #endif
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
Cache_Read_Enable(0); Cache_Read_Enable(0);
@@ -785,6 +807,8 @@ static void set_cache_and_start_app(
Cache_Resume_DCache(autoload); Cache_Resume_DCache(autoload);
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
Cache_Resume_ICache(autoload); Cache_Resume_ICache(autoload);
#elif CONFIG_IDF_TARGET_ESP32H2
Cache_Resume_ICache(autoload);
#endif #endif
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1) // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)

View File

@@ -0,0 +1,327 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_image_format.h"
#include "flash_qio_mode.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp_rom_uart.h"
#include "esp_rom_sys.h"
#include "soc/efuse_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/io_mux_reg.h"
#include "soc/assist_debug_reg.h"
#include "soc/cpu.h"
#include "soc/rtc.h"
#include "soc/spi_periph.h"
#include "soc/extmem_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/system_reg.h"
#include "esp32h2/rom/efuse.h"
#include "esp32h2/rom/spi_flash.h"
#include "esp32h2/rom/cache.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp32h2/rom/spi_flash.h"
#include "esp32h2/rom/rtc.h"
#include "bootloader_common.h"
#include "bootloader_init.h"
#include "bootloader_clock.h"
#include "bootloader_flash_config.h"
#include "bootloader_mem.h"
#include "regi2c_ctrl.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
static const char *TAG = "boot.esp32h2";
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
uint8_t clk_gpio_num = SPI_CLK_GPIO_NUM;
uint8_t q_gpio_num = SPI_Q_GPIO_NUM;
uint8_t d_gpio_num = SPI_D_GPIO_NUM;
uint8_t cs0_gpio_num = SPI_CS0_GPIO_NUM;
uint8_t hd_gpio_num = SPI_HD_GPIO_NUM;
uint8_t wp_gpio_num = SPI_WP_GPIO_NUM;
if (spiconfig == 0) {
} else {
clk_gpio_num = spiconfig & 0x3f;
q_gpio_num = (spiconfig >> 6) & 0x3f;
d_gpio_num = (spiconfig >> 12) & 0x3f;
cs0_gpio_num = (spiconfig >> 18) & 0x3f;
hd_gpio_num = (spiconfig >> 24) & 0x3f;
wp_gpio_num = wp_pin;
}
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
if (hd_gpio_num <= MAX_PAD_GPIO_NUM) {
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
}
if (wp_gpio_num <= MAX_PAD_GPIO_NUM) {
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
}
static void bootloader_reset_mmu(void)
{
Cache_Suspend_ICache();
Cache_Invalidate_ICache_All();
Cache_MMU_Init();
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS);
REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
default:
size = 2;
}
uint32_t autoload = Cache_Suspend_ICache();
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: set mode
Cache_Resume_ICache(autoload);
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_40M:
str = "40MHz";
break;
case ESP_IMAGE_SPI_SPEED_26M:
str = "26.7MHz";
break;
case ESP_IMAGE_SPI_SPEED_20M:
str = "20MHz";
break;
case ESP_IMAGE_SPI_SPEED_80M:
str = "80MHz";
break;
default:
str = "20MHz";
break;
}
ESP_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
uint32_t spi_ctrl = REG_READ(SPI_MEM_CTRL_REG(0));
if (spi_ctrl & SPI_MEM_FREAD_QIO) {
str = "QIO";
} else if (spi_ctrl & SPI_MEM_FREAD_QUAD) {
str = "QOUT";
} else if (spi_ctrl & SPI_MEM_FREAD_DIO) {
str = "DIO";
} else if (spi_ctrl & SPI_MEM_FREAD_DUAL) {
str = "DOUT";
} else if (spi_ctrl & SPI_MEM_FASTRD_MODE) {
str = "FAST READ";
} else {
str = "SLOW READ";
}
ESP_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = "1MB";
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = "2MB";
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = "4MB";
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = "8MB";
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = "16MB";
break;
default:
str = "2MB";
break;
}
ESP_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_flash_dummy_config(&bootloader_image_hdr);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
static esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_SPI && spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI) {
ESP_LOGE(TAG, "SPI flash pins are overridden. Enable CONFIG_SPI_FLASH_ROM_DRIVER_PATCH in menuconfig");
return ESP_FAIL;
}
#endif
bootloader_spi_flash_resume();
esp_rom_spiflash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
update_flash_config(&bootloader_image_hdr);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
static void wdt_reset_cpu0_info_enable(void)
{
REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG);
REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG);
REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN);
}
static void wdt_reset_info_dump(int cpu)
{
(void) cpu;
// saved PC was already printed by the ROM bootloader.
// nothing to do here.
}
static void bootloader_check_wdt_reset(void)
{
int wdt_rst = 0;
RESET_REASON rst_reas[2];
rst_reas[0] = rtc_get_reset_reason(0);
if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET ||
rst_reas[0] == TG0WDT_CPU_RESET || rst_reas[0] == TG1WDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) {
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1;
}
if (wdt_rst) {
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
}
static void bootloader_super_wdt_auto_feed(void)
{
REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY_VALUE);
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN);
REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0);
}
static inline void bootloader_hardware_init(void)
{
// This check is always included in the bootloader so it can
// print the minimum revision error message later in the boot
if (bootloader_common_get_chip_revision() < 3) {
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
}
}
static inline void bootloader_glitch_reset_disable(void)
{
/*
For origin chip & ECO1: only support swt reset;
For ECO2: fix brownout reset bug, support swt & brownout reset;
For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
*/
uint8_t chip_version = bootloader_common_get_chip_revision();
if (chip_version < 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
} else if (chip_version == 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
}
}
esp_err_t bootloader_init(void)
{
esp_err_t ret = ESP_OK;
bootloader_hardware_init();
bootloader_glitch_reset_disable();
bootloader_super_wdt_auto_feed();
// protect memory region
bootloader_init_mem();
/* check that static RAM is after the stack */
assert(&_bss_start <= &_bss_end);
assert(&_data_start <= &_data_end);
// clear bss section
bootloader_clear_bss_section();
// reset MMU
bootloader_reset_mmu();
// config clock
bootloader_clock_configure();
// initialize console, from now on, we can use esp_log
bootloader_console_init();
/* print 2nd bootloader banner */
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;
}
// read chip revision and check if it's compatible to bootloader
if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
goto err;
}
// initialize spi flash
if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
goto err;
}
// check whether a WDT reset happend
bootloader_check_wdt_reset();
// config WDT
bootloader_config_wdt();
// enable RNG early entropy source
bootloader_enable_random();
err:
return ret;
}

View File

@@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bootloader_sha.h"
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <sys/param.h>
#include "esp32h2/rom/sha.h"
static SHA_CTX ctx;
bootloader_sha256_handle_t bootloader_sha256_start()
{
// Enable SHA hardware
ets_sha_enable();
ets_sha_init(&ctx, SHA2_256);
return &ctx; // Meaningless non-NULL value
}
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
{
assert(handle != NULL);
assert(data_len % 4 == 0);
ets_sha_update(&ctx, data, data_len, false);
}
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
{
assert(handle != NULL);
if (digest == NULL) {
bzero(&ctx, sizeof(ctx));
return;
}
ets_sha_finish(&ctx, digest);
}

View File

@@ -0,0 +1,346 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <strings.h>
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "bootloader_utility.h"
#include "esp_image_format.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "esp_secure_boot.h"
#include "esp_log.h"
#include "esp32h2/rom/secure_boot.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/wdt_hal.h"
static const char *TAG = "flash_encrypt";
/* Static functions for stages of flash encryption */
static esp_err_t initialise_flash_encryption(void);
static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
static esp_err_t encrypt_bootloader(void);
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
esp_err_t esp_flash_encrypt_check_and_update(void)
{
uint8_t flash_crypt_wr_dis = 0;
uint32_t flash_crypt_cnt = 0;
esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, 3);
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &flash_crypt_wr_dis, 1);
ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_cnt);
ESP_LOGV(TAG, "EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT 0x%x", flash_crypt_wr_dis);
if (__builtin_parity(flash_crypt_cnt) == 1) {
/* Flash is already encrypted */
int left = (flash_crypt_cnt == 1) ? 1 : 0;
if (flash_crypt_wr_dis) {
left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
}
ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
return ESP_OK;
} else {
#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
/* Flash is not encrypted, so encrypt it! */
return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis);
#else
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
"is set, refusing to boot.");
return ESP_ERR_INVALID_STATE;
#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
}
}
static esp_err_t check_and_generate_encryption_keys(void)
{
esp_efuse_block_t aes_128_key_block;
bool has_key = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, &aes_128_key_block);
bool dis_write = false;
bool dis_read = false;
// If there are keys set, they must be write and read protected!
if(has_key) {
dis_write = esp_efuse_get_key_dis_write(aes_128_key_block);
dis_read = esp_efuse_get_key_dis_read(aes_128_key_block);
}
if(has_key && (!dis_read || !dis_write)) {
ESP_LOGE(TAG, "Invalid key state, a key was set but not read and write protected.");
return ESP_ERR_INVALID_STATE;
}
if(!has_key && !dis_write && !dis_read) {
ESP_LOGI(TAG, "Generating new flash encryption key...");
enum { BLOCKS_NEEDED = 1 };
esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
};
uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
for (int i = 0; i < BLOCKS_NEEDED; ++i) {
bootloader_fill_random(keys[i], 32);
}
esp_err_t err = esp_efuse_write_keys(purposes, keys, BLOCKS_NEEDED);
if (err != ESP_OK) {
if (err == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED);
} else {
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", err);
}
return err;
}
ESP_LOGD(TAG, "Key generation complete");
return ESP_OK;
} else {
ESP_LOGI(TAG, "Using pre-existing key in efuse");
return ESP_OK;
}
}
static esp_err_t initialise_flash_encryption(void)
{
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_encryption_keys();
if(key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
#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_LEGACY_SPI_BOOT);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
}
return err;
}
/* Encrypt all flash data that should be encrypted */
static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis)
{
esp_err_t err;
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
int num_partitions;
/* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the
device can't re-encrypt itself. */
if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) {
ESP_LOGE(TAG, "Cannot re-encrypt data SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis);
return ESP_FAIL;
}
if (spi_boot_crypt_cnt == 0) {
/* Very first flash of encrypted data: generate keys, etc. */
err = initialise_flash_encryption();
if (err != ESP_OK) {
return err;
}
}
err = encrypt_bootloader();
if (err != ESP_OK) {
return err;
}
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
if (err != ESP_OK) {
return err;
}
/* Now iterate the just-loaded partition table, looking for entries to encrypt
*/
/* Go through each partition and encrypt if necessary */
for (int i = 0; i < num_partitions; i++) {
err = encrypt_partition(i, &partition_table[i]);
if (err != ESP_OK) {
return err;
}
}
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
/* Set least significant 0-bit in spi_boot_crypt_cnt */
int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7);
/* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */
uint32_t new_spi_boot_crypt_cnt = (1 << (ffs_inv - 1));
ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt + spi_boot_crypt_cnt);
esp_efuse_write_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &new_spi_boot_crypt_cnt, 3);
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
//Secure SPI boot cnt after its update if needed.
const uint32_t spi_boot_cnt_wr_dis = 1;
ESP_LOGI(TAG, "Write protecting SPI_CRYPT_CNT eFuse");
esp_efuse_write_field_blob(ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT, &spi_boot_cnt_wr_dis, 1);
#endif
ESP_LOGI(TAG, "Flash encryption completed");
return ESP_OK;
}
static esp_err_t encrypt_bootloader(void)
{
esp_err_t err;
uint32_t image_length;
/* Check for plaintext bootloader (verification will fail if it's already encrypted) */
if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
ESP_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
/* The image length obtained from esp_image_verify_bootloader includes the sector boundary padding and the signature block lengths */
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_SIZE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
ESP_LOGI(TAG, "bootloader encrypted successfully");
return err;
}
else {
ESP_LOGW(TAG, "no valid bootloader was found");
return ESP_ERR_NOT_FOUND;
}
}
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
{
esp_err_t err;
/* Check for plaintext partition table */
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read partition table data");
return err;
}
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
return err;
}
} else {
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
return ESP_ERR_INVALID_STATE;
}
/* Valid partition table loaded */
ESP_LOGI(TAG, "partition table encrypted and loaded successfully");
return ESP_OK;
}
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
{
esp_err_t err;
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
if (partition->type == PART_TYPE_APP) {
/* check if the partition holds a valid unencrypted app */
esp_image_metadata_t data_ignored;
err = esp_image_verify(ESP_IMAGE_VERIFY,
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
if (!should_encrypt) {
return ESP_OK;
} else {
/* should_encrypt */
ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x (length 0x%x)...", index, partition->pos.offset, partition->pos.size);
err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size);
ESP_LOGI(TAG, "Done encrypting");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt partition %d", index);
}
return err;
}
}
esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
{
esp_err_t err;
uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)];
if (src_addr % FLASH_SECTOR_SIZE != 0) {
ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr);
return ESP_FAIL;
}
wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_feed(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
uint32_t sec_start = i + src_addr;
err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false);
if (err != ESP_OK) {
goto flash_failed;
}
err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE);
if (err != ESP_OK) {
goto flash_failed;
}
err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true);
if (err != ESP_OK) {
goto flash_failed;
}
}
return ESP_OK;
flash_failed:
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
return err;
}

View File

@@ -0,0 +1,289 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "soc/efuse_reg.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_rom_crc.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp32h2/rom/efuse.h"
#include "esp32h2/rom/secure_boot.h"
static const char *TAG = "secure_boot_v2";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
/* A signature block is valid when it has correct magic byte, crc and image digest. */
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
{
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
// All signature blocks have been parsed, no new signature block present.
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
return ESP_FAIL;
}
if (block->block_crc != crc) {
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
return ESP_FAIL;
}
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
return ESP_FAIL;
} else {
ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
return ESP_OK;
}
return ESP_FAIL;
}
/* Generates the public key digests of the valid public keys in an image's
signature block, verifies each signature, and stores the key digests in the
public_key_digests structure.
@param flash_offset Image offset in flash
@param flash_size Image size in flash (not including signature block)
@param[out] public_key_digests Pointer to structure to hold the key digests for valid sig blocks
Note that this function doesn't read any eFuses, so it doesn't know if the
keys are ultimately trusted by the hardware or not
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
*/
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
{
esp_err_t ret;
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;
}
ESP_LOGD(TAG, "reading signatures");
const ets_secure_boot_signature_t *signatures = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
if (signatures == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
return ESP_FAIL;
}
for (int i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
const ets_secure_boot_sig_block_t *block = &signatures->block[i];
ret = validate_signature_block(block, i, image_digest);
if (ret != ESP_OK) {
ret = ESP_OK; // past the last valid signature block
break;
}
/* Generating the SHA of the public key components in the signature block */
bootloader_sha256_handle_t sig_block_sha;
sig_block_sha = bootloader_sha256_start();
bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key));
bootloader_sha256_finish(sig_block_sha, key_digest);
// Check we can verify the image using this signature and this key
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
if (!verified) {
/* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid,
so this is a fatal error
*/
ret = ESP_FAIL;
ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
break;
}
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
/* Copy the key digest to the buffer provided by the caller */
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
public_key_digests->num_digests++;
}
if (ret == ESP_OK && public_key_digests->num_digests > 0) {
ESP_LOGI(TAG, "Digests successfully calculated, %d valid signatures (image offset 0x%x)",
public_key_digests->num_digests, flash_offset);
}
bootloader_munmap(signatures);
return ret;
}
static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t *image_data)
{
esp_err_t ret;
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
ret = esp_image_verify_bootloader_data(&bootloader_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
return ret;
}
/* Check if secure boot digests are present */
bool has_secure_boot_digest = esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, NULL);
has_secure_boot_digest |= esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, NULL);
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
if (!has_secure_boot_digest) {
esp_image_sig_public_key_digests_t boot_key_digests = {0};
esp_image_sig_public_key_digests_t app_key_digests = {0};
/* Generate the bootloader public key digests */
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Bootloader signature block is invalid");
return ret;
}
if (boot_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid bootloader signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", boot_key_digests.num_digests);
esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = {
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1,
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2,
};
ret = esp_efuse_write_keys(secure_boot_key_purpose, boot_key_digests.key_digests, boot_key_digests.num_digests);
if (ret) {
if (ret == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots.", boot_key_digests.num_digests);
} else {
ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", ret);
}
return ret;
}
/* Generate the application public key digests */
ret = s_calculate_image_public_key_digests(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_key_digests);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "App signature block is invalid.");
return ret;
}
if (app_key_digests.num_digests == 0) {
ESP_LOGE(TAG, "No valid applications signature blocks found.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "%d signature block(s) found appended to the app.", app_key_digests.num_digests);
if (app_key_digests.num_digests > boot_key_digests.num_digests) {
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?");
}
/* Confirm if at least one public key from the application matches a public key in the bootloader
(Also, ensure if that public revoke bit is not set for the matched key) */
bool match = false;
for (int i = 0; i < boot_key_digests.num_digests; i++) {
if (esp_efuse_get_digest_revoke(i)) {
ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
continue; // skip if the key block is revoked
}
for (int j = 0; j < app_key_digests.num_digests; j++) {
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
match = true;
}
}
}
if (match == false) {
ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
return ESP_FAIL;
}
/* Revoke the empty signature blocks */
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
/* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
for (uint8_t i = boot_key_digests.num_digests; i < SECURE_BOOT_NUM_BLOCKS; i++) {
ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
esp_efuse_set_digest_revoke(i);
}
}
}
return ESP_OK;
}
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
{
ESP_LOGI(TAG, "enabling secure boot v2...");
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "secure boot v2 is already enabled, continuing..");
return ESP_OK;
}
esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
esp_err_t key_state = check_and_generate_secure_boot_keys(image_data);
if (key_state != ESP_OK) {
esp_efuse_batch_write_cancel();
return key_state;
}
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
ESP_LOGI(TAG, "Enabling Security download mode...");
esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
#else
ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
esp_err_t err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
assert(ets_efuse_secure_boot_aggressive_revoke_enabled());
#endif
assert(esp_rom_efuse_is_secure_boot_enabled());
ESP_LOGI(TAG, "Secure boot permanently enabled");
return ESP_OK;
}

View File

@@ -30,6 +30,9 @@
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h" #include "esp32c3/rom/rtc.h"
#include "esp32c3/rom/secure_boot.h" #include "esp32c3/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/secure_boot.h"
#endif #endif
/* Checking signatures as part of verifying images is necessary: /* Checking signatures as part of verifying images is necessary:

View File

@@ -86,7 +86,7 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
uint8_t dis_dl_enc = 0; uint8_t dis_dl_enc = 0;
uint8_t dis_dl_icache = 0; uint8_t dis_dl_icache = 0;
uint8_t dis_dl_dcache = 0; uint8_t dis_dl_dcache = 0;
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
uint8_t dis_dl_enc = 0; uint8_t dis_dl_enc = 0;
uint8_t dis_dl_icache = 0; uint8_t dis_dl_icache = 0;
#endif #endif
@@ -123,7 +123,7 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
if (dis_dl_enc && dis_dl_icache && dis_dl_dcache) { if (dis_dl_enc && dis_dl_icache && dis_dl_dcache) {
mode = ESP_FLASH_ENC_MODE_RELEASE; mode = ESP_FLASH_ENC_MODE_RELEASE;
} }
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
dis_dl_enc = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT); dis_dl_enc = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
dis_dl_icache = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE); dis_dl_icache = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);

View File

@@ -13,6 +13,8 @@
#include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#else #else
#include "esp32/rom/spi_flash.h" #include "esp32/rom/spi_flash.h"
#endif #endif

View File

@@ -21,6 +21,8 @@
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h" #include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#endif #endif
#include "soc/efuse_periph.h" #include "soc/efuse_periph.h"
#include "soc/io_mux_reg.h" #include "soc/io_mux_reg.h"

View File

@@ -74,6 +74,15 @@ if(IDF_TARGET STREQUAL "esp32c3")
"esp32c3/rtc_tempsensor.c") "esp32c3/rtc_tempsensor.c")
endif() endif()
if(IDF_TARGET STREQUAL "esp32h2")
list(APPEND srcs "gdma.c"
"spi_slave_hd.c"
"adc_common.c"
"esp32h2/adc.c"
"esp32h2/adc2_init_cal.c"
"esp32h2/rtc_tempsensor.c")
endif()
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${includes} INCLUDE_DIRS ${includes}
PRIV_INCLUDE_DIRS "include/driver" PRIV_INCLUDE_DIRS "include/driver"

View File

@@ -0,0 +1,717 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "sys/lock.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "freertos/ringbuf.h"
#include "esp32h2/rom/ets_sys.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "hal/adc_types.h"
#include "hal/adc_hal.h"
#include "hal/dma_types.h"
#include "esp_efuse_rtc_calib.h"
#include "esp_private/gdma.h"
#define ADC_CHECK_RET(fun_ret) ({ \
if (fun_ret != ESP_OK) { \
ESP_LOGE(ADC_TAG,"%s(%d)",__FUNCTION__,__LINE__); \
return ESP_FAIL; \
} \
})
static const char *ADC_TAG = "ADC";
#define ADC_CHECK(a, str, ret_val) ({ \
if (!(a)) { \
ESP_LOGE(ADC_TAG,"%s(%d) :%s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
} \
})
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG)
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
/**
* 1. sar_adc1_lock: this mutex lock is to protect the SARADC1 module.
* 2. sar_adc2_lock: this mutex lock is to protect the SARADC2 module. On H2, it is controlled by the digital controller
* and PWDET controller.
* 3. adc_reg_lock: this spin lock is to protect the shared registers used by ADC1 / ADC2 single read mode.
*/
static _lock_t sar_adc1_lock;
#define SAR_ADC1_LOCK_ACQUIRE() _lock_acquire(&sar_adc1_lock)
#define SAR_ADC1_LOCK_RELEASE() _lock_release(&sar_adc1_lock)
static _lock_t sar_adc2_lock;
#define SAR_ADC2_LOCK_ACQUIRE() _lock_acquire(&sar_adc2_lock)
#define SAR_ADC2_LOCK_RELEASE() _lock_release(&sar_adc2_lock)
portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED;
#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock)
#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock)
#define INTERNAL_BUF_NUM 5
#define IN_SUC_EOF_BIT GDMA_LL_EVENT_RX_SUC_EOF
/*---------------------------------------------------------------
Digital Controller Context
---------------------------------------------------------------*/
typedef struct adc_digi_context_t {
uint8_t *rx_dma_buf; //dma buffer
adc_hal_context_t hal; //hal context
gdma_channel_handle_t rx_dma_channel; //dma rx channel handle
RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler
intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel
bool ringbuf_overflow_flag; //1: ringbuffer overflow
bool driver_start_flag; //1: driver is started; 0: driver is stoped
bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used.
bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not.
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
adc_digi_config_t digi_controller_config; //Digital Controller Configuration
esp_pm_lock_handle_t pm_lock; //For power management
} adc_digi_context_t;
static adc_digi_context_t *s_adc_digi_ctx = NULL;
static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t chan, adc_atten_t atten);
/*---------------------------------------------------------------
ADC Continuous Read Mode (via DMA)
---------------------------------------------------------------*/
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
static int8_t adc_digi_get_io_num(uint8_t adc_unit, uint8_t adc_channel)
{
return adc_channel_io_map[adc_unit][adc_channel];
}
static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
{
esp_err_t ret = ESP_OK;
uint64_t gpio_mask = 0;
uint32_t n = 0;
int8_t io = 0;
while (channel_mask) {
if (channel_mask & 0x1) {
io = adc_digi_get_io_num(adc_unit, n);
if (io < 0) {
return ESP_ERR_INVALID_ARG;
}
gpio_mask |= BIT64(io);
}
channel_mask = channel_mask >> 1;
n++;
}
gpio_config_t cfg = {
.pin_bit_mask = gpio_mask,
.mode = GPIO_MODE_DISABLE,
};
ret = gpio_config(&cfg);
return ret;
}
esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
{
esp_err_t ret = ESP_OK;
s_adc_digi_ctx = calloc(1, sizeof(adc_digi_context_t));
if (s_adc_digi_ctx == NULL) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//ringbuffer
s_adc_digi_ctx->ringbuf_hdl = xRingbufferCreate(init_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF);
if (!s_adc_digi_ctx->ringbuf_hdl) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc internal buffer used by DMA
s_adc_digi_ctx->rx_dma_buf = heap_caps_calloc(1, init_config->conv_num_each_intr * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL);
if (!s_adc_digi_ctx->rx_dma_buf) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc dma descriptor
s_adc_digi_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * INTERNAL_BUF_NUM, MALLOC_CAP_DMA);
if (!s_adc_digi_ctx->hal.rx_desc) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc pattern table
s_adc_digi_ctx->digi_controller_config.adc_pattern = calloc(1, SOC_ADC_PATT_LEN_MAX * sizeof(adc_digi_pattern_table_t));
if (!s_adc_digi_ctx->digi_controller_config.adc_pattern) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
#if CONFIG_PM_ENABLE
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &s_adc_digi_ctx->pm_lock);
if (ret != ESP_OK) {
goto cleanup;
}
#endif //CONFIG_PM_ENABLE
//init gpio pins
if (init_config->adc1_chan_mask) {
ret = adc_digi_gpio_init(ADC_NUM_1, init_config->adc1_chan_mask);
if (ret != ESP_OK) {
goto cleanup;
}
}
if (init_config->adc2_chan_mask) {
ret = adc_digi_gpio_init(ADC_NUM_2, init_config->adc2_chan_mask);
if (ret != ESP_OK) {
goto cleanup;
}
}
//alloc rx gdma channel
gdma_channel_alloc_config_t rx_alloc_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX,
};
ret = gdma_new_channel(&rx_alloc_config, &s_adc_digi_ctx->rx_dma_channel);
if (ret != ESP_OK) {
goto cleanup;
}
gdma_connect(s_adc_digi_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0));
gdma_strategy_config_t strategy_config = {
.auto_update_desc = true,
.owner_check = true
};
gdma_apply_strategy(s_adc_digi_ctx->rx_dma_channel, &strategy_config);
gdma_rx_event_callbacks_t cbs = {
.on_recv_eof = adc_dma_in_suc_eof_callback
};
gdma_register_rx_event_callbacks(s_adc_digi_ctx->rx_dma_channel, &cbs, s_adc_digi_ctx);
int dma_chan;
gdma_get_channel_id(s_adc_digi_ctx->rx_dma_channel, &dma_chan);
adc_hal_config_t config = {
.desc_max_num = INTERNAL_BUF_NUM,
.dma_chan = dma_chan,
.eof_num = init_config->conv_num_each_intr / ADC_HAL_DATA_LEN_PER_CONV
};
adc_hal_context_config(&s_adc_digi_ctx->hal, &config);
//enable SARADC module clock
periph_module_enable(PERIPH_SARADC_MODULE);
adc_hal_calibration_init(ADC_NUM_1);
adc_hal_calibration_init(ADC_NUM_2);
return ret;
cleanup:
adc_digi_deinitialize();
return ret;
}
static IRAM_ATTR bool adc_dma_intr(adc_digi_context_t *adc_digi_ctx);
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
assert(event_data);
adc_digi_context_t *adc_digi_ctx = (adc_digi_context_t *)user_data;
adc_digi_ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr;
return adc_dma_intr(adc_digi_ctx);
}
static IRAM_ATTR bool adc_dma_intr(adc_digi_context_t *adc_digi_ctx)
{
portBASE_TYPE taskAwoken = 0;
BaseType_t ret;
adc_hal_dma_desc_status_t status = false;
dma_descriptor_t *current_desc = NULL;
while (1) {
status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, &current_desc);
if (status != ADC_HAL_DMA_DESC_VALID) {
break;
}
ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, current_desc->buffer, current_desc->dw0.length, &taskAwoken);
if (ret == pdFALSE) {
//ringbuffer overflow
adc_digi_ctx->ringbuf_overflow_flag = 1;
}
}
if (status == ADC_HAL_DMA_DESC_NULL) {
//start next turns of dma operation
adc_hal_digi_rxdma_start(&adc_digi_ctx->hal, adc_digi_ctx->rx_dma_buf);
}
return (taskAwoken == pdTRUE);
}
esp_err_t adc_digi_start(void)
{
if (s_adc_digi_ctx->driver_start_flag != 0) {
ESP_LOGE(ADC_TAG, "The driver is already started");
return ESP_ERR_INVALID_STATE;
}
adc_power_acquire();
//reset flags
s_adc_digi_ctx->ringbuf_overflow_flag = 0;
s_adc_digi_ctx->driver_start_flag = 1;
if (s_adc_digi_ctx->use_adc1) {
SAR_ADC1_LOCK_ACQUIRE();
}
if (s_adc_digi_ctx->use_adc2) {
SAR_ADC2_LOCK_ACQUIRE();
}
#if CONFIG_PM_ENABLE
// Lock APB frequency while ADC driver is in use
esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock);
#endif
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
if (s_adc_digi_ctx->use_adc1) {
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc1_atten);
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
}
if (s_adc_digi_ctx->use_adc2) {
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_2, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc2_atten);
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
}
adc_hal_init();
adc_hal_arbiter_config(&config);
adc_hal_digi_init(&s_adc_digi_ctx->hal);
adc_hal_digi_controller_config(&s_adc_digi_ctx->digi_controller_config);
//reset ADC and DMA
adc_hal_fifo_reset(&s_adc_digi_ctx->hal);
//start DMA
adc_hal_digi_rxdma_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf);
//start ADC
adc_hal_digi_start(&s_adc_digi_ctx->hal);
return ESP_OK;
}
esp_err_t adc_digi_stop(void)
{
if (s_adc_digi_ctx->driver_start_flag != 1) {
ESP_LOGE(ADC_TAG, "The driver is already stopped");
return ESP_ERR_INVALID_STATE;
}
s_adc_digi_ctx->driver_start_flag = 0;
//disable the in suc eof intrrupt
adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, IN_SUC_EOF_BIT);
//clear the in suc eof interrupt
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, IN_SUC_EOF_BIT);
//stop ADC
adc_hal_digi_stop(&s_adc_digi_ctx->hal);
//stop DMA
adc_hal_digi_rxdma_stop(&s_adc_digi_ctx->hal);
adc_hal_digi_deinit();
#if CONFIG_PM_ENABLE
if (s_adc_digi_ctx->pm_lock) {
esp_pm_lock_release(s_adc_digi_ctx->pm_lock);
}
#endif //CONFIG_PM_ENABLE
if (s_adc_digi_ctx->use_adc1) {
SAR_ADC1_LOCK_RELEASE();
}
if (s_adc_digi_ctx->use_adc2) {
SAR_ADC2_LOCK_RELEASE();
}
adc_power_release();
return ESP_OK;
}
esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms)
{
TickType_t ticks_to_wait;
esp_err_t ret = ESP_OK;
uint8_t *data = NULL;
size_t size = 0;
ticks_to_wait = timeout_ms / portTICK_RATE_MS;
if (timeout_ms == ADC_MAX_DELAY) {
ticks_to_wait = portMAX_DELAY;
}
data = xRingbufferReceiveUpTo(s_adc_digi_ctx->ringbuf_hdl, &size, ticks_to_wait, length_max);
if (!data) {
ESP_LOGV(ADC_TAG, "No data, increase timeout or reduce conv_num_each_intr");
ret = ESP_ERR_TIMEOUT;
*out_length = 0;
return ret;
}
memcpy(buf, data, size);
vRingbufferReturnItem(s_adc_digi_ctx->ringbuf_hdl, data);
assert((size % 4) == 0);
*out_length = size;
if (s_adc_digi_ctx->ringbuf_overflow_flag) {
ret = ESP_ERR_INVALID_STATE;
}
return ret;
}
esp_err_t adc_digi_deinitialize(void)
{
if (!s_adc_digi_ctx) {
return ESP_ERR_INVALID_STATE;
}
if (s_adc_digi_ctx->driver_start_flag != 0) {
ESP_LOGE(ADC_TAG, "The driver is not stopped");
return ESP_ERR_INVALID_STATE;
}
if (s_adc_digi_ctx->ringbuf_hdl) {
vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl);
s_adc_digi_ctx->ringbuf_hdl = NULL;
}
#if CONFIG_PM_ENABLE
if (s_adc_digi_ctx->pm_lock) {
esp_pm_lock_delete(s_adc_digi_ctx->pm_lock);
}
#endif //CONFIG_PM_ENABLE
free(s_adc_digi_ctx->rx_dma_buf);
free(s_adc_digi_ctx->hal.rx_desc);
free(s_adc_digi_ctx->digi_controller_config.adc_pattern);
gdma_disconnect(s_adc_digi_ctx->rx_dma_channel);
gdma_del_channel(s_adc_digi_ctx->rx_dma_channel);
free(s_adc_digi_ctx);
s_adc_digi_ctx = NULL;
periph_module_disable(PERIPH_SARADC_MODULE);
return ESP_OK;
}
/*---------------------------------------------------------------
ADC Single Read Mode
---------------------------------------------------------------*/
static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API
static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
{
esp_err_t ret;
uint32_t channel = ADC2_CHANNEL_MAX;
if (adc_unit == ADC_UNIT_2) {
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
if (gpio == ADC_GET_IO_NUM(ADC_NUM_2, i)) {
channel = i;
break;
}
}
if (channel == ADC2_CHANNEL_MAX) {
return ESP_ERR_INVALID_ARG;
}
}
adc_power_acquire();
if (adc_unit & ADC_UNIT_1) {
ADC_ENTER_CRITICAL();
adc_hal_vref_output(ADC_NUM_1, channel, true);
ADC_EXIT_CRITICAL()
} else if (adc_unit & ADC_UNIT_2) {
ADC_ENTER_CRITICAL();
adc_hal_vref_output(ADC_NUM_2, channel, true);
ADC_EXIT_CRITICAL()
}
ret = adc_digi_gpio_init(ADC_NUM_2, BIT(channel));
return ret;
}
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
{
//On ESP32H2, the data width is always 12-bits.
if (width_bit != ADC_WIDTH_BIT_12) {
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
{
ADC_CHANNEL_CHECK(ADC_NUM_1, channel);
ADC_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
s_atten1_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_NUM_1, BIT(channel));
adc_hal_calibration_init(ADC_NUM_1);
return ret;
}
int adc1_get_raw(adc1_channel_t channel)
{
int raw_out = 0;
periph_module_enable(PERIPH_SARADC_MODULE);
adc_power_acquire();
SAR_ADC1_LOCK_ACQUIRE();
adc_atten_t atten = s_atten1_single[channel];
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, channel, atten);
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
ADC_REG_LOCK_ENTER();
adc_hal_set_atten(ADC_NUM_2, channel, atten);
adc_hal_convert(ADC_NUM_1, channel, &raw_out);
ADC_REG_LOCK_EXIT();
SAR_ADC1_LOCK_RELEASE();
adc_power_release();
periph_module_disable(PERIPH_SARADC_MODULE);
return raw_out;
}
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
{
ADC_CHANNEL_CHECK(ADC_NUM_2, channel);
ADC_CHECK(atten <= ADC_ATTEN_11db, "ADC2 Atten Err", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
s_atten2_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_NUM_2, BIT(channel));
adc_hal_calibration_init(ADC_NUM_2);
return ret;
}
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
{
//On ESP32H2, the data width is always 12-bits.
if (width_bit != ADC_WIDTH_BIT_12) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
periph_module_enable(PERIPH_SARADC_MODULE);
adc_power_acquire();
SAR_ADC2_LOCK_ACQUIRE();
adc_atten_t atten = s_atten2_single[channel];
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_2, channel, atten);
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
ADC_REG_LOCK_ENTER();
adc_hal_set_atten(ADC_NUM_2, channel, atten);
ret = adc_hal_convert(ADC_NUM_2, channel, raw_out);
ADC_REG_LOCK_EXIT();
SAR_ADC2_LOCK_RELEASE();
adc_power_release();
periph_module_disable(PERIPH_SARADC_MODULE);
return ret;
}
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
{
if (!s_adc_digi_ctx) {
return ESP_ERR_INVALID_STATE;
}
ADC_CHECK(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, "ADC sampling frequency out of range", ESP_ERR_INVALID_ARG);
s_adc_digi_ctx->digi_controller_config.conv_limit_en = config->conv_limit_en;
s_adc_digi_ctx->digi_controller_config.conv_limit_num = config->conv_limit_num;
s_adc_digi_ctx->digi_controller_config.adc_pattern_len = config->adc_pattern_len;
s_adc_digi_ctx->digi_controller_config.sample_freq_hz = config->sample_freq_hz;
memcpy(s_adc_digi_ctx->digi_controller_config.adc_pattern, config->adc_pattern, config->adc_pattern_len * sizeof(adc_digi_pattern_table_t));
const int atten_uninitialised = 999;
s_adc_digi_ctx->adc1_atten = atten_uninitialised;
s_adc_digi_ctx->adc2_atten = atten_uninitialised;
s_adc_digi_ctx->use_adc1 = 0;
s_adc_digi_ctx->use_adc2 = 0;
for (int i = 0; i < config->adc_pattern_len; i++) {
const adc_digi_pattern_table_t *pat = &config->adc_pattern[i];
if (pat->unit == ADC_NUM_1) {
s_adc_digi_ctx->use_adc1 = 1;
if (s_adc_digi_ctx->adc1_atten == atten_uninitialised) {
s_adc_digi_ctx->adc1_atten = pat->atten;
} else if (s_adc_digi_ctx->adc1_atten != pat->atten) {
return ESP_ERR_INVALID_ARG;
}
} else if (pat->unit == ADC_NUM_2) {
//See whether ADC2 will be used or not. If yes, the ``sar_adc2_mutex`` should be acquired in the continuous read driver
s_adc_digi_ctx->use_adc2 = 1;
if (s_adc_digi_ctx->adc2_atten == atten_uninitialised) {
s_adc_digi_ctx->adc2_atten = pat->atten;
} else if (s_adc_digi_ctx->adc2_atten != pat->atten) {
return ESP_ERR_INVALID_ARG;
}
}
}
return ESP_OK;
}
/*************************************/
/* Digital controller filter setting */
/*************************************/
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_filter_reset(idx);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_filter_set_factor(idx, config);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_filter_get_factor(idx, config);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_filter_enable(idx, enable);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
/**************************************/
/* Digital controller monitor setting */
/**************************************/
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_monitor_config(idx, config);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable)
{
ADC_ENTER_CRITICAL();
adc_hal_digi_monitor_enable(idx, enable);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
static uint16_t s_adc_cali_param[ADC_UNIT_MAX][ADC_ATTEN_MAX] = {};
//NOTE: according to calibration version, different types of lock may be taken during the process:
// 1. Semaphore when reading efuse
// 2. Lock (Spinlock, or Mutex) if we actually do ADC calibration in the future
//This function shoudn't be called inside critical section or ISR
static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
const bool no_cal = false;
if (s_adc_cali_param[adc_n][atten]) {
return (uint32_t)s_adc_cali_param[adc_n][atten];
}
if (no_cal) {
return 0; //indicating failure
}
// check if we can fetch the values from eFuse.
int version = esp_efuse_rtc_calib_get_ver();
uint32_t init_code = 0;
if (version == 1) {
//for calibration v1, both ADC units use the same init code (calibrated by ADC1)
init_code = esp_efuse_rtc_calib_get_init_code(version, atten);
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC0, 1 atten=%d: %04X", version, atten, init_code);
s_adc_cali_param[0][atten] = init_code;
s_adc_cali_param[1][atten] = init_code;
} else {
adc_power_acquire();
ADC_ENTER_CRITICAL();
const bool internal_gnd = true;
init_code = adc_hal_self_calibration(adc_n, channel, atten, internal_gnd);
ADC_EXIT_CRITICAL();
adc_power_release();
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code);
s_adc_cali_param[adc_n][atten] = init_code;
}
return init_code;
}
// Internal function to calibrate PWDET for WiFi
esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
adc_hal_calibration_init(adc_n);
uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten);
ADC_ENTER_CRITICAL();
adc_hal_set_calibration_param(adc_n, cal_val);
ADC_EXIT_CRITICAL();
return ESP_OK;
}

View File

@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* This file is used to get `adc2_init_code_calibration` executed before the APP when the ADC2 is used by Wi-Fi or other drivers.
The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used.
Don't put any other code into this file. */
#include "adc2_wifi_private.h"
#include "hal/adc_hal.h"
#include "esp_private/adc_cali.h"
/**
* @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code.
* This API be called in before `app_main()`.
*/
static __attribute__((constructor)) void adc2_init_code_calibration(void)
{
const adc_ll_num_t adc_n = ADC_NUM_2;
const adc_atten_t atten = ADC_ATTEN_DB_11;
const adc_channel_t channel = 0;
adc_cal_offset(adc_n, channel, atten);
}
/** Don't call `adc2_cal_include` in user code. */
void adc2_cal_include(void)
{
/* When this empty function is called, the `adc2_init_code_calibration` constructor will be linked and executed before the app.*/
}

View File

@@ -0,0 +1,93 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "driver/adc_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/*************************************/
/* Digital controller filter setting */
/*************************************/
/**
* @brief Reset adc digital controller filter.
*
* @param idx Filter index.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx);
/**
* @brief Set adc digital controller filter configuration.
*
* @param idx Filter index.
* @param config See ``adc_digi_filter_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
/**
* @brief Get adc digital controller filter configuration.
*
* @param idx Filter index.
* @param config See ``adc_digi_filter_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
/**
* @brief Enable/disable adc digital controller filter.
* Filtering the ADC data to obtain smooth data at higher sampling rates.
*
* @param idx Filter index.
* @param enable Enable/Disable filter.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable);
/**************************************/
/* Digital controller monitor setting */
/**************************************/
/**
* @brief Config monitor of adc digital controller.
*
* @param idx Monitor index.
* @param config See ``adc_digi_monitor_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config);
/**
* @brief Enable/disable monitor of adc digital controller.
*
* @param idx Monitor index.
* @param enable True or false enable monitor.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TSENS_DAC_L0 = 0, /*!< offset = -2, measure range: 50℃ ~ 125℃, error < 3℃. */
TSENS_DAC_L1, /*!< offset = -1, measure range: 20℃ ~ 100℃, error < 2℃. */
TSENS_DAC_L2, /*!< offset = 0, measure range:-10℃ ~ 80℃, error < 1℃. */
TSENS_DAC_L3, /*!< offset = 1, measure range:-30℃ ~ 50℃, error < 2℃. */
TSENS_DAC_L4, /*!< offset = 2, measure range:-40℃ ~ 20℃, error < 3℃. */
TSENS_DAC_MAX,
TSENS_DAC_DEFAULT = TSENS_DAC_L2,
} temp_sensor_dac_offset_t;
/**
* @brief Configuration for temperature sensor reading
*/
typedef struct {
temp_sensor_dac_offset_t dac_offset; /*!< The temperature measurement range is configured with a built-in temperature offset DAC. */
uint8_t clk_div; /*!< Default: 6 */
} temp_sensor_config_t;
#define TSENS_CONFIG_DEFAULT() {.dac_offset = TSENS_DAC_L2, \
.clk_div = 6}
/**
* @brief Set parameter of temperature sensor.
* @param tsens
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens);
/**
* @brief Get parameter of temperature sensor.
* @param tsens
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens);
/**
* @brief Start temperature sensor measure.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG
*/
esp_err_t temp_sensor_start(void);
/**
* @brief Stop temperature sensor measure.
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_stop(void);
/**
* @brief Read temperature sensor raw data.
* @param tsens_out Pointer to raw data, Range: 0 ~ 255
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG `tsens_out` is NULL
* - ESP_ERR_INVALID_STATE temperature sensor dont start
*/
esp_err_t temp_sensor_read_raw(uint32_t *tsens_out);
/**
* @brief Read temperature sensor data that is converted to degrees Celsius.
* @note Should not be called from interrupt.
* @param celsius The measure output value.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG ARG is NULL.
* - ESP_ERR_INVALID_STATE The ambient temperature is out of range.
*/
esp_err_t temp_sensor_read_celsius(float *celsius);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "hal/adc_ll.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/apb_saradc_struct.h"
#include "soc/apb_saradc_reg.h"
#include "soc/system_reg.h"
#include "driver/temp_sensor.h"
#include "regi2c_ctrl.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp_efuse_rtc_calib.h"
static const char *TAG = "tsens";
#define TSENS_CHECK(res, ret_val) ({ \
if (!(res)) { \
ESP_LOGE(TAG, "%s(%d)", __FUNCTION__, __LINE__); \
return (ret_val); \
} \
})
#define TSENS_XPD_WAIT_DEFAULT 0xFF /* Set wait cycle time(8MHz) from power up to reset enable. */
#define TSENS_ADC_FACTOR (0.4386)
#define TSENS_DAC_FACTOR (27.88)
#define TSENS_SYS_OFFSET (20.52)
typedef struct {
int index;
int offset;
int set_val;
int range_min;
int range_max;
int error_max;
} tsens_dac_offset_t;
static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
/* DAC Offset reg_val min max error */
{TSENS_DAC_L0, -2, 5, 50, 125, 3},
{TSENS_DAC_L1, -1, 7, 20, 100, 2},
{TSENS_DAC_L2, 0, 15, -10, 80, 1},
{TSENS_DAC_L3, 1, 11, -30, 50, 2},
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
};
static float s_deltaT = NAN; // unused number
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
{
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PD);
SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PU);
REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_TSENS_DAC, dac_offset[tsens.dac_offset].set_val);
APB_SARADC.apb_tsens_ctrl.tsens_clk_div = tsens.clk_div;
APB_SARADC.apb_tsens_ctrl2.tsens_xpd_wait = TSENS_XPD_WAIT_DEFAULT;
APB_SARADC.apb_tsens_ctrl2.tsens_xpd_force = 1;
ESP_LOGD(TAG, "Config temperature range [%d°C ~ %d°C], error < %d°C",
dac_offset[tsens.dac_offset].range_min,
dac_offset[tsens.dac_offset].range_max,
dac_offset[tsens.dac_offset].error_max);
return ESP_OK;
}
esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
{
TSENS_CHECK(tsens != NULL, ESP_ERR_INVALID_ARG);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PD);
SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PU);
tsens->dac_offset = REGI2C_READ_MASK(I2C_SAR_ADC, I2C_SARADC_TSENS_DAC);
for (int i = TSENS_DAC_L0; i < TSENS_DAC_MAX; i++) {
if (tsens->dac_offset == dac_offset[i].set_val) {
tsens->dac_offset = dac_offset[i].index;
break;
}
}
tsens->clk_div = APB_SARADC.apb_tsens_ctrl.tsens_clk_div;
return ESP_OK;
}
esp_err_t temp_sensor_start(void)
{
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 1;
APB_SARADC.apb_tsens_ctrl.tsens_pu = 1;
return ESP_OK;
}
esp_err_t temp_sensor_stop(void)
{
APB_SARADC.apb_tsens_ctrl.tsens_pu = 0;
APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 0;
return ESP_OK;
}
esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
{
TSENS_CHECK(tsens_out != NULL, ESP_ERR_INVALID_ARG);
*tsens_out = APB_SARADC.apb_tsens_ctrl.tsens_out;
return ESP_OK;
}
static void read_delta_t_from_efuse(void)
{
uint32_t version = esp_efuse_rtc_calib_get_ver();
if (version == 1) {
// fetch calibration value for temp sensor from eFuse
s_deltaT = esp_efuse_rtc_calib_get_cal_temp(version);
} else {
// no value to fetch, use 0.
s_deltaT = 0;
}
ESP_LOGD(TAG, "s_deltaT = %f", s_deltaT);
}
static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const int dac_offset)
{
if (isnan(s_deltaT)) { //suggests that the value is not initialized
read_delta_t_from_efuse();
}
float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac_offset - TSENS_SYS_OFFSET) - s_deltaT / 10.0;
return result;
}
esp_err_t temp_sensor_read_celsius(float *celsius)
{
TSENS_CHECK(celsius != NULL, ESP_ERR_INVALID_ARG);
temp_sensor_config_t tsens;
uint32_t tsens_out = 0;
esp_err_t ret = temp_sensor_get_config(&tsens);
if (ret == ESP_OK) {
ret = temp_sensor_read_raw(&tsens_out);
printf("tsens_out %d\r\n", tsens_out);
TSENS_CHECK(ret == ESP_OK, ret);
const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset];
*celsius = parse_temp_sensor_raw_value(tsens_out, dac->offset);
if (*celsius < dac->range_min || *celsius > dac->range_max) {
ESP_LOGW(TAG, "Exceeding the temperature range!");
ret = ESP_ERR_INVALID_STATE;
}
}
return ret;
}

View File

@@ -35,7 +35,7 @@ esp_err_t adc2_wifi_acquire(void);
*/ */
esp_err_t adc2_wifi_release(void); esp_err_t adc2_wifi_release(void);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/** /**
* @brief This API help ADC2 calibration constructor be linked. * @brief This API help ADC2 calibration constructor be linked.
* *

View File

@@ -45,7 +45,7 @@ typedef enum {
ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 */ ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 */
ADC1_CHANNEL_MAX, ADC1_CHANNEL_MAX,
} adc1_channel_t; } adc1_channel_t;
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ /**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum { typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */ ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */
@@ -72,7 +72,7 @@ typedef enum {
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */ ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
ADC2_CHANNEL_MAX, ADC2_CHANNEL_MAX,
} adc2_channel_t; } adc2_channel_t;
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ /**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum { typedef enum {
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */ ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */
@@ -103,7 +103,7 @@ typedef enum {
#define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11 #define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11
#define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12 #define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/** /**
* @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports * @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports
*/ */
@@ -121,7 +121,7 @@ typedef enum {
ADC_ENCODE_MAX, ADC_ENCODE_MAX,
} adc_i2s_encode_t; } adc_i2s_encode_t;
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
//This feature is currently supported on ESP32C3, will be supported on other chips soon //This feature is currently supported on ESP32C3, will be supported on other chips soon
/** /**
* @brief Digital ADC DMA configuration * @brief Digital ADC DMA configuration
@@ -167,7 +167,7 @@ void adc_power_acquire(void);
*/ */
void adc_power_release(void); void adc_power_release(void);
#if !CONFIG_IDF_TARGET_ESP32C3 #if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
/** /**
* @brief Initialize ADC pad * @brief Initialize ADC pad
* @param adc_unit ADC unit index * @param adc_unit ADC unit index
@@ -177,7 +177,7 @@ void adc_power_release(void);
* - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_ARG Parameter error
*/ */
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel); esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
#endif //#if !CONFIG_IDF_TARGET_ESP32C3 #endif //#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
/*--------------------------------------------------------------- /*---------------------------------------------------------------
ADC Single Read Setting ADC Single Read Setting
@@ -276,7 +276,7 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit);
*/ */
int adc1_get_raw(adc1_channel_t channel); int adc1_get_raw(adc1_channel_t channel);
#if !CONFIG_IDF_TARGET_ESP32C3 #if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
/** /**
* @brief Set ADC data invert * @brief Set ADC data invert
* @param adc_unit ADC unit index * @param adc_unit ADC unit index
@@ -317,7 +317,7 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
* to be called to configure ADC1 channels, before ADC1 is used by the ULP. * to be called to configure ADC1 channels, before ADC1 is used by the ULP.
*/ */
void adc1_ulp_enable(void); void adc1_ulp_enable(void);
#endif //#if !CONFIG_IDF_TARGET_ESP32C3 #endif //#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
/** /**
* @brief Get the GPIO number of a specific ADC2 channel. * @brief Get the GPIO number of a specific ADC2 channel.
@@ -477,7 +477,7 @@ esp_err_t adc_digi_deinit(void);
*/ */
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config); esp_err_t adc_digi_controller_config(const adc_digi_config_t *config);
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
//This feature is currently supported on ESP32C3, will be supported on other chips soon //This feature is currently supported on ESP32C3, will be supported on other chips soon
/*--------------------------------------------------------------- /*---------------------------------------------------------------
DMA setting DMA setting
@@ -537,7 +537,7 @@ esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_l
*/ */
esp_err_t adc_digi_deinitialize(void); esp_err_t adc_digi_deinitialize(void);
#endif //#if CONFIG_IDF_TARGET_ESP32C3 #endif //#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -33,6 +33,8 @@
#include "esp32c3/rom/gpio.h" #include "esp32c3/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/gpio.h" #include "esp32s3/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/gpio.h"
#endif #endif
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS #ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS

View File

@@ -42,6 +42,7 @@ void periph_module_reset(periph_module_t periph)
portEXIT_CRITICAL_SAFE(&periph_spinlock); portEXIT_CRITICAL_SAFE(&periph_spinlock);
} }
#if CONFIG_ESP32_WIFI_ENABLED
IRAM_ATTR void wifi_bt_common_module_enable(void) IRAM_ATTR void wifi_bt_common_module_enable(void)
{ {
portENTER_CRITICAL_SAFE(&periph_spinlock); portENTER_CRITICAL_SAFE(&periph_spinlock);
@@ -71,3 +72,4 @@ void wifi_module_disable(void)
{ {
periph_ll_wifi_module_disable_clk_set_rst(); periph_ll_wifi_module_disable_clk_set_rst();
} }
#endif // CONFIG_ESP32_WIFI_ENABLED

View File

@@ -32,6 +32,8 @@
#include "esp32s3/clk.h" #include "esp32s3/clk.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/clk.h" #include "esp32c3/clk.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/clk.h"
#endif #endif
#ifdef CONFIG_UART_ISR_IN_IRAM #ifdef CONFIG_UART_ISR_IN_IRAM

View File

@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2017-2021 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 "esp32h2/rom/efuse.h"
#include "assert.h"
#include "esp_err.h"
#include "esp_log.h"
#include "soc/efuse_periph.h"
#include "bootloader_random.h"
#include "sys/param.h"
static __attribute__((unused)) const char *TAG = "efuse";
// Contains functions that provide access to efuse fields which are often used in IDF.
// Returns chip version from efuse
uint8_t esp_efuse_get_chip_ver(void)
{
uint32_t chip_ver = 0;
esp_efuse_read_field_blob(ESP_EFUSE_WAFER_VERSION, &chip_ver, ESP_EFUSE_WAFER_VERSION[0]->bit_count);
return chip_ver;
}
// 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,89 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_bit_defs.h>
#include "esp_efuse.h"
#include "esp_efuse_table.h"
int esp_efuse_rtc_calib_get_ver(void)
{
uint32_t result = 0;
esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &result, 3);
return result;
}
uint16_t esp_efuse_rtc_calib_get_init_code(int version, int atten)
{
assert(version == 1);
const esp_efuse_desc_t** init_code_efuse;
assert(atten < 4);
if (atten == 0) {
init_code_efuse = ESP_EFUSE_ADC1_INIT_CODE_ATTEN0;
} else if (atten == 1) {
init_code_efuse = ESP_EFUSE_ADC1_INIT_CODE_ATTEN1;
} else if (atten == 2) {
init_code_efuse = ESP_EFUSE_ADC1_INIT_CODE_ATTEN2;
} else {
init_code_efuse = ESP_EFUSE_ADC1_INIT_CODE_ATTEN3;
}
int init_code_size = esp_efuse_get_field_size(init_code_efuse);
assert(init_code_size == 10);
uint32_t init_code = 0;
ESP_ERROR_CHECK(esp_efuse_read_field_blob(init_code_efuse, &init_code, init_code_size));
return init_code + 1000; // version 1 logic
}
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv)
{
const esp_efuse_desc_t** cal_vol_efuse;
uint32_t calib_vol_expected_mv;
if (version != 1) {
return ESP_ERR_INVALID_ARG;
}
if (atten >= 4) {
return ESP_ERR_INVALID_ARG;
}
if (atten == 0) {
cal_vol_efuse = ESP_EFUSE_ADC1_CAL_VOL_ATTEN0;
calib_vol_expected_mv = 400;
} else if (atten == 1) {
cal_vol_efuse = ESP_EFUSE_ADC1_CAL_VOL_ATTEN1;
calib_vol_expected_mv = 550;
} else if (atten == 2) {
cal_vol_efuse = ESP_EFUSE_ADC1_CAL_VOL_ATTEN2;
calib_vol_expected_mv = 750;
} else {
cal_vol_efuse = ESP_EFUSE_ADC1_CAL_VOL_ATTEN3;
calib_vol_expected_mv = 1370;
}
assert(cal_vol_efuse[0]->bit_count == 10);
uint32_t cal_vol = 0;
ESP_ERROR_CHECK(esp_efuse_read_field_blob(cal_vol_efuse, &cal_vol, cal_vol_efuse[0]->bit_count));
*out_digi = 2000 + ((cal_vol & BIT(9))? -(cal_vol & ~BIT9): cal_vol);
*out_vol_mv = calib_vol_expected_mv;
return ESP_OK;
}
float esp_efuse_rtc_calib_get_cal_temp(int version)
{
assert(version == 1);
const esp_efuse_desc_t** cal_temp_efuse;
cal_temp_efuse = ESP_EFUSE_TEMP_CALIB;
int cal_temp_size = esp_efuse_get_field_size(cal_temp_efuse);
assert(cal_temp_size == 9);
uint32_t cal_temp = 0;
esp_err_t err = esp_efuse_read_field_blob(cal_temp_efuse, &cal_temp, cal_temp_size);
assert(err == ESP_OK);
(void)err;
// BIT(8) stands for sign: 1: negtive, 0: positive
return ((cal_temp & BIT(8)) != 0)? -(uint8_t)cal_temp: (uint8_t)cal_temp;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,165 @@
# field_name, | efuse_block, | bit_start, | bit_count, |comment #
# | (EFUSE_BLK0 | (0..255) | (1..-) | #
# | EFUSE_BLK1 | |MAX_BLK_LEN*| #
# | ... | | | #
# | EFUSE_BLK10)| | | #
##########################################################################
# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128.
# !!!!!!!!!!! #
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
# this will generate new source files, next rebuild all the sources.
# !!!!!!!!!!! #
# ESP32H2-TODO: IDF-3390
# EFUSE_RD_REPEAT_DATA BLOCK #
##############################
# EFUSE_RD_WR_DIS_REG #
WR_DIS, EFUSE_BLK0, 0, 32, Write protection
WR_DIS.RD_DIS, EFUSE_BLK0, 0, 1, Write protection for RD_DIS_KEY0 RD_DIS_KEY1 RD_DIS_KEY2 RD_DIS_KEY3 RD_DIS_KEY4 RD_DIS_KEY5 RD_DIS_SYS_DATA_PART2
WR_DIS.GROUP_1, EFUSE_BLK0, 2, 1, Write protection for DIS_ICACHE DIS_DOWNLOAD_ICACHE DIS_FORCE_DOWNLOAD DIS_USB DIS_CAN SOFT_DIS_JTAG DIS_DOWNLOAD_MANUAL_ENCRYPT
WR_DIS.GROUP_2, EFUSE_BLK0, 3, 1, Write protection for WDT_DELAY_SEL
WR_DIS.SPI_BOOT_CRYPT_CNT, EFUSE_BLK0, 4, 1, Write protection for SPI_BOOT_CRYPT_CNT
WR_DIS.SECURE_BOOT_KEY_REVOKE0,EFUSE_BLK0, 5, 1, Write protection for SECURE_BOOT_KEY_REVOKE0
WR_DIS.SECURE_BOOT_KEY_REVOKE1,EFUSE_BLK0, 6, 1, Write protection for SECURE_BOOT_KEY_REVOKE1
WR_DIS.SECURE_BOOT_KEY_REVOKE2,EFUSE_BLK0, 7, 1, Write protection for SECURE_BOOT_KEY_REVOKE2
WR_DIS.KEY0_PURPOSE, EFUSE_BLK0, 8, 1, Write protection for key_purpose. KEY0
WR_DIS.KEY1_PURPOSE, EFUSE_BLK0, 9, 1, Write protection for key_purpose. KEY1
WR_DIS.KEY2_PURPOSE, EFUSE_BLK0, 10, 1, Write protection for key_purpose. KEY2
WR_DIS.KEY3_PURPOSE, EFUSE_BLK0, 11, 1, Write protection for key_purpose. KEY3
WR_DIS.KEY4_PURPOSE, EFUSE_BLK0, 12, 1, Write protection for key_purpose. KEY4
WR_DIS.KEY5_PURPOSE, EFUSE_BLK0, 13, 1, Write protection for key_purpose. KEY5
WR_DIS.SECURE_BOOT_EN, EFUSE_BLK0, 15, 1, Write protection for SECURE_BOOT_EN
WR_DIS.SECURE_BOOT_AGGRESSIVE_REVOKE,EFUSE_BLK0, 16, 1, Write protection for SECURE_BOOT_AGGRESSIVE_REVOKE
WR_DIS.GROUP_3, EFUSE_BLK0, 18, 1, Write protection for FLASH_TPUW DIS_DOWNLOAD_MODE DIS_LEGACY_SPI_BOOT UART_PRINT_CHANNEL DIS_TINY_BASIC DIS_USB_DOWNLOAD_MODE ENABLE_SECURITY_DOWNLOAD UART_PRINT_CONTROL PIN_POWER_SELECTION FLASH_TYPE FORCE_SEND_RESUME SECURE_VERSION
WR_DIS.BLK1, EFUSE_BLK0, 20, 1, Write protection for EFUSE_BLK1. MAC_SPI_8M_SYS
WR_DIS.SYS_DATA_PART1, EFUSE_BLK0, 21, 1, Write protection for EFUSE_BLK2. SYS_DATA_PART1
WR_DIS.USER_DATA, EFUSE_BLK0, 22, 1, Write protection for EFUSE_BLK3. USER_DATA
WR_DIS.KEY0, EFUSE_BLK0, 23, 1, Write protection for EFUSE_BLK4. KEY0
WR_DIS.KEY1, EFUSE_BLK0, 24, 1, Write protection for EFUSE_BLK5. KEY1
WR_DIS.KEY2, EFUSE_BLK0, 25, 1, Write protection for EFUSE_BLK6. KEY2
WR_DIS.KEY3, EFUSE_BLK0, 26, 1, Write protection for EFUSE_BLK7. KEY3
WR_DIS.KEY4, EFUSE_BLK0, 27, 1, Write protection for EFUSE_BLK8. KEY4
WR_DIS.KEY5, EFUSE_BLK0, 28, 1, Write protection for EFUSE_BLK9. KEY5
WR_DIS.SYS_DATA_PART2, EFUSE_BLK0, 29, 1, Write protection for EFUSE_BLK10. SYS_DATA_PART2
# EFUSE_RD_REPEAT_DATA0_REG #
RD_DIS, EFUSE_BLK0, 32, 7, Read protection
RD_DIS.KEY0, EFUSE_BLK0, 32, 1, Read protection for EFUSE_BLK4. KEY0
RD_DIS.KEY1, EFUSE_BLK0, 33, 1, Read protection for EFUSE_BLK5. KEY1
RD_DIS.KEY2, EFUSE_BLK0, 34, 1, Read protection for EFUSE_BLK6. KEY2
RD_DIS.KEY3, EFUSE_BLK0, 35, 1, Read protection for EFUSE_BLK7. KEY3
RD_DIS.KEY4, EFUSE_BLK0, 36, 1, Read protection for EFUSE_BLK8. KEY4
RD_DIS.KEY5, EFUSE_BLK0, 37, 1, Read protection for EFUSE_BLK9. KEY5
RD_DIS.SYS_DATA_PART2, EFUSE_BLK0, 38, 1, Read protection for EFUSE_BLK10. SYS_DATA_PART2
DIS_RTC_RAM_BOOT, EFUSE_BLK0, 39, 1, Disable boot from RTC RAM
DIS_ICACHE, EFUSE_BLK0, 40, 1, Disable Icache
DIS_USB_JTAG, EFUSE_BLK0, 41, 1, Disable USB JTAG
DIS_DOWNLOAD_ICACHE, EFUSE_BLK0, 42, 1, Disable Icache in download mode
DIS_USB_DEVICE, EFUSE_BLK0, 43, 1, Disable USB_DEVICE
DIS_FORCE_DOWNLOAD, EFUSE_BLK0, 44, 1, Disable force chip go to download mode function
DIS_USB, EFUSE_BLK0, 45, 1, Disable USB function
DIS_CAN, EFUSE_BLK0, 46, 1, Disable CAN function
JTAG_SEL_ENABLE, EFUSE_BLK0, 47, 1, Set this bit to enable selection between usb_to_jtag and pad_to_jtag through strapping gpio10 when both reg_dis_usb_jtag and reg_dis_pad_jtag are equal to 0.
SOFT_DIS_JTAG, EFUSE_BLK0, 48, 2, Set these bits to disable JTAG in the soft way (odd number 1 means disable). JTAG can be enabled in HMAC module.
DIS_PAD_JTAG, EFUSE_BLK0, 51, 1, Disable JTAG in the hard way. JTAG is disabled permanently.
DIS_DOWNLOAD_MANUAL_ENCRYPT, EFUSE_BLK0, 52, 1, Disable flash encryption when in download boot modes.
USB_DREFH, EFUSE_BLK0, 53, 2, Controls single-end input threshold vrefh 1.76 V to 2 V with step of 80 mV stored in eFuse.
USB_DREFL, EFUSE_BLK0, 55, 2, Controls single-end input threshold vrefl 0.8 V to 1.04 V with step of 80 mV stored in eFuse.
USB_EXCHG_PINS, EFUSE_BLK0, 57, 1, Exchange D+ D- pins
VDD_SPI_AS_GPIO, EFUSE_BLK0, 58, 1, Set this bit to vdd spi pin function as gpio
BTLC_GPIO_ENABLE, EFUSE_BLK0, 59, 2, Enable btlc gpio
POWERGLITCH_EN, EFUSE_BLK0, 61, 1, Set this bit to enable power glitch function
POWER_GLITCH_DSENSE, EFUSE_BLK0, 62, 2, Sample delay configuration of power glitch
# EFUSE_RD_REPEAT_DATA1_REG #
WDT_DELAY_SEL, EFUSE_BLK0, 80, 2, Select RTC WDT time out threshold
SPI_BOOT_CRYPT_CNT, EFUSE_BLK0, 82, 3, SPI boot encrypt decrypt enable. odd number 1 enable. even number 1 disable
SECURE_BOOT_KEY_REVOKE0, EFUSE_BLK0, 85, 1, Enable revoke first secure boot key
SECURE_BOOT_KEY_REVOKE1, EFUSE_BLK0, 86, 1, Enable revoke second secure boot key
SECURE_BOOT_KEY_REVOKE2, EFUSE_BLK0, 87, 1, Enable revoke third secure boot key
KEY_PURPOSE_0, EFUSE_BLK0, 88, 4, Key0 purpose
KEY_PURPOSE_1, EFUSE_BLK0, 92, 4, Key1 purpose
# EFUSE_RD_REPEAT_DATA2_REG #
KEY_PURPOSE_2, EFUSE_BLK0, 96, 4, Key2 purpose
KEY_PURPOSE_3, EFUSE_BLK0, 100, 4, Key3 purpose
KEY_PURPOSE_4, EFUSE_BLK0, 104, 4, Key4 purpose
KEY_PURPOSE_5, EFUSE_BLK0, 108, 4, Key5 purpose
SECURE_BOOT_EN, EFUSE_BLK0, 116, 1, Secure boot enable
SECURE_BOOT_AGGRESSIVE_REVOKE, EFUSE_BLK0, 117, 1, Enable aggressive secure boot revoke
FLASH_TPUW, EFUSE_BLK0, 124, 4, Flash wait time after power up. (unit is ms). When value is 15. the time is 30 ms
# EFUSE_RD_REPEAT_DATA3_REG #
DIS_DOWNLOAD_MODE, EFUSE_BLK0, 128, 1, Disble download mode include boot_mode[3:0] is 0 1 2 3 6 7
DIS_LEGACY_SPI_BOOT, EFUSE_BLK0, 129, 1, Disable_Legcy_SPI_boot mode include boot_mode[3:0] is 4
UART_PRINT_CHANNEL, EFUSE_BLK0, 130, 1, 0: UART0. 1: UART1
FLASH_ECC_MODE, EFUSE_BLK0, 131, 1, Set this bit to set flsah ecc mode. 0:flash ecc 16to18 byte mode. 1:flash ecc 16to17 byte mode
DIS_USB_DOWNLOAD_MODE, EFUSE_BLK0, 132, 1, Disable download through USB
ENABLE_SECURITY_DOWNLOAD, EFUSE_BLK0, 133, 1, Enable security download mode
UART_PRINT_CONTROL, EFUSE_BLK0, 134, 2, b00:force print. b01:control by GPIO8 - low level print. b10:control by GPIO8 - high level print. b11:force disable print.
PIN_POWER_SELECTION, EFUSE_BLK0, 136, 1, GPIO33-GPIO37 power supply selection in ROM code. 0:VDD3P3_CPU. 1:VDD_SPI.
FLASH_TYPE, EFUSE_BLK0, 137, 1, Connected Flash interface type. 0: 4 data line. 1: 8 data line
FLASH_PAGE_SIZE, EFUSE_BLK0, 138, 2, Flash page size
FLASH_ECC_EN, EFUSE_BLK0, 140, 1, Enable ECC for flash boot
FORCE_SEND_RESUME, EFUSE_BLK0, 141, 1, Force ROM code to send a resume command during SPI boot
SECURE_VERSION, EFUSE_BLK0, 142, 16, Secure version for anti-rollback
# EFUSE_RD_REPEAT_DATA4_REG #
# MAC_SPI_SYS BLOCK#
#######################
MAC_FACTORY, EFUSE_BLK1, 40, 8, Factory MAC addr [0]
, EFUSE_BLK1, 32, 8, Factory MAC addr [1]
, EFUSE_BLK1, 24, 8, Factory MAC addr [2]
, EFUSE_BLK1, 16, 8, Factory MAC addr [3]
, EFUSE_BLK1, 8, 8, Factory MAC addr [4]
, EFUSE_BLK1, 0, 8, Factory MAC addr [5]
SPI_PAD_CONFIG_CLK, EFUSE_BLK1, 48, 6, SPI_PAD_configure CLK
SPI_PAD_CONFIG_Q_D1, EFUSE_BLK1, 54, 6, SPI_PAD_configure Q(D1)
SPI_PAD_CONFIG_D_D0, EFUSE_BLK1, 60, 6, SPI_PAD_configure D(D0)
SPI_PAD_CONFIG_CS, EFUSE_BLK1, 66, 6, SPI_PAD_configure CS
SPI_PAD_CONFIG_HD_D3, EFUSE_BLK1, 72, 6, SPI_PAD_configure HD(D3)
SPI_PAD_CONFIG_WP_D2, EFUSE_BLK1, 78, 6, SPI_PAD_configure WP(D2)
SPI_PAD_CONFIG_DQS, EFUSE_BLK1, 84, 6, SPI_PAD_configure DQS
SPI_PAD_CONFIG_D4, EFUSE_BLK1, 90, 6, SPI_PAD_configure D4
SPI_PAD_CONFIG_D5, EFUSE_BLK1, 96, 6, SPI_PAD_configure D5
SPI_PAD_CONFIG_D6, EFUSE_BLK1, 102, 6, SPI_PAD_configure D6
SPI_PAD_CONFIG_D7, EFUSE_BLK1, 108, 6, SPI_PAD_configure D7
WAFER_VERSION, EFUSE_BLK1, 114, 3, WAFER version
PKG_VERSION, EFUSE_BLK1, 117, 3, Package version 0:ESP32H2
BLOCK1_VERSION, EFUSE_BLK1, 120, 3, BLOCK1 efuse version
# SYS_DATA_PART1 BLOCK# - System configuration
#######################
OPTIONAL_UNIQUE_ID, EFUSE_BLK2, 0, 128, Optional unique 128-bit ID
BLOCK2_VERSION, EFUSE_BLK2, 128, 3, Version of BLOCK2
TEMP_CALIB, EFUSE_BLK2, 131, 9, Temperature calibration data
OCODE, EFUSE_BLK2, 140, 8, ADC OCode
ADC1_INIT_CODE_ATTEN0, EFUSE_BLK2, 148, 10, ADC1 init code at atten0
ADC1_INIT_CODE_ATTEN1, EFUSE_BLK2, 158, 10, ADC1 init code at atten1
ADC1_INIT_CODE_ATTEN2, EFUSE_BLK2, 168, 10, ADC1 init code at atten2
ADC1_INIT_CODE_ATTEN3, EFUSE_BLK2, 178, 10, ADC1 init code at atten3
ADC1_CAL_VOL_ATTEN0, EFUSE_BLK2, 188, 10, ADC1 calibration voltage at atten0
ADC1_CAL_VOL_ATTEN1, EFUSE_BLK2, 198, 10, ADC1 calibration voltage at atten1
ADC1_CAL_VOL_ATTEN2, EFUSE_BLK2, 208, 10, ADC1 calibration voltage at atten2
ADC1_CAL_VOL_ATTEN3, EFUSE_BLK2, 218, 10, ADC1 calibration voltage at atten3
################
USER_DATA, EFUSE_BLK3, 0, 256, User data
KEY0, EFUSE_BLK4, 0, 256, Key0 or user data
KEY1, EFUSE_BLK5, 0, 256, Key1 or user data
KEY2, EFUSE_BLK6, 0, 256, Key2 or user data
KEY3, EFUSE_BLK7, 0, 256, Key3 or user data
KEY4, EFUSE_BLK8, 0, 256, Key4 or user data
KEY5, EFUSE_BLK9, 0, 256, Key5 or user data
SYS_DATA_PART2, EFUSE_BLK10, 0, 256, System configuration
# AUTO CONFIG DIG&RTC DBIAS#
################
K_RTC_LDO, EFUSE_BLK1, 135, 7, BLOCK1 K_RTC_LDO
K_DIG_LDO, EFUSE_BLK1, 142, 7, BLOCK1 K_DIG_LDO
V_RTC_DBIAS20, EFUSE_BLK1, 149, 8, BLOCK1 voltage of rtc dbias20
V_DIG_DBIAS20, EFUSE_BLK1, 157, 8, BLOCK1 voltage of digital dbias20
DIG_DBIAS_HVT, EFUSE_BLK1, 165, 5, BLOCK1 digital dbias when hvt
THRES_HVT, EFUSE_BLK1, 170, 10, BLOCK1 pvt threshold when hvt
Can't render this file because it contains an unexpected character in line 7 and column 87.

View File

@@ -0,0 +1,141 @@
/*
* SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "assert.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "esp32h2/clk.h"
#include "esp32h2/rom/efuse.h"
static const char *TAG = "efuse";
#ifdef CONFIG_EFUSE_VIRTUAL
extern uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK];
#endif // CONFIG_EFUSE_VIRTUAL
/*Range addresses to read blocks*/
const esp_efuse_range_addr_t range_read_addr_blocks[] = {
{EFUSE_RD_WR_DIS_REG, EFUSE_RD_REPEAT_DATA4_REG}, // range address of EFUSE_BLK0 REPEAT
{EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_RD_MAC_SPI_SYS_5_REG}, // range address of EFUSE_BLK1 MAC_SPI_8M
{EFUSE_RD_SYS_PART1_DATA0_REG, EFUSE_RD_SYS_PART1_DATA7_REG}, // range address of EFUSE_BLK2 SYS_DATA
{EFUSE_RD_USR_DATA0_REG, EFUSE_RD_USR_DATA7_REG}, // range address of EFUSE_BLK3 USR_DATA
{EFUSE_RD_KEY0_DATA0_REG, EFUSE_RD_KEY0_DATA7_REG}, // range address of EFUSE_BLK4 KEY0
{EFUSE_RD_KEY1_DATA0_REG, EFUSE_RD_KEY1_DATA7_REG}, // range address of EFUSE_BLK5 KEY1
{EFUSE_RD_KEY2_DATA0_REG, EFUSE_RD_KEY2_DATA7_REG}, // range address of EFUSE_BLK6 KEY2
{EFUSE_RD_KEY3_DATA0_REG, EFUSE_RD_KEY3_DATA7_REG}, // range address of EFUSE_BLK7 KEY3
{EFUSE_RD_KEY4_DATA0_REG, EFUSE_RD_KEY4_DATA7_REG}, // range address of EFUSE_BLK8 KEY4
{EFUSE_RD_KEY5_DATA0_REG, EFUSE_RD_KEY5_DATA7_REG}, // range address of EFUSE_BLK9 KEY5
{EFUSE_RD_SYS_PART2_DATA0_REG, EFUSE_RD_SYS_PART2_DATA7_REG} // range address of EFUSE_BLK10 KEY6
};
static uint32_t write_mass_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK] = { 0 };
/*Range addresses to write blocks (it is not real regs, it is buffer) */
const esp_efuse_range_addr_t range_write_addr_blocks[] = {
{(uint32_t) &write_mass_blocks[EFUSE_BLK0][0], (uint32_t) &write_mass_blocks[EFUSE_BLK0][5]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK1][0], (uint32_t) &write_mass_blocks[EFUSE_BLK1][5]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK2][0], (uint32_t) &write_mass_blocks[EFUSE_BLK2][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK3][0], (uint32_t) &write_mass_blocks[EFUSE_BLK3][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK4][0], (uint32_t) &write_mass_blocks[EFUSE_BLK4][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK5][0], (uint32_t) &write_mass_blocks[EFUSE_BLK5][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK6][0], (uint32_t) &write_mass_blocks[EFUSE_BLK6][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK7][0], (uint32_t) &write_mass_blocks[EFUSE_BLK7][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK8][0], (uint32_t) &write_mass_blocks[EFUSE_BLK8][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK9][0], (uint32_t) &write_mass_blocks[EFUSE_BLK9][7]},
{(uint32_t) &write_mass_blocks[EFUSE_BLK10][0], (uint32_t) &write_mass_blocks[EFUSE_BLK10][7]},
};
#ifndef CONFIG_EFUSE_VIRTUAL
// Update Efuse timing configuration
static esp_err_t esp_efuse_set_timing(void)
{
// efuse clock is fixed in ESP32-C3, so the ets_efuse_set_timing() function
// takes an argument for compatibility with older ROM functions but it's ignored.
int res = ets_efuse_set_timing(0);
assert(res == 0);
(void)res;
REG_SET_FIELD(EFUSE_WR_TIM_CONF2_REG, EFUSE_PWR_OFF_NUM, 0x60);
return ESP_OK;
}
#endif // ifndef CONFIG_EFUSE_VIRTUAL
// Efuse read operation: copies data from physical efuses to efuse read registers.
void esp_efuse_utility_clear_program_registers(void)
{
ets_efuse_read();
ets_efuse_clear_program_registers();
}
// Burn values written to the efuse write registers
void esp_efuse_utility_burn_chip(void)
{
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses");
for (int num_block = EFUSE_BLK_MAX - 1; num_block >= EFUSE_BLK0; num_block--) {
int subblock = 0;
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
}
}
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_utility_write_efuses_to_flash();
#endif
#else
if (esp_efuse_set_timing() != ESP_OK) {
ESP_LOGE(TAG, "Efuse fields are not burnt");
} else {
// Permanently update values written to the efuse write registers
// It is necessary to process blocks in the order from MAX-> EFUSE_BLK0, because EFUSE_BLK0 has protection bits for other blocks.
for (int num_block = EFUSE_BLK_MAX - 1; num_block >= EFUSE_BLK0; num_block--) {
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
if (REG_READ(addr_wr_block) != 0) {
if (esp_efuse_get_coding_scheme(num_block) == EFUSE_CODING_SCHEME_RS) {
uint8_t block_rs[12];
ets_efuse_rs_calculate((void *)range_write_addr_blocks[num_block].start, block_rs);
memcpy((void *)EFUSE_PGM_CHECK_VALUE0_REG, block_rs, sizeof(block_rs));
}
int data_len = (range_write_addr_blocks[num_block].end - range_write_addr_blocks[num_block].start) + sizeof(uint32_t);
memcpy((void *)EFUSE_PGM_DATA0_REG, (void *)range_write_addr_blocks[num_block].start, data_len);
ets_efuse_program(num_block);
break;
}
}
}
}
#endif // CONFIG_EFUSE_VIRTUAL
esp_efuse_utility_reset();
}
// After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values.
// This function reads EFUSE_BLKx_WDATAx_REG registers, and checks possible to write these data with RS coding scheme.
// The RS coding scheme does not require data changes for the encoded data. esp32s2 has special registers for this.
// They will be filled during the burn operation.
esp_err_t esp_efuse_utility_apply_new_coding_scheme()
{
// start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE.
for (int num_block = EFUSE_BLK1; num_block < EFUSE_BLK_MAX; num_block++) {
if (esp_efuse_get_coding_scheme(num_block) == EFUSE_CODING_SCHEME_RS) {
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
if (REG_READ(addr_wr_block)) {
int num_reg = 0;
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++num_reg) {
if (esp_efuse_utility_read_reg(num_block, num_reg)) {
ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden.");
return ESP_ERR_CODING;
}
}
break;
}
}
}
}
return ESP_OK;
}

View File

@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of eFuse blocks ESP32H2
*/
typedef enum {
EFUSE_BLK0 = 0, /**< Number of eFuse BLOCK0. REPEAT_DATA */
EFUSE_BLK1 = 1, /**< Number of eFuse BLOCK1. MAC_SPI_8M_SYS */
EFUSE_BLK2 = 2, /**< Number of eFuse BLOCK2. SYS_DATA_PART1 */
EFUSE_BLK_SYS_DATA_PART1 = 2, /**< Number of eFuse BLOCK2. SYS_DATA_PART1 */
EFUSE_BLK3 = 3, /**< Number of eFuse BLOCK3. USER_DATA*/
EFUSE_BLK_USER_DATA = 3, /**< Number of eFuse BLOCK3. USER_DATA*/
EFUSE_BLK4 = 4, /**< Number of eFuse BLOCK4. KEY0 */
EFUSE_BLK_KEY0 = 4, /**< Number of eFuse BLOCK4. KEY0 */
EFUSE_BLK5 = 5, /**< Number of eFuse BLOCK5. KEY1 */
EFUSE_BLK_KEY1 = 5, /**< Number of eFuse BLOCK5. KEY1 */
EFUSE_BLK6 = 6, /**< Number of eFuse BLOCK6. KEY2 */
EFUSE_BLK_KEY2 = 6, /**< Number of eFuse BLOCK6. KEY2 */
EFUSE_BLK7 = 7, /**< Number of eFuse BLOCK7. KEY3 */
EFUSE_BLK_KEY3 = 7, /**< Number of eFuse BLOCK7. KEY3 */
EFUSE_BLK8 = 8, /**< Number of eFuse BLOCK8. KEY4 */
EFUSE_BLK_KEY4 = 8, /**< Number of eFuse BLOCK8. KEY4 */
EFUSE_BLK9 = 9, /**< Number of eFuse BLOCK9. KEY5 */
EFUSE_BLK_KEY5 = 9, /**< Number of eFuse BLOCK9. KEY5 */
EFUSE_BLK_KEY_MAX = 10,
EFUSE_BLK10 = 10, /**< Number of eFuse BLOCK10. SYS_DATA_PART2 */
EFUSE_BLK_SYS_DATA_PART2 = 10, /**< Number of eFuse BLOCK10. SYS_DATA_PART2 */
EFUSE_BLK_MAX
} esp_efuse_block_t;
/**
* @brief Type of coding scheme
*/
typedef enum {
EFUSE_CODING_SCHEME_NONE = 0, /**< None */
EFUSE_CODING_SCHEME_RS = 3, /**< Reed-Solomon coding */
} esp_efuse_coding_scheme_t;
/**
* @brief Type of key purpose
*/
typedef enum {
ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */
ESP_EFUSE_KEY_PURPOSE_RESERVED = 1, /**< Reserved */
ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY = 4, /**< XTS_AES_128_KEY (flash/PSRAM encryption) */
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL = 5, /**< HMAC Downstream mode */
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG = 6, /**< JTAG soft enable key (uses HMAC Downstream mode) */
ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE = 7, /**< Digital Signature peripheral key (uses HMAC Downstream mode) */
ESP_EFUSE_KEY_PURPOSE_HMAC_UP = 8, /**< HMAC Upstream mode */
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0 = 9, /**< SECURE_BOOT_DIGEST0 (Secure Boot key digest) */
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1 = 10, /**< SECURE_BOOT_DIGEST1 (Secure Boot key digest) */
ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11, /**< SECURE_BOOT_DIGEST2 (Secure Boot key digest) */
ESP_EFUSE_KEY_PURPOSE_MAX, /**< MAX PURPOSE */
} esp_efuse_purpose_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the RTC calibration efuse version
*
* @return Version of the stored efuse
*/
int esp_efuse_rtc_calib_get_ver(void);
/**
* @brief Get the init code in the efuse, for the corresponding attenuation.
*
* @param version Version of the stored efuse
* @param atten Attenuation of the init code
* @return The init code stored in efuse
*/
uint16_t esp_efuse_rtc_calib_get_init_code(int version, int atten);
/**
* @brief Get the calibration digits stored in the efuse, and the corresponding voltage.
*
* @param version Version of the stored efuse
* @param atten Attenuation to use
* @param out_digi Output buffer of the digits
* @param out_vol_mv Output of the voltage, in mV
* @return
* - ESP_ERR_INVALID_ARG: If efuse version or attenuation is invalid
* - ESP_OK: if success
*/
esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv);
/**
* @brief Get the temperature sensor calibration number delta_T stored in the efuse.
*
* @param version Version of the stored efuse
*
* @return The specification of temperature sensor calibration number in efuse.
*/
float esp_efuse_rtc_calib_get_cal_temp(int version);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef __cplusplus
extern "C" {
#endif
// md5_digest_table 9e42b2f9dd879191ca75ad0cf50841a1
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
// To show efuse_table run the command 'show_efuse_table'.
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_RD_DIS[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_GROUP_1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_GROUP_2[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY0_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY1_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY2_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY3_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY4_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY5_PURPOSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SECURE_BOOT_EN[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SECURE_BOOT_AGGRESSIVE_REVOKE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_GROUP_3[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SYS_DATA_PART1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_USER_DATA[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY0[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY2[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY3[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY4[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_KEY5[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_SYS_DATA_PART2[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY0[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY1[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY2[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY3[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY4[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_KEY5[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_SYS_DATA_PART2[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_RTC_RAM_BOOT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_ICACHE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_USB_JTAG[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_DOWNLOAD_ICACHE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_USB_DEVICE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_FORCE_DOWNLOAD[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_USB[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_CAN[];
extern const esp_efuse_desc_t* ESP_EFUSE_JTAG_SEL_ENABLE[];
extern const esp_efuse_desc_t* ESP_EFUSE_SOFT_DIS_JTAG[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_PAD_JTAG[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT[];
extern const esp_efuse_desc_t* ESP_EFUSE_USB_DREFH[];
extern const esp_efuse_desc_t* ESP_EFUSE_USB_DREFL[];
extern const esp_efuse_desc_t* ESP_EFUSE_USB_EXCHG_PINS[];
extern const esp_efuse_desc_t* ESP_EFUSE_VDD_SPI_AS_GPIO[];
extern const esp_efuse_desc_t* ESP_EFUSE_BTLC_GPIO_ENABLE[];
extern const esp_efuse_desc_t* ESP_EFUSE_POWERGLITCH_EN[];
extern const esp_efuse_desc_t* ESP_EFUSE_POWER_GLITCH_DSENSE[];
extern const esp_efuse_desc_t* ESP_EFUSE_WDT_DELAY_SEL[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_BOOT_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_0[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_1[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_2[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_3[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_4[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY_PURPOSE_5[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_EN[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_TPUW[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_DOWNLOAD_MODE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_LEGACY_SPI_BOOT[];
extern const esp_efuse_desc_t* ESP_EFUSE_UART_PRINT_CHANNEL[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_ECC_MODE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIS_USB_DOWNLOAD_MODE[];
extern const esp_efuse_desc_t* ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD[];
extern const esp_efuse_desc_t* ESP_EFUSE_UART_PRINT_CONTROL[];
extern const esp_efuse_desc_t* ESP_EFUSE_PIN_POWER_SELECTION[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_TYPE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_PAGE_SIZE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_ECC_EN[];
extern const esp_efuse_desc_t* ESP_EFUSE_FORCE_SEND_RESUME[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_CLK[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_Q_D1[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D_D0[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_CS[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_HD_D3[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_WP_D2[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_DQS[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D4[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D5[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D6[];
extern const esp_efuse_desc_t* ESP_EFUSE_SPI_PAD_CONFIG_D7[];
extern const esp_efuse_desc_t* ESP_EFUSE_WAFER_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_PKG_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_BLOCK1_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_OPTIONAL_UNIQUE_ID[];
extern const esp_efuse_desc_t* ESP_EFUSE_BLOCK2_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEMP_CALIB[];
extern const esp_efuse_desc_t* ESP_EFUSE_OCODE[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_INIT_CODE_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN1[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN2[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_CAL_VOL_ATTEN3[];
extern const esp_efuse_desc_t* ESP_EFUSE_USER_DATA[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY0[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY1[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY2[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY3[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY4[];
extern const esp_efuse_desc_t* ESP_EFUSE_KEY5[];
extern const esp_efuse_desc_t* ESP_EFUSE_SYS_DATA_PART2[];
extern const esp_efuse_desc_t* ESP_EFUSE_K_RTC_LDO[];
extern const esp_efuse_desc_t* ESP_EFUSE_K_DIG_LDO[];
extern const esp_efuse_desc_t* ESP_EFUSE_V_RTC_DBIAS20[];
extern const esp_efuse_desc_t* ESP_EFUSE_V_DIG_DBIAS20[];
extern const esp_efuse_desc_t* ESP_EFUSE_DIG_DBIAS_HVT[];
extern const esp_efuse_desc_t* ESP_EFUSE_THRES_HVT[];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define COUNT_EFUSE_REG_PER_BLOCK 8 /* The number of registers per block. */
#define ESP_EFUSE_SECURE_VERSION_NUM_BLOCK EFUSE_BLK0
#define ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(scheme, max_num_bit)
#ifdef __cplusplus
}
#endif

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

@@ -25,6 +25,8 @@ extern "C" {
#include "esp32c3/rom/secure_boot.h" #include "esp32c3/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/secure_boot.h" #include "esp32s3/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/secure_boot.h"
#endif #endif
#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */ #define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */

View File

@@ -26,7 +26,7 @@ menu "ESP-TLS"
config ESP_TLS_USE_DS_PERIPHERAL config ESP_TLS_USE_DS_PERIPHERAL
bool "Use Digital Signature (DS) Peripheral with ESP-TLS" bool "Use Digital Signature (DS) Peripheral with ESP-TLS"
depends on (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2) && ESP_TLS_USING_MBEDTLS depends on (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32H2) && ESP_TLS_USING_MBEDTLS
default y default y
help help
Enable use of the Digital Signature Peripheral for ESP-TLS.The DS peripheral Enable use of the Digital Signature Peripheral for ESP-TLS.The DS peripheral

View File

@@ -0,0 +1,66 @@
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
if(NOT "${target}" STREQUAL "esp32h2")
return()
endif()
if(BOOTLOADER_BUILD)
# For bootloader, all we need from esp32h2 is headers
idf_component_register(INCLUDE_DIRS include REQUIRES riscv)
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32h2.peripherals.ld")
else()
# Regular app build
set(srcs "dport_access.c"
"esp_hmac.c"
"esp_ds.c"
"esp_crypto_lock.c"
"memprot.c")
set(include_dirs "include")
set(requires driver efuse soc riscv) #unfortunately rom/uart uses SOC registers directly
# driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
# esp_timer is added here because cpu_start.c uses esp_timer
set(priv_requires
app_trace app_update bootloader_support log mbedtls nvs_flash
pthread spi_flash vfs espcoredump esp_common esp_timer)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
REQUIRES "${requires}"
PRIV_REQUIRES "${priv_requires}"
REQUIRED_IDF_TARGETS esp32h2)
target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32h2_out.ld")
# Process the template file through the linker script generation mechanism, and use the output for linking the
# final binary
target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32h2.project.ld.in"
PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32h2.project.ld")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32h2.peripherals.ld")
target_link_libraries(${COMPONENT_LIB} PUBLIC gcc)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0")
idf_build_get_property(config_dir CONFIG_DIR)
# Preprocess esp32h2.ld linker script to include configuration, becomes esp32h2_out.ld
set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld)
add_custom_command(
OUTPUT esp32h2_out.ld
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32h2_out.ld -I ${config_dir} ${LD_DIR}/esp32h2.ld
MAIN_DEPENDENCY ${LD_DIR}/esp32h2.ld
DEPENDS ${sdkconfig_header}
COMMENT "Generating linker script..."
VERBATIM)
add_custom_target(esp32h2_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32h2_out.ld)
add_dependencies(${COMPONENT_LIB} esp32h2_linker_script)
# disable stack protection in files which are involved in initialization of that feature
set_source_files_properties(
cpu_start.c
PROPERTIES COMPILE_FLAGS
-fno-stack-protector)
endif()

205
components/esp32h2/Kconfig Normal file
View File

@@ -0,0 +1,205 @@
menu "ESP32H2-Specific"
visible if IDF_TARGET_ESP32H2
choice ESP32H2_DEFAULT_CPU_FREQ_MHZ
prompt "CPU frequency"
default ESP32H2_DEFAULT_CPU_FREQ_64 if IDF_ENV_FPGA
default ESP32H2_DEFAULT_CPU_FREQ_96 if !IDF_ENV_FPGA
help
CPU frequency to be set on application startup.
config ESP32H2_DEFAULT_CPU_FREQ_16
bool "16 MHz"
config ESP32H2_DEFAULT_CPU_FREQ_32
bool "32 MHz"
config ESP32H2_DEFAULT_CPU_FREQ_64
bool "64 MHz"
config ESP32H2_DEFAULT_CPU_FREQ_96
bool "96 MHz"
depends on !IDF_ENV_FPGA
endchoice
config ESP32H2_DEFAULT_CPU_FREQ_MHZ
int
default 16 if ESP32H2_DEFAULT_CPU_FREQ_16
default 32 if ESP32H2_DEFAULT_CPU_FREQ_32
default 64 if ESP32H2_DEFAULT_CPU_FREQ_64
default 96 if ESP32H2_DEFAULT_CPU_FREQ_96
choice ESP32H2_REV_MIN
prompt "Minimum Supported ESP32-H2 Revision"
default ESP32H2_REV_MIN_0
help
Minimum revision that ESP-IDF would support.
Only supporting higher chip revisions can reduce binary size.
config ESP32H2_REV_MIN_0
bool "Rev 0"
endchoice
config ESP32H2_REV_MIN
int
default 0 if ESP32H2_REV_MIN_0
config ESP32H2_DEBUG_OCDAWARE
bool "Make exception and panic handlers JTAG/OCD aware"
default y
select FREERTOS_DEBUG_OCDAWARE
help
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
instead of panicking, have the debugger stop on the offending instruction.
config ESP32H2_DEBUG_STUBS_ENABLE
bool "OpenOCD debug stubs"
default COMPILER_OPTIMIZATION_LEVEL_DEBUG
depends on !ESP32H2_TRAX
help
Debug stubs are used by OpenOCD to execute pre-compiled onboard code which does some useful debugging,
e.g. GCOV data dump.
config ESP32H2_BROWNOUT_DET
bool "Hardware brownout detect & reset"
default y
help
The ESP32-C3 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 ESP32H2_BROWNOUT_DET_LVL_SEL
prompt "Brownout voltage level"
depends on ESP32H2_BROWNOUT_DET
default ESP32H2_BROWNOUT_DET_LVL_SEL_7
help
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 ESP32H2_BROWNOUT_DET_LVL_SEL_7
bool "2.51V"
config ESP32H2_BROWNOUT_DET_LVL_SEL_6
bool "2.64V"
config ESP32H2_BROWNOUT_DET_LVL_SEL_5
bool "2.76V"
config ESP32H2_BROWNOUT_DET_LVL_SEL_4
bool "2.92V"
config ESP32H2_BROWNOUT_DET_LVL_SEL_3
bool "3.10V"
config ESP32H2_BROWNOUT_DET_LVL_SEL_2
bool "3.27V"
endchoice
config ESP32H2_BROWNOUT_DET_LVL
int
default 2 if ESP32H2_BROWNOUT_DET_LVL_SEL_2
default 3 if ESP32H2_BROWNOUT_DET_LVL_SEL_3
default 4 if ESP32H2_BROWNOUT_DET_LVL_SEL_4
default 5 if ESP32H2_BROWNOUT_DET_LVL_SEL_5
default 6 if ESP32H2_BROWNOUT_DET_LVL_SEL_6
default 7 if ESP32H2_BROWNOUT_DET_LVL_SEL_7
choice ESP32H2_TIME_SYSCALL
prompt "Timers used for gettimeofday function"
default ESP32H2_TIME_SYSCALL_USE_RTC_SYSTIMER
help
This setting defines which hardware timers are used to
implement 'gettimeofday' and 'time' functions in C library.
- If both high-resolution (systimer) and RTC timers are used, timekeeping will
continue in deep sleep. Time will be reported at 1 microsecond
resolution. This is the default, and the recommended option.
- If only high-resolution timer (systimer) is used, gettimeofday will
provide time at microsecond resolution.
Time will not be preserved when going into deep sleep mode.
- If only RTC timer is used, timekeeping will continue in
deep sleep, but time will be measured at 6.(6) microsecond
resolution. Also the gettimeofday function itself may take
longer to run.
- If no timers are used, gettimeofday and time functions
return -1 and set errno to ENOSYS.
- When RTC is used for timekeeping, two RTC_STORE registers are
used to keep time in deep sleep mode.
config ESP32H2_TIME_SYSCALL_USE_RTC_SYSTIMER
bool "RTC and high-resolution timer"
select ESP_TIME_FUNCS_USE_RTC_TIMER
select ESP_TIME_FUNCS_USE_ESP_TIMER
config ESP32H2_TIME_SYSCALL_USE_RTC
bool "RTC"
select ESP_TIME_FUNCS_USE_RTC_TIMER
config ESP32H2_TIME_SYSCALL_USE_SYSTIMER
bool "High-resolution timer"
select ESP_TIME_FUNCS_USE_ESP_TIMER
config ESP32H2_TIME_SYSCALL_USE_NONE
bool "None"
select ESP_TIME_FUNCS_USE_NONE
endchoice
choice ESP32H2_RTC_CLK_SRC
prompt "RTC clock source"
default ESP32H2_RTC_CLK_SRC_INT_RC
help
Choose which clock is used as RTC clock source.
config ESP32H2_RTC_CLK_SRC_INT_RC
bool "Internal 150kHz RC oscillator"
config ESP32H2_RTC_CLK_SRC_EXT_CRYS
bool "External 32kHz crystal"
select ESP_SYSTEM_RTC_EXT_XTAL
config ESP32H2_RTC_CLK_SRC_EXT_OSC
bool "External 32kHz oscillator at 32K_XP pin"
config ESP32H2_RTC_CLK_SRC_INT_8MD256
bool "Internal 8MHz oscillator, divided by 256 (~32kHz)"
endchoice
config ESP32H2_RTC_CLK_CAL_CYCLES
int "Number of cycles for RTC_SLOW_CLK calibration"
default 3000 if ESP32H2_RTC_CLK_SRC_EXT_CRYS || ESP32H2_RTC_CLK_SRC_EXT_OSC || ESP32H2_RTC_CLK_SRC_INT_8MD256
default 576 if ESP32H2_RTC_CLK_SRC_INT_RC
range 0 125000
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.
config ESP32H2_NO_BLOBS
bool "No Binary Blobs"
depends on !BT_ENABLED
default n
help
If enabled, this disables the linking of binary libraries in the application build. Note
that after enabling this Wi-Fi/Bluetooth will not work.
config ESP32H2_LIGHTSLEEP_GPIO_RESET_WORKAROUND
bool "light sleep GPIO reset workaround"
default y
select PM_SLP_DISABLE_GPIO if FREERTOS_USE_TICKLESS_IDLE
help
ESP32H2 will reset at wake-up if GPIO is received a small electrostatic pulse during
light sleep, with specific condition
- GPIO needs to be configured as input-mode only
- The pin receives a small electrostatic pulse, and reset occurs when the pulse
voltage is higher than 6 V
For GPIO set to input mode only, it is not a good practice to leave it open/floating,
The hardware design needs to controlled it with determined supply or ground voltage
is necessary.
This option provides a software workaround for this issue. Configure to isolate all
GPIO pins in sleep state.
endmenu # ESP32H2-Specific

View File

@@ -0,0 +1 @@
# ESP32-H2 is not supported in the GNU Make build system.

View File

@@ -0,0 +1,4 @@
#
# Component Makefile
#
COMPONENT_CONFIG_ONLY := 1

View File

@@ -0,0 +1,25 @@
// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <string.h>
#include "soc/dport_access.h"
// Read a sequence of DPORT registers to the buffer.
void esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address, uint32_t num_words)
{
for (uint32_t i = 0; i < num_words; ++i) {
buff_out[i] = DPORT_SEQUENCE_REG_READ(address + i * 4);
}
}

View File

@@ -0,0 +1,83 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <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
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);
}

232
components/esp32h2/esp_ds.c Normal file
View File

@@ -0,0 +1,232 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/periph_ctrl.h"
#include "esp_crypto_lock.h"
#include "hal/ds_hal.h"
#include "hal/ds_ll.h"
#include "hal/hmac_hal.h"
#include "esp32h2/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 ESP32H2_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 ESP32H2_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 = ESP32H2_ERR_HW_CRYPTO_DS_INVALID_DIGEST;
}
if (sig_check_result == DS_SIGNATURE_PADDING_FAIL) {
return_value = ESP32H2_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;
}

View File

@@ -0,0 +1,132 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "driver/periph_ctrl.h"
#include "esp32h2/rom/hmac.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp_hmac.h"
#include "esp_crypto_lock.h"
#include "hal/hmac_hal.h"
#define SHA256_BLOCK_SZ 64
#define SHA256_PAD_SZ 8
/**
* @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 ESP32H2, 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 ESP32H2 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;
}

View File

@@ -0,0 +1,42 @@
// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_DPORT_ACCESS_H_
#define _ESP_DPORT_ACCESS_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Read a sequence of DPORT registers to the buffer.
*
* @param[out] buff_out Contains the read data.
* @param[in] address Initial address for reading registers.
* @param[in] num_words The number of words.
*/
void esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address, uint32_t num_words);
#define DPORT_STALL_OTHER_CPU_START()
#define DPORT_STALL_OTHER_CPU_END()
#define DPORT_INTERRUPT_DISABLE()
#define DPORT_INTERRUPT_RESTORE()
#ifdef __cplusplus
}
#endif
#endif /* _ESP_DPORT_ACCESS_H_ */

View File

@@ -0,0 +1,455 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* INTERNAL API
* generic interface to PMS memory protection features
*/
#pragma once
#include <stdbool.h>
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef IRAM_SRAM_START
#define IRAM_SRAM_START 0x4037C000
#endif
#ifndef DRAM_SRAM_START
#define DRAM_SRAM_START 0x3FC7C000
#endif
#ifndef MAP_DRAM_TO_IRAM
#define MAP_DRAM_TO_IRAM(addr) (addr - DRAM_SRAM_START + IRAM_SRAM_START)
#endif
#ifndef MAP_IRAM_TO_DRAM
#define MAP_IRAM_TO_DRAM(addr) (addr - IRAM_SRAM_START + DRAM_SRAM_START)
#endif
typedef enum {
MEMPROT_NONE = 0x00000000,
MEMPROT_IRAM0_SRAM = 0x00000001,
MEMPROT_DRAM0_SRAM = 0x00000002,
MEMPROT_ALL = 0xFFFFFFFF
} mem_type_prot_t;
typedef enum {
MEMPROT_SPLITLINE_NONE = 0,
MEMPROT_IRAM0_DRAM0_SPLITLINE,
MEMPROT_IRAM0_LINE_0_SPLITLINE,
MEMPROT_IRAM0_LINE_1_SPLITLINE,
MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE,
MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE
} split_line_t;
typedef enum {
MEMPROT_PMS_AREA_NONE = 0,
MEMPROT_IRAM0_PMS_AREA_0,
MEMPROT_IRAM0_PMS_AREA_1,
MEMPROT_IRAM0_PMS_AREA_2,
MEMPROT_IRAM0_PMS_AREA_3,
MEMPROT_DRAM0_PMS_AREA_0,
MEMPROT_DRAM0_PMS_AREA_1,
MEMPROT_DRAM0_PMS_AREA_2,
MEMPROT_DRAM0_PMS_AREA_3
} pms_area_t;
typedef enum
{
MEMPROT_PMS_WORLD_0 = 0,
MEMPROT_PMS_WORLD_1,
MEMPROT_PMS_WORLD_2,
MEMPROT_PMS_WORLD_INVALID = 0xFFFFFFFF
} pms_world_t;
typedef enum
{
MEMPROT_PMS_OP_READ = 0,
MEMPROT_PMS_OP_WRITE,
MEMPROT_PMS_OP_FETCH,
MEMPROT_PMS_OP_INVALID = 0xFFFFFFFF
} pms_operation_type_t;
/**
* @brief Converts Memory protection type to string
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*/
const char *esp_memprot_mem_type_to_str(mem_type_prot_t mem_type);
/**
* @brief Converts Split line type to string
*
* @param line_type Split line type (see split_line_t enum)
*/
const char *esp_memprot_split_line_to_str(split_line_t line_type);
/**
* @brief Converts PMS Area type to string
*
* @param area_type PMS Area type (see pms_area_t enum)
*/
const char *esp_memprot_pms_to_str(pms_area_t area_type);
/**
* @brief Returns PMS splitting address for given Split line type
*
* The value is taken from PMS configuration registers (IRam0 range)
* For details on split lines see 'esp_memprot_set_prot_int' function description
*
* @param line_type Split line type (see split_line_t enum)
*
* @return appropriate split line address
*/
uint32_t *esp_memprot_get_split_addr(split_line_t line_type);
/**
* @brief Returns default main IRAM/DRAM splitting address
*
* The address value is given by _iram_text_end global (IRam0 range)
* @return Main I/D split line (IRam0_DRam0_Split_Addr)
*/
void *esp_memprot_get_default_main_split_addr(void);
/**
* @brief Sets a lock for the main IRAM/DRAM splitting address
*
* Locks can be unlocked only by digital system reset
*/
void esp_memprot_set_split_line_lock(void);
/**
* @brief Gets a lock status for the main IRAM/DRAM splitting address
*
* @return true/false (locked/unlocked)
*/
bool esp_memprot_get_split_line_lock(void);
/**
* @brief Sets required split line address
*
* @param line_type Split line type (see split_line_t enum)
* @param line_addr target address from a memory range relevant to given line_type (IRAM/DRAM)
*/
void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr);
/**
* @brief Sets a lock for PMS Area settings of required Memory type
*
* Locks can be unlocked only by digital system reset
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*/
void esp_memprot_set_pms_lock(mem_type_prot_t mem_type);
/**
* @brief Gets a lock status for PMS Area settings of required Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return true/false (locked/unlocked)
*/
bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type);
/**
* @brief Sets permissions for given PMS Area in IRam0 memory range (MEMPROT_IRAM0_SRAM)
*
* @param area_type IRam0 PMS Area type (see pms_area_t enum)
* @param r Read permission flag
* @param w Write permission flag
* @param x Execute permission flag
*/
void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x);
/**
* @brief Gets current permissions for given PMS Area in IRam0 memory range (MEMPROT_IRAM0_SRAM)
*
* @param area_type IRam0 PMS Area type (see pms_area_t enum)
* @param r Read permission flag holder
* @param w Write permission flag holder
* @param x Execute permission flag holder
*/
void esp_memprot_iram_get_pms_area(pms_area_t area_type, bool *r, bool *w, bool *x);
/**
* @brief Sets permissions for given PMS Area in DRam0 memory range (MEMPROT_DRAM0_SRAM)
*
* @param area_type DRam0 PMS Area type (see pms_area_t enum)
* @param r Read permission flag
* @param w Write permission flag
*/
void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w);
/**
* @brief Gets current permissions for given PMS Area in DRam0 memory range (MEMPROT_DRAM0_SRAM)
*
* @param area_type DRam0 PMS Area type (see pms_area_t enum)
* @param r Read permission flag holder
* @param w Write permission flag holder
*/
void esp_memprot_dram_get_pms_area(pms_area_t area_type, bool *r, bool *w);
/**
* @brief Sets a lock for PMS interrupt monitor settings of required Memory type
*
* Locks can be unlocked only by digital system reset
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*/
void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type);
/**
* @brief Gets a lock status for PMS interrupt monitor settings of required Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return true/false (locked/unlocked)
*/
bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type);
/**
* @brief Enable PMS violation interrupt monitoring of required Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
* @param enable/disable
*/
void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable);
/**
* @brief Gets enable/disable status for PMS interrupt monitor settings of required Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return true/false (enabled/disabled)
*/
bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type);
/**
* @brief Gets CPU ID for currently active PMS violation interrupt
*
* @return CPU ID (CPU_PRO for ESP32H2)
*/
int IRAM_ATTR esp_memprot_intr_get_cpuid(void);
/**
* @brief Clears current interrupt ON flag for given Memory type
*
* Interrupt clearing happens in two steps:
* 1. Interrupt CLR flag is set (to clear the interrupt ON status)
* 2. Interrupt CLR flag is reset (to allow further monitoring)
* This operation is non-atomic by PMS module design
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*/
void IRAM_ATTR esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type);
/**
* @brief Returns active PMS violation interrupt (if any)
*
* This function iterates through supported Memory type status registers
* and returns the first interrupt-on flag. If none is found active,
* MEMPROT_NONE is returned.
* Order of checking (in current version):
* 1. MEMPROT_IRAM0_SRAM
* 2. MEMPROT_DRAM0_SRAM
*
* @return mem_type Memory protection type related to active interrupt found (see mem_type_prot_t enum)
*/
mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void);
/**
* @brief Checks whether any violation interrupt is active
*
* @return true/false (yes/no)
*/
bool IRAM_ATTR esp_memprot_is_locked_any(void);
/**
* @brief Checks whether any violation interrupt is enabled
*
* @return true/false (yes/no)
*/
bool IRAM_ATTR esp_memprot_is_intr_ena_any(void);
/**
* @brief Checks whether any violation interrupt is enabled
*
* @return true/false (yes/no)
*/
bool IRAM_ATTR esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type);
/**
* @brief Returns the address which caused the violation interrupt (if any)
*
* The address is taken from appropriate PMS violation status register, based given Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return faulting address
*/
uint32_t IRAM_ATTR esp_memprot_get_violate_addr(mem_type_prot_t mem_type);
/**
* @brief Returns the World identifier of the code causing the violation interrupt (if any)
*
* The value is taken from appropriate PMS violation status register, based given Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return World identifier (see pms_world_t enum)
*/
pms_world_t IRAM_ATTR esp_memprot_get_violate_world(mem_type_prot_t mem_type);
/**
* @brief Returns Read or Write operation type which caused the violation interrupt (if any)
*
* The value (bit) is taken from appropriate PMS violation status register, based given Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return PMS operation type relevant to mem_type parameter (se pms_operation_type_t)
*/
pms_operation_type_t IRAM_ATTR esp_memprot_get_violate_wr(mem_type_prot_t mem_type);
/**
* @brief Returns LoadStore flag of the operation type which caused the violation interrupt (if any)
*
* The value (bit) is taken from appropriate PMS violation status register, based given Memory type
* Effective only on IRam0 access
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return true/false (LoadStore bit on/off)
*/
bool IRAM_ATTR esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type);
/**
* @brief Returns byte-enables for the address which caused the violation interrupt (if any)
*
* The value is taken from appropriate PMS violation status register, based given Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return byte-enables
*/
uint32_t IRAM_ATTR esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type);
/**
* @brief Returns raw contents of DRam0 status register 1
*
* @return 32-bit register value
*/
uint32_t IRAM_ATTR esp_memprot_get_dram_status_reg_1(void);
/**
* @brief Returns raw contents of DRam0 status register 2
*
* @return 32-bit register value
*/
uint32_t IRAM_ATTR esp_memprot_get_dram_status_reg_2(void);
/**
* @brief Returns raw contents of IRam0 status register
*
* @return 32-bit register value
*/
uint32_t IRAM_ATTR esp_memprot_get_iram_status_reg(void);
/**
* @brief Register PMS violation interrupt in global interrupt matrix for given Memory type
*
* Memory protection components uses specific interrupt number, see ETS_MEMPROT_ERR_INUM
* The registration makes the panic-handler routine being called when the interrupt appears
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*/
void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type);
/**
* @brief Convenient routine for setting the PMS defaults
*
* Called on application startup, depending on CONFIG_ESP_SYSTEM_MEMPROT_FEATURE Kconfig settings
* For implementation details see 'esp_memprot_set_prot_int' description
*
* @param invoke_panic_handler register all interrupts for panic handling (true/false)
* @param lock_feature lock the defaults to prevent further PMS settings changes (true/false)
* @param mem_type_mask 32-bit field of specific PMS parts to configure (see 'esp_memprot_set_prot_int')
*/
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask);
/**
* @brief Internal routine for setting the PMS defaults
*
* Called on application startup from within 'esp_memprot_set_prot'. Allows setting a specific splitting address
* (main I/D split line) - see the parameter 'split_addr'. If the 'split_addr' equals to NULL, default I/D split line
* is used (&_iram_text_end) and all the remaining lines share the same address.
* The function sets all the split lines and PMS areas to the same space,
* ie there is a single instruction space and single data space at the end.
* The PMS split lines and permission areas scheme described below:
*
* DRam0/DMA IRam0
* -----------------------------------------------
* ... | IRam0_PMS_0 |
* DRam0_PMS_0 ----------------------------------------------- IRam0_line1_Split_addr
* ... | IRam0_PMS_1 |
* ... ----------------------------------------------- IRam0_line0_Split_addr
* | IRam0_PMS_2 |
* =============================================== IRam0_DRam0_Split_addr (main I/D)
* | DRam0_PMS_1 |
* DRam0_DMA_line0_Split_addr ----------------------------------------------- ...
* | DRam0_PMS_2 | ...
* DRam0_DMA_line1_Split_addr ----------------------------------------------- IRam0_PMS_3
* | DRam0_PMS_3 | ...
* -----------------------------------------------
*
* Default settings provided by 'esp_memprot_set_prot_int' are as follows:
*
* DRam0/DMA IRam0
* -----------------------------------------------
* | IRam0_PMS_0 = IRam0_PMS_1 = IRam0_PMS_2 |
* | DRam0_PMS_0 | IRam0_line1_Split_addr
* DRam0_DMA_line0_Split_addr | | =
* = =============================================== IRam0_line0_Split_addr
* DRam0_DMA_line1_Split_addr | | =
* | DRam0_PMS_1 = DRam0_PMS_2 = DRam0_PMS_3 | IRam0_DRam0_Split_addr (main I/D)
* | IRam0_PMS_3 |
* -----------------------------------------------
*
* Once the memprot feature is locked, it can be unlocked only by digital system reset
*
* @param invoke_panic_handler register all the violation interrupts for panic handling (true/false)
* @param lock_feature lock the defaults to prevent further PMS settings changes (true/false)
* @param split_addr specific main I/D adrees or NULL to use default ($_iram_text_end)
* @param mem_type_mask 32-bit field of specific PMS parts to configure (members of mem_type_prot_t)
*/
void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask);
/**
* @brief Returns raw contents of PMS interrupt monitor register for given Memory type
*
* @param mem_type Memory protection type (see mem_type_prot_t enum)
*
* @return 32-bit register value
*/
uint32_t esp_memprot_get_monitor_enable_reg(mem_type_prot_t mem_type);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,40 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file esp32h2/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

@@ -0,0 +1,76 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#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

View File

@@ -0,0 +1,218 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp_hmac.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP32H2_ERR_HW_CRYPTO_DS_HMAC_FAIL ESP_ERR_HW_CRYPTO_BASE + 0x1 /*!< HMAC peripheral problem */
#define ESP32H2_ERR_HW_CRYPTO_DS_INVALID_KEY ESP_ERR_HW_CRYPTO_BASE + 0x2 /*!< given HMAC key isn't correct,
HMAC peripheral problem */
#define ESP32H2_ERR_HW_CRYPTO_DS_INVALID_DIGEST ESP_ERR_HW_CRYPTO_BASE + 0x4 /*!< message digest check failed,
result is invalid */
#define ESP32H2_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.
*
* 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 is determined by data->rsa_length
* @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.
*
* @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 is determined by data->rsa_length
* @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

View File

@@ -0,0 +1,67 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_HMAC_H_
#define _ESP_HMAC_H_
#include <stdbool.h>
#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 32 bytes long
*
* @return
* * ESP_OK, if the calculation was successful,
* * 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);
#ifdef __cplusplus
}
#endif
#endif // _ESP_HMAC_H_

View File

@@ -0,0 +1,118 @@
/**
* ESP32-H2 Linker Script Memory Layout
* This file describes the memory layout (memory blocks) by virtual memory addresses.
* This linker script is passed through the C preprocessor to include configuration options.
* Please use preprocessor features sparingly!
* Restrict to simple macros with numeric values, and/or #if/#endif blocks.
*/
#include "sdkconfig.h"
#ifdef CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE + CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC_SIZE)
#elif defined(CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP)
#define ESP_BOOTLOADER_RESERVE_RTC (CONFIG_BOOTLOADER_RESERVE_RTC_SIZE)
#else
#define ESP_BOOTLOADER_RESERVE_RTC 0
#endif
#define SRAM_IRAM_START 0x4037C000
#define SRAM_DRAM_START 0x3FC7C000
#define ICACHE_SIZE 0x4000 /* ICache size is fixed to 16KB on ESP32-C3 */
#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START)
#define SRAM_DRAM_END 0x403D0000 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_IRAM_ORG (SRAM_IRAM_START + ICACHE_SIZE)
#define SRAM_DRAM_ORG (SRAM_DRAM_START + ICACHE_SIZE)
#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG
#if CONFIG_ESP32H2_USE_FIXED_STATIC_RAM_SIZE
ASSERT((CONFIG_ESP32H2_FIXED_STATIC_RAM_SIZE <= I_D_SRAM_SIZE), "Fixed static ram data does not fit.")
#define DRAM0_0_SEG_LEN CONFIG_ESP3C3_FIXED_STATIC_RAM_SIZE
#else
#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE
#endif // CONFIG_ESP32H2_USE_FIXED_STATIC_RAM_SIZE
MEMORY
{
/**
* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
* of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
* are connected to the data port of the CPU and eg allow byte-wise access.
*/
/* IRAM for PRO CPU. */
iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped instruction data */
iram0_2_seg (RX) : org = 0x42000020, len = 0x8000000-0x20
/**
* (0x20 offset above is a convenience for the app binary image generation.
* Flash cache has 64KB pages. The .bin file which is flashed to the chip
* has a 0x18 byte file header, and each segment has a 0x08 byte segment
* header. Setting this offset makes it simple to meet the flash cache MMU's
* constraint that (paddr % 64KB == vaddr % 64KB).)
*/
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
* Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available.
*/
dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */
drom0_0_seg (R) : org = 0x3C000020, len = 0x8000000-0x20
/* (See iram0_2_seg for meaning of 0x20 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
* RTC fast memory (executable). Persists over deep sleep.
*/
rtc_iram_seg(RWX) : org = 0x50000000, len = 0x2000 - ESP_BOOTLOADER_RESERVE_RTC
}
#if CONFIG_ESP32H2_USE_FIXED_STATIC_RAM_SIZE
/* static data ends at defined address */
_static_data_end = 0x3FCA0000 + DRAM0_0_SEG_LEN;
#else
_static_data_end = _bss_end;
#endif // CONFIG_ESP32H2_USE_FIXED_STATIC_RAM_SIZE
/* Heap ends at top of dram0_0_seg */
_heap_end = 0x40000000;
_data_seg_org = ORIGIN(rtc_data_seg);
/**
* The lines below define location alias for .rtc.data section
* As C3 only has RTC fast memory, this is not configurable like on other targets
*/
REGION_ALIAS("rtc_data_seg", rtc_iram_seg );
REGION_ALIAS("rtc_slow_seg", rtc_iram_seg );
REGION_ALIAS("rtc_data_location", rtc_iram_seg );
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", iram0_2_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom0_0_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
* If rodata default segment is placed in `drom0_0_seg`, then flash's first rodata section must
* also be first in the segment.
*/
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
ASSERT(_flash_rodata_dummy_start == ORIGIN(default_rodata_seg),
".flash_rodata_dummy section must be placed at the beginning of the rodata segment.")
#endif

View File

@@ -0,0 +1,30 @@
PROVIDE ( UART0 = 0x60000000 );
PROVIDE ( UART1 = 0x60010000 );
PROVIDE ( SPIMEM1 = 0x60002000 );
PROVIDE ( SPIMEM0 = 0x60003000 );
PROVIDE ( GPIO = 0x60004000 );
PROVIDE ( SIGMADELTA = 0x60004f00 );
PROVIDE ( RTCCNTL = 0x60008000 );
PROVIDE ( RTCIO = 0x60008400 );
PROVIDE ( HINF = 0x6000B000 );
PROVIDE ( I2S1 = 0x6002d000 );
PROVIDE ( I2C0 = 0x60013000 );
PROVIDE ( UHCI0 = 0x60014000 );
PROVIDE ( UHCI1 = 0x6000c000 );
PROVIDE ( HOST = 0x60015000 );
PROVIDE ( RMT = 0x60016000 );
PROVIDE ( RMTMEM = 0x60016400 );
PROVIDE ( PCNT = 0x60017000 );
PROVIDE ( SLC = 0x60018000 );
PROVIDE ( LEDC = 0x60019000 );
PROVIDE ( TIMERG0 = 0x6001F000 );
PROVIDE ( TIMERG1 = 0x60020000 );
PROVIDE ( SYSTIMER = 0x60023000 );
PROVIDE ( GPSPI2 = 0x60024000 );
PROVIDE ( GPSPI3 = 0x60025000 );
PROVIDE ( SYSCON = 0x60026000 );
PROVIDE ( TWAI = 0x6002B000 );
PROVIDE ( GPSPI4 = 0x60037000 );
PROVIDE ( APB_SARADC = 0x60040000 );
PROVIDE ( USB_SERIAL_JTAG = 0x60043000 );
PROVIDE ( GDMA = 0x6003F000 );

View File

@@ -0,0 +1,392 @@
/* Default entry point */
ENTRY(call_start_cpu0);
SECTIONS
{
/**
* RTC fast memory holds RTC wake stub code,
* including from any source file named rtc_wake_stub*.c
*/
.rtc.text :
{
. = ALIGN(4);
mapping[rtc_text]
*rtc_wake_stub*.*(.literal .text .literal.* .text.*)
_rtc_text_end = ABSOLUTE(.);
} > rtc_iram_seg
/**
* This section is required to skip rtc.text area because rtc_iram_seg and
* rtc_data_seg are reflect the same address space on different buses.
*/
.rtc.dummy :
{
_rtc_dummy_start = ABSOLUTE(.);
_rtc_fast_start = ABSOLUTE(.);
. = SIZEOF(.rtc.text);
_rtc_dummy_end = ABSOLUTE(.);
} > rtc_data_seg
/**
* This section located in RTC FAST Memory area.
* It holds data marked with RTC_FAST_ATTR attribute.
* See the file "esp_attr.h" for more information.
*/
.rtc.force_fast :
{
. = ALIGN(4);
_rtc_force_fast_start = ABSOLUTE(.);
mapping[rtc_force_fast]
*(.rtc.force_fast .rtc.force_fast.*)
. = ALIGN(4) ;
_rtc_force_fast_end = ABSOLUTE(.);
} > rtc_data_seg
/**
* RTC data section holds RTC wake stub
* data/rodata, including from any source file
* named rtc_wake_stub*.c and the data marked with
* RTC_DATA_ATTR, RTC_RODATA_ATTR attributes.
* The memory location of the data is dependent on
* CONFIG_ESP32H2_RTCDATA_IN_FAST_MEM option.
*/
.rtc.data :
{
_rtc_data_start = ABSOLUTE(.);
mapping[rtc_data]
*rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*)
_rtc_data_end = ABSOLUTE(.);
} > rtc_data_location
/* RTC bss, from any source file named rtc_wake_stub*.c */
.rtc.bss (NOLOAD) :
{
_rtc_bss_start = ABSOLUTE(.);
*rtc_wake_stub*.*(.bss .bss.*)
*rtc_wake_stub*.*(COMMON)
mapping[rtc_bss]
_rtc_bss_end = ABSOLUTE(.);
} > rtc_data_location
/**
* This section holds data that should not be initialized at power up
* and will be retained during deep sleep.
* User data marked with RTC_NOINIT_ATTR will be placed
* into this section. See the file "esp_attr.h" for more information.
* The memory location of the data is dependent on CONFIG_ESP32H2_RTCDATA_IN_FAST_MEM option.
*/
.rtc_noinit (NOLOAD):
{
. = ALIGN(4);
_rtc_noinit_start = ABSOLUTE(.);
*(.rtc_noinit .rtc_noinit.*)
. = ALIGN(4) ;
_rtc_noinit_end = ABSOLUTE(.);
} > rtc_data_location
/**
* This section located in RTC SLOW Memory area.
* It holds data marked with RTC_SLOW_ATTR attribute.
* See the file "esp_attr.h" for more information.
*/
.rtc.force_slow :
{
. = ALIGN(4);
_rtc_force_slow_start = ABSOLUTE(.);
*(.rtc.force_slow .rtc.force_slow.*)
. = ALIGN(4) ;
_rtc_force_slow_end = ABSOLUTE(.);
} > rtc_slow_seg
/* Get size of rtc slow data based on rtc_data_location alias */
_rtc_slow_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location))
? (_rtc_force_slow_end - _rtc_data_start)
: (_rtc_force_slow_end - _rtc_force_slow_start);
_rtc_fast_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location))
? (_rtc_force_fast_end - _rtc_fast_start)
: (_rtc_noinit_end - _rtc_fast_start);
ASSERT((_rtc_slow_length <= LENGTH(rtc_slow_seg)),
"RTC_SLOW segment data does not fit.")
ASSERT((_rtc_fast_length <= LENGTH(rtc_data_seg)),
"RTC_FAST segment data does not fit.")
.iram0.text :
{
_iram_start = ABSOLUTE(.);
/* Vectors go to start of IRAM */
ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
KEEP(*(.exception_vectors.text));
. = ALIGN(4);
_invalid_pc_placeholder = ABSOLUTE(.);
/* Code marked as running out of IRAM */
_iram_text_start = ABSOLUTE(.);
mapping[iram0_text]
} > iram0_0_seg
/**
* This section is required to skip .iram0.text area because iram0_0_seg and
* dram0_0_seg reflect the same address space on different buses.
*/
.dram0.dummy (NOLOAD):
{
. = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
} > dram0_0_seg
.dram0.data :
{
_data_start = ABSOLUTE(.);
*(.gnu.linkonce.d.*)
*(.data1)
__global_pointer$ = . + 0x800;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
_esp_system_init_fn_array_start = ABSOLUTE(.);
KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*)))
_esp_system_init_fn_array_end = ABSOLUTE(.);
mapping[dram0_data]
_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > dram0_0_seg
/**
* This section holds data that should not be initialized at power up.
* The section located in Internal SRAM memory region. The macro _NOINIT
* can be used as attribute to place data into this section.
* See the "esp_attr.h" file for more information.
*/
.noinit (NOLOAD):
{
. = ALIGN(4);
_noinit_start = ABSOLUTE(.);
*(.noinit .noinit.*)
. = ALIGN(4) ;
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.")
.flash.text :
{
_stext = .;
_instruction_reserved_start = ABSOLUTE(.);
_text_start = ABSOLUTE(.);
mapping[flash_text]
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
*(.fini.literal)
*(.fini)
*(.gnu.version)
/** CPU will try to prefetch up to 16 bytes of
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
* safe access to up to 16 bytes after the last real instruction, add
* dummy bytes to ensure this
*/
. += 16;
_text_end = ABSOLUTE(.);
_instruction_reserved_end = ABSOLUTE(.);
_etext = .;
/**
* Similar to _iram_start, this symbol goes here so it is
* resolved by addr2line in preference to the first symbol in
* the flash.text segment.
*/
_flash_cache_start = ABSOLUTE(0);
} > default_code_seg
/**
* This dummy section represents the .flash.text section but in default_rodata_seg.
* Thus, it must have its alignement and (at least) its size.
*/
.flash_rodata_dummy (NOLOAD):
{
_flash_rodata_dummy_start = .;
/* Start at the same alignement constraint than .flash.text */
. = ALIGN(ALIGNOF(.flash.text));
/* Create an empty gap as big as .flash.text section */
. = . + SIZEOF(.flash.text);
/* Prepare the alignement of the section above. Few bytes (0x20) must be
* added for the mapping header. */
. = ALIGN(0x10000) + 0x20;
_rodata_reserved_start = .;
} > default_rodata_seg
.flash.appdesc : ALIGN(0x10)
{
_rodata_start = ABSOLUTE(.);
*(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */
*(.rodata_custom_desc .rodata_custom_desc.*) /* Should be the second. Custom app version info. DO NOT PUT ANYTHING BEFORE IT! */
/* Create an empty gap within this section. Thanks to this, the end of this
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
.flash.rodata : ALIGN(0x10)
{
_flash_rodata_start = ABSOLUTE(.);
mapping[flash_rodata]
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table .gcc_except_table.*)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
. = (. + 3) & ~ 3;
__eh_frame = ABSOLUTE(.);
KEEP(*(.eh_frame))
. = (. + 7) & ~ 3;
/*
* C++ constructor and destructor tables
* Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt.
*
* RISC-V gcc is configured with --enable-initfini-array so it emits an .init_array section instead.
* But the init_priority sections will be sorted for iteration in ascending order during startup.
* The rest of the init_array sections is sorted for iteration in descending order during startup, however.
* Hence a different section is generated for the init_priority functions which is iterated in
* ascending order during startup. The corresponding code can be found in startup.c.
*/
__init_priority_array_start = ABSOLUTE(.);
KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))
__init_priority_array_end = ABSOLUTE(.);
__init_array_start = ABSOLUTE(.);
KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array))
__init_array_end = ABSOLUTE(.);
KEEP (*crtbegin.*(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
/* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */
soc_reserved_memory_region_start = ABSOLUTE(.);
KEEP (*(.reserved_memory_address))
soc_reserved_memory_region_end = ABSOLUTE(.);
_rodata_end = ABSOLUTE(.);
/* Literals are also RO data. */
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
*(.tbss)
*(.tbss.*)
*(.srodata)
*(.srodata.*)
_thread_local_end = ABSOLUTE(.);
_rodata_reserved_end = ABSOLUTE(.);
. = ALIGN(4);
} > default_rodata_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
{
/* C3 memprot requires 512 B alignment for split lines */
. = ALIGN (0x200);
/* iram_end_test section exists for use by memprot unit tests only */
*(.iram_end_test)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
.iram0.data :
{
. = ALIGN(16);
_iram_data_start = ABSOLUTE(.);
mapping[iram0_data]
_iram_data_end = ABSOLUTE(.);
} > iram0_0_seg
.iram0.bss (NOLOAD) :
{
. = ALIGN(16);
_iram_bss_start = ABSOLUTE(.);
mapping[iram0_bss]
_iram_bss_end = ABSOLUTE(.);
. = ALIGN(16);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/* Marks the end of data, bss and possibly rodata */
.dram0.heap_start (NOLOAD) :
{
. = ALIGN (16);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
}
ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View File

@@ -0,0 +1,616 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* INTERNAL API
* implementation of PMS memory protection features
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "soc/sensitive_reg.h"
#include "soc/dport_access.h"
#include "soc/periph_defs.h"
#include "esp_intr_alloc.h"
#include "hal/memprot_ll.h"
#include "esp32h2/memprot.h"
#include "riscv/interrupt.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp_log.h"
extern int _iram_text_end;
static const char *TAG = "memprot";
const char *esp_memprot_mem_type_to_str(mem_type_prot_t mem_type)
{
switch (mem_type) {
case MEMPROT_NONE:
return "NONE";
case MEMPROT_IRAM0_SRAM:
return "IRAM0_SRAM";
case MEMPROT_DRAM0_SRAM:
return "DRAM0_SRAM";
case MEMPROT_ALL:
return "ALL";
default:
return "UNKNOWN";
}
}
const char *esp_memprot_split_line_to_str(split_line_t line_type)
{
switch (line_type) {
case MEMPROT_IRAM0_DRAM0_SPLITLINE:
return "MEMPROT_IRAM0_DRAM0_SPLITLINE";
case MEMPROT_IRAM0_LINE_0_SPLITLINE:
return "MEMPROT_IRAM0_LINE_0_SPLITLINE";
case MEMPROT_IRAM0_LINE_1_SPLITLINE:
return "MEMPROT_IRAM0_LINE_1_SPLITLINE";
case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE:
return "MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE";
case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE:
return "MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE";
default:
return "UNKNOWN";
}
}
const char *esp_memprot_pms_to_str(pms_area_t area_type)
{
switch (area_type) {
case MEMPROT_IRAM0_PMS_AREA_0:
return "MEMPROT_IRAM0_PMS_AREA_0";
case MEMPROT_IRAM0_PMS_AREA_1:
return "MEMPROT_IRAM0_PMS_AREA_1";
case MEMPROT_IRAM0_PMS_AREA_2:
return "MEMPROT_IRAM0_PMS_AREA_2";
case MEMPROT_IRAM0_PMS_AREA_3:
return "MEMPROT_IRAM0_PMS_AREA_3";
case MEMPROT_DRAM0_PMS_AREA_0:
return "MEMPROT_DRAM0_PMS_AREA_0";
case MEMPROT_DRAM0_PMS_AREA_1:
return "MEMPROT_DRAM0_PMS_AREA_1";
case MEMPROT_DRAM0_PMS_AREA_2:
return "MEMPROT_DRAM0_PMS_AREA_2";
case MEMPROT_DRAM0_PMS_AREA_3:
return "MEMPROT_DRAM0_PMS_AREA_3";
default:
return "UNKNOWN";
}
}
/* split lines */
void *esp_memprot_get_default_main_split_addr()
{
return &_iram_text_end;
}
uint32_t *esp_memprot_get_split_addr(split_line_t line_type)
{
switch ( line_type ) {
case MEMPROT_IRAM0_DRAM0_SPLITLINE:
return memprot_ll_get_iram0_split_line_main_I_D();
case MEMPROT_IRAM0_LINE_0_SPLITLINE:
return memprot_ll_get_iram0_split_line_I_0();
case MEMPROT_IRAM0_LINE_1_SPLITLINE:
return memprot_ll_get_iram0_split_line_I_1();
case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE:
return memprot_ll_get_dram0_split_line_D_0();
case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE:
return memprot_ll_get_dram0_split_line_D_1();
default:
abort();
}
}
void esp_memprot_set_split_line_lock()
{
memprot_ll_set_iram0_dram0_split_line_lock();
}
bool esp_memprot_get_split_line_lock()
{
return memprot_ll_get_iram0_dram0_split_line_lock();
}
void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr)
{
ESP_EARLY_LOGD(TAG, "Setting split line %s, addr: 0x%08X", esp_memprot_split_line_to_str(line_type), (uint32_t)line_addr);
//split-line must be divisible by 512 (PMS module restriction)
assert( ((uint32_t)line_addr) % 0x200 == 0 );
switch ( line_type ) {
case MEMPROT_IRAM0_DRAM0_SPLITLINE:
memprot_ll_set_iram0_split_line_main_I_D(line_addr);
break;
case MEMPROT_IRAM0_LINE_0_SPLITLINE:
memprot_ll_set_iram0_split_line_I_0(line_addr);
break;
case MEMPROT_IRAM0_LINE_1_SPLITLINE:
memprot_ll_set_iram0_split_line_I_1(line_addr);
break;
case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE:
memprot_ll_set_dram0_split_line_D_0(line_addr);
break;
case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE:
memprot_ll_set_dram0_split_line_D_1(line_addr);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", (uint32_t)line_addr);
abort();
}
}
/* PMS */
void esp_memprot_set_pms_lock(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_pms_lock(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
memprot_ll_iram0_set_pms_lock();
break;
case MEMPROT_DRAM0_SRAM:
memprot_ll_dram0_set_pms_lock();
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_pms_lock();
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_pms_lock();
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", esp_memprot_pms_to_str(area_type), r, w, x);
switch ( area_type ) {
case MEMPROT_IRAM0_PMS_AREA_0:
memprot_ll_iram0_set_pms_area_0(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_1:
memprot_ll_iram0_set_pms_area_1(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_2:
memprot_ll_iram0_set_pms_area_2(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_3:
memprot_ll_iram0_set_pms_area_3(r, w, x);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type));
abort();
}
}
void esp_memprot_iram_get_pms_area(pms_area_t area_type, bool *r, bool *w, bool *x)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_iram_get_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w);
switch ( area_type ) {
case MEMPROT_IRAM0_PMS_AREA_0:
memprot_ll_iram0_get_pms_area_0(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_1:
memprot_ll_iram0_get_pms_area_1(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_2:
memprot_ll_iram0_get_pms_area_2(r, w, x);
break;
case MEMPROT_IRAM0_PMS_AREA_3:
memprot_ll_iram0_get_pms_area_3(r, w, x);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type));
abort();
}
}
void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w);
switch ( area_type ) {
case MEMPROT_DRAM0_PMS_AREA_0:
memprot_ll_dram0_set_pms_area_0(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_1:
memprot_ll_dram0_set_pms_area_1(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_2:
memprot_ll_dram0_set_pms_area_2(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_3:
memprot_ll_dram0_set_pms_area_3(r, w);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type));
abort();
}
}
void esp_memprot_dram_get_pms_area(pms_area_t area_type, bool *r, bool *w)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_dram_get_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w);
switch ( area_type ) {
case MEMPROT_DRAM0_PMS_AREA_0:
memprot_ll_dram0_get_pms_area_0(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_1:
memprot_ll_dram0_get_pms_area_1(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_2:
memprot_ll_dram0_get_pms_area_2(r, w);
break;
case MEMPROT_DRAM0_PMS_AREA_3:
memprot_ll_dram0_get_pms_area_3(r, w);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type));
abort();
}
}
/* monitor */
void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_lock(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
memprot_ll_iram0_set_monitor_lock();
break;
case MEMPROT_DRAM0_SRAM:
memprot_ll_dram0_set_monitor_lock();
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_lock();
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_lock();
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
memprot_ll_iram0_set_monitor_en(enable);
break;
case MEMPROT_DRAM0_SRAM:
memprot_ll_dram0_set_monitor_en(enable);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_en();
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_en();
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
bool esp_memprot_is_intr_ena_any()
{
return esp_memprot_get_monitor_en(MEMPROT_IRAM0_SRAM) || esp_memprot_get_monitor_en(MEMPROT_DRAM0_SRAM);
}
void esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", esp_memprot_mem_type_to_str(mem_type));
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
memprot_ll_iram0_clear_monitor_intr();
memprot_ll_iram0_reset_clear_monitor_intr();
break;
case MEMPROT_DRAM0_SRAM:
memprot_ll_dram0_clear_monitor_intr();
memprot_ll_dram0_reset_clear_monitor_intr();
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
mem_type_prot_t esp_memprot_get_active_intr_memtype()
{
if ( memprot_ll_iram0_get_monitor_status_intr() > 0 ) {
return MEMPROT_IRAM0_SRAM;
} else if ( memprot_ll_dram0_get_monitor_status_intr() ) {
return MEMPROT_DRAM0_SRAM;
}
return MEMPROT_NONE;
}
bool esp_memprot_is_locked_any()
{
return
esp_memprot_get_split_line_lock() ||
esp_memprot_get_pms_lock(MEMPROT_IRAM0_SRAM) ||
esp_memprot_get_pms_lock(MEMPROT_DRAM0_SRAM) ||
esp_memprot_get_monitor_lock(MEMPROT_IRAM0_SRAM) ||
esp_memprot_get_monitor_lock(MEMPROT_DRAM0_SRAM);
}
bool esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type)
{
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_status_intr() == 1;
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_status_intr() == 1;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
uint32_t esp_memprot_get_violate_addr(mem_type_prot_t mem_type)
{
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_status_fault_addr();
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_status_fault_addr();
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
pms_world_t esp_memprot_get_violate_world(mem_type_prot_t mem_type)
{
uint32_t world = 0;
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
world = memprot_ll_iram0_get_monitor_status_fault_world();
break;
case MEMPROT_DRAM0_SRAM:
world = memprot_ll_dram0_get_monitor_status_fault_world();
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
switch ( world ) {
case 0x01: return MEMPROT_PMS_WORLD_0;
case 0x10: return MEMPROT_PMS_WORLD_1;
default: return MEMPROT_PMS_WORLD_INVALID;
}
}
pms_operation_type_t esp_memprot_get_violate_wr(mem_type_prot_t mem_type)
{
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_status_fault_wr() == 1 ? MEMPROT_PMS_OP_WRITE : MEMPROT_PMS_OP_READ;
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_status_fault_wr() == 1 ? MEMPROT_PMS_OP_WRITE : MEMPROT_PMS_OP_READ;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
bool esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type)
{
switch ( mem_type ) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_status_fault_loadstore() == 1;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
uint32_t esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type)
{
switch ( mem_type ) {
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_status_fault_byte_en();
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
}
int esp_memprot_intr_get_cpuid()
{
return PRO_CPU_NUM;
}
void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", esp_memprot_mem_type_to_str(mem_type));
ESP_INTR_DISABLE(ETS_MEMPROT_ERR_INUM);
switch (mem_type) {
case MEMPROT_IRAM0_SRAM:
intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_iram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM);
break;
case MEMPROT_DRAM0_SRAM:
intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_dram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM);
break;
default:
ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type));
abort();
}
/* Set the type and priority to cache error interrupts. */
esprv_intc_int_set_type(BIT(ETS_MEMPROT_ERR_INUM), INTR_TYPE_LEVEL);
esprv_intc_int_set_priority(ETS_MEMPROT_ERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
ESP_INTR_ENABLE(ETS_MEMPROT_ERR_INUM);
}
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask)
{
esp_memprot_set_prot_int(invoke_panic_handler, lock_feature, NULL, mem_type_mask);
}
void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask)
{
ESP_EARLY_LOGD(TAG, "esp_memprot_set_prot(panic_handler: %u, lock: %u, split.addr: 0x%08X, mem.types: 0x%08X", invoke_panic_handler, lock_feature, (uint32_t)split_addr, (uint32_t)mem_type_mask);
uint32_t required_mem_prot = mem_type_mask == NULL ? (uint32_t)MEMPROT_ALL : *mem_type_mask;
bool use_iram0 = required_mem_prot & MEMPROT_IRAM0_SRAM;
bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM;
if (required_mem_prot == MEMPROT_NONE) {
return;
}
//disable protection
if (use_iram0) {
esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, false);
}
if (use_dram0) {
esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, false);
}
//panic handling
if (invoke_panic_handler) {
if (use_iram0) {
esp_memprot_set_intr_matrix(MEMPROT_IRAM0_SRAM);
}
if (use_dram0) {
esp_memprot_set_intr_matrix(MEMPROT_DRAM0_SRAM);
}
}
//set split lines (must-have for all mem_types)
const void *line_addr = split_addr == NULL ? esp_memprot_get_default_main_split_addr() : split_addr;
esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_1_SPLITLINE, line_addr);
esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_0_SPLITLINE, line_addr);
esp_memprot_set_split_line(MEMPROT_IRAM0_DRAM0_SPLITLINE, line_addr);
esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr)));
esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr)));
//set permissions
if (required_mem_prot & MEMPROT_IRAM0_SRAM) {
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_0, true, false, true);
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_1, true, false, true);
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_2, true, false, true);
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_3, true, true, false);
}
if (required_mem_prot & MEMPROT_DRAM0_SRAM) {
esp_memprot_dram_set_pms_area( MEMPROT_DRAM0_PMS_AREA_0, true, false );
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_1, true, true);
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_2, true, true);
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_3, true, true);
}
//reenable protection
if (use_iram0) {
esp_memprot_monitor_clear_intr(MEMPROT_IRAM0_SRAM);
esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, true);
}
if (use_dram0) {
esp_memprot_monitor_clear_intr(MEMPROT_DRAM0_SRAM);
esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, true);
}
//lock if required
if (lock_feature) {
esp_memprot_set_split_line_lock();
if (use_iram0) {
esp_memprot_set_pms_lock(MEMPROT_IRAM0_SRAM);
esp_memprot_set_monitor_lock(MEMPROT_IRAM0_SRAM);
}
if (use_dram0) {
esp_memprot_set_pms_lock(MEMPROT_DRAM0_SRAM);
esp_memprot_set_monitor_lock(MEMPROT_DRAM0_SRAM);
}
}
}
uint32_t esp_memprot_get_dram_status_reg_1()
{
return memprot_ll_dram0_get_monitor_status_register_1();
}
uint32_t esp_memprot_get_dram_status_reg_2()
{
return memprot_ll_dram0_get_monitor_status_register_2();
}
uint32_t esp_memprot_get_iram_status_reg()
{
return memprot_ll_iram0_get_monitor_status_register();
}
uint32_t esp_memprot_get_monitor_enable_reg(mem_type_prot_t mem_type)
{
switch (mem_type) {
case MEMPROT_IRAM0_SRAM:
return memprot_ll_iram0_get_monitor_enable_register();
case MEMPROT_DRAM0_SRAM:
return memprot_ll_dram0_get_monitor_enable_register();
default:
abort();
}
}

View File

@@ -0,0 +1,5 @@
set(compile_options "-Wno-error=format="
"-nostartfiles"
"-Wno-format")
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)

View File

@@ -0,0 +1,9 @@
if(IDF_TARGET STREQUAL "esp32h2")
idf_component_register(SRC_DIRS .
INCLUDE_DIRS . ${CMAKE_CURRENT_BINARY_DIR}
REQUIRES unity test_utils esp_common mbedtls
)
idf_build_set_property(COMPILE_DEFINITIONS "-DESP_TIMER_DYNAMIC_OVERFLOW_VAL" APPEND)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_test_dport_xt_highint5")
endif()

View File

@@ -0,0 +1,4 @@
#
# Component Makefile (not used for tests, but CI checks test parity between GNU Make & CMake)
#
COMPONENT_CONFIG_ONLY := 1

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,382 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "unity.h"
#include "esp32h2/rom/efuse.h"
#include "esp32h2/rom/digital_signature.h"
#include "esp32h2/rom/hmac.h"
#include <string.h>
#include "esp_ds.h"
#define NUM_RESULTS 10
#define DS_MAX_BITS (ETS_DS_MAX_BITS)
typedef struct {
uint8_t iv[ETS_DS_IV_LEN];
ets_ds_p_data_t p_data;
uint8_t expected_c[ETS_DS_C_LEN];
uint8_t hmac_key_idx;
uint32_t expected_results[NUM_RESULTS][DS_MAX_BITS/32];
} encrypt_testcase_t;
// Generated header (components/esp32s2/test/gen_digital_signature_tests.py) defines
// NUM_HMAC_KEYS, test_hmac_keys, NUM_MESSAGES, NUM_CASES, test_messages[], test_cases[]
#include "digital_signature_test_cases.h"
_Static_assert(NUM_RESULTS == NUM_MESSAGES, "expected_results size should be the same as NUM_MESSAGES in generated header");
TEST_CASE("Digital Signature Parameter Encryption data NULL", "[hw_crypto] [ds]")
{
const char iv [32];
esp_ds_p_data_t p_data;
const char key [32];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(NULL, iv, &p_data, key));
}
TEST_CASE("Digital Signature Parameter Encryption iv NULL", "[hw_crypto] [ds]")
{
esp_ds_data_t data;
esp_ds_p_data_t p_data;
const char key [32];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, NULL, &p_data, key));
}
TEST_CASE("Digital Signature Parameter Encryption p_data NULL", "[hw_crypto] [ds]")
{
esp_ds_data_t data;
const char iv [32];
const char key [32];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, iv, NULL, key));
}
TEST_CASE("Digital Signature Parameter Encryption key NULL", "[hw_crypto] [ds]")
{
esp_ds_data_t data;
const char iv [32];
esp_ds_p_data_t p_data;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, iv, &p_data, NULL));
}
TEST_CASE("Digital Signature Parameter Encryption", "[hw_crypto] [ds]")
{
for (int i = 0; i < NUM_CASES; i++) {
printf("Encrypting test case %d...\n", i);
const encrypt_testcase_t *t = &test_cases[i];
esp_ds_data_t result = { };
esp_ds_p_data_t p_data;
memcpy(p_data.Y, t->p_data.Y, ESP_DS_SIGNATURE_MAX_BIT_LEN/8);
memcpy(p_data.M, t->p_data.M, ESP_DS_SIGNATURE_MAX_BIT_LEN/8);
memcpy(p_data.Rb, t->p_data.Rb, ESP_DS_SIGNATURE_MAX_BIT_LEN/8);
p_data.M_prime = t->p_data.M_prime;
p_data.length = t->p_data.length;
esp_err_t r = esp_ds_encrypt_params(&result, t->iv, &p_data,
test_hmac_keys[t->hmac_key_idx]);
printf("Encrypting test case %d done\n", i);
TEST_ASSERT_EQUAL(ESP_OK, r);
TEST_ASSERT_EQUAL(t->p_data.length, result.rsa_length);
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->iv, result.iv, ETS_DS_IV_LEN);
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_c, result.c, ETS_DS_C_LEN);
}
}
TEST_CASE("Digital Signature start Invalid message", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = { };
ds_data.rsa_length = ESP_DS_RSA_3072;
esp_ds_context_t *ctx;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(NULL, &ds_data, HMAC_KEY1, &ctx));
}
TEST_CASE("Digital Signature start Invalid data", "[hw_crypto] [ds]")
{
const char *message = "test";
esp_ds_context_t *ctx;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, NULL, HMAC_KEY1, &ctx));
}
TEST_CASE("Digital Signature start Invalid context", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = ESP_DS_RSA_3072;
const char *message = "test";
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL));
}
TEST_CASE("Digital Signature RSA length 0", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = 0;
const char *message = "test";
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL));
}
TEST_CASE("Digital Signature RSA length too long", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = 128;
const char *message = "test";
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL));
}
TEST_CASE("Digital Signature start HMAC key out of range", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = ESP_DS_RSA_3072;
esp_ds_context_t *ctx;
const char *message = "test";
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY5 + 1, &ctx));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY0 - 1, &ctx));
}
TEST_CASE("Digital Signature finish Invalid signature ptr", "[hw_crypto] [ds]")
{
esp_ds_context_t *ctx = NULL;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_finish_sign(NULL, ctx));
}
TEST_CASE("Digital Signature finish Invalid context", "[hw_crypto] [ds]")
{
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_finish_sign(signature_data, NULL));
}
TEST_CASE("Digital Signature Blocking Invalid message", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = { };
ds_data.rsa_length = ESP_DS_RSA_3072;
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(NULL, &ds_data, HMAC_KEY1, signature_data));
}
TEST_CASE("Digital Signature Blocking Invalid data", "[hw_crypto] [ds]")
{
const char *message = "test";
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, NULL, HMAC_KEY1, signature_data));
}
TEST_CASE("Digital Signature Blocking Invalid signature ptr", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = ESP_DS_RSA_3072;
const char *message = "test";
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, NULL));
}
TEST_CASE("Digital Signature Blocking RSA length 0", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = 0;
const char *message = "test";
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, signature_data));
}
TEST_CASE("Digital Signature Blocking RSA length too long", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = 128;
const char *message = "test";
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, signature_data));
}
TEST_CASE("Digital Signature Blocking HMAC key out of range", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = 127;
const char *message = "test";
uint8_t signature_data [128 * 4];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY5 + 1, signature_data));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY0 - 1, signature_data));
}
#if CONFIG_IDF_ENV_FPGA
// Burn eFuse blocks 1, 2 and 3. Block 0 is used for HMAC tests already.
static void burn_hmac_keys(void)
{
printf("Burning %d HMAC keys to efuse...\n", NUM_HMAC_KEYS);
for (int i = 0; i < NUM_HMAC_KEYS; i++) {
// TODO: vary the purpose across the keys
ets_efuse_purpose_t purpose = ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE;
ets_efuse_write_key(ETS_EFUSE_BLOCK_KEY1 + i,
purpose,
test_hmac_keys[i], 32);
}
/* verify the keys are what we expect (possibly they're already burned, doesn't matter but they have to match) */
uint8_t block_compare[32];
for (int i = 0; i < NUM_HMAC_KEYS; i++) {
printf("Checking key %d...\n", i);
memcpy(block_compare, (void *)ets_efuse_get_read_register_address(ETS_EFUSE_BLOCK_KEY1 + i), 32);
TEST_ASSERT_EQUAL_HEX8_ARRAY(test_hmac_keys[i], block_compare, 32);
}
}
// This test uses the HMAC_KEY0 eFuse key which hasn't been burned by burn_hmac_keys().
// HMAC_KEY0 is usually used for HMAC upstream (user access) tests.
TEST_CASE("Digital Signature wrong HMAC key purpose (FPGA only)", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = ESP_DS_RSA_3072;
esp_ds_context_t *ctx;
const char *message = "test";
// HMAC fails in that case because it checks for the correct purpose
TEST_ASSERT_EQUAL(ESP32H2_ERR_HW_CRYPTO_DS_HMAC_FAIL, esp_ds_start_sign(message, &ds_data, HMAC_KEY0, &ctx));
}
// This test uses the HMAC_KEY0 eFuse key which hasn't been burned by burn_hmac_keys().
// HMAC_KEY0 is usually used for HMAC upstream (user access) tests.
TEST_CASE("Digital Signature Blocking wrong HMAC key purpose (FPGA only)", "[hw_crypto] [ds]")
{
esp_ds_data_t ds_data = {};
ds_data.rsa_length = ESP_DS_RSA_3072;
const char *message = "test";
uint8_t signature_data [128 * 4];
// HMAC fails in that case because it checks for the correct purpose
TEST_ASSERT_EQUAL(ESP32H2_ERR_HW_CRYPTO_DS_HMAC_FAIL, esp_ds_sign(message, &ds_data, HMAC_KEY0, signature_data));
}
TEST_CASE("Digital Signature Operation (FPGA only)", "[hw_crypto] [ds]")
{
burn_hmac_keys();
for (int i = 0; i < NUM_CASES; i++) {
printf("Running test case %d...\n", i);
const encrypt_testcase_t *t = &test_cases[i];
// copy encrypt parameter test case into ds_data structure
esp_ds_data_t ds_data = { };
memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN);
memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN);
ds_data.rsa_length = t->p_data.length;
for (int j = 0; j < NUM_MESSAGES; j++) {
uint8_t signature[DS_MAX_BITS/8] = { 0 };
printf(" ... message %d\n", j);
esp_ds_context_t *esp_ds_ctx;
esp_err_t ds_r = esp_ds_start_sign(test_messages[j],
&ds_data,
t->hmac_key_idx + 1,
&esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP_OK, ds_r);
ds_r = esp_ds_finish_sign(signature, esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP_OK, ds_r);
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_results[j], signature, sizeof(signature));
}
ets_hmac_invalidate_downstream(ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE);
}
}
TEST_CASE("Digital Signature Blocking Operation (FPGA only)", "[hw_crypto] [ds]")
{
burn_hmac_keys();
for (int i = 0; i < NUM_CASES; i++) {
printf("Running test case %d...\n", i);
const encrypt_testcase_t *t = &test_cases[i];
// copy encrypt parameter test case into ds_data structure
esp_ds_data_t ds_data = { };
memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN);
memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN);
ds_data.rsa_length = t->p_data.length;
uint8_t signature[DS_MAX_BITS/8] = { 0 };
esp_err_t ds_r = esp_ds_sign(test_messages[0],
&ds_data,
t->hmac_key_idx + 1,
signature);
TEST_ASSERT_EQUAL(ESP_OK, ds_r);
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_results[0], signature, sizeof(signature));
}
}
TEST_CASE("Digital Signature Invalid Data (FPGA only)", "[hw_crypto] [ds]")
{
burn_hmac_keys();
// Set up a valid test case
const encrypt_testcase_t *t = &test_cases[0];
esp_ds_data_t ds_data = { };
memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN);
memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN);
ds_data.rsa_length = t->p_data.length;
uint8_t signature[DS_MAX_BITS/8] = { 0 };
const uint8_t zero[DS_MAX_BITS/8] = { 0 };
// Corrupt the IV one bit at a time, rerun and expect failure
for (int bit = 0; bit < 128; bit++) {
printf("Corrupting IV bit %d...\n", bit);
ds_data.iv[bit / 8] ^= 1 << (bit % 8);
esp_ds_context_t *esp_ds_ctx;
esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP_OK, ds_r);
ds_r = esp_ds_finish_sign(signature, esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP32H2_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r);
TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS/8);
ds_data.iv[bit / 8] ^= 1 << (bit % 8);
}
// Corrupt encrypted key data one bit at a time, rerun and expect failure
printf("Corrupting C...\n");
for (int bit = 0; bit < ETS_DS_C_LEN * 8; bit++) {
printf("Corrupting C bit %d...\n", bit);
ds_data.c[bit / 8] ^= 1 << (bit % 8);
esp_ds_context_t *esp_ds_ctx;
esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP_OK, ds_r);
ds_r = esp_ds_finish_sign(signature, esp_ds_ctx);
TEST_ASSERT_EQUAL(ESP32H2_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r);
TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS/8);
ds_data.c[bit / 8] ^= 1 << (bit % 8);
}
}
#endif // CONFIG_IDF_ENV_FPGA

View File

@@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_types.h"
#include "esp32h2/clk.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_heap_caps.h"
#include "idf_performance.h"
#include "unity.h"
#include "test_utils.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "sha/sha_dma.h"
/* Note: Most of the SHA functions are called as part of mbedTLS, so
are tested as part of mbedTLS tests. Only esp_sha() is different.
*/
#define TAG "sha_test"
TEST_CASE("Test esp_sha()", "[hw_crypto]")
{
const size_t BUFFER_SZ = 32 * 1024 + 6; // NB: not an exact multiple of SHA block size
int64_t begin, end;
uint32_t us_sha1;
uint8_t sha1_result[20] = { 0 };
void *buffer = heap_caps_malloc(BUFFER_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buffer);
memset(buffer, 0xEE, BUFFER_SZ);
const uint8_t sha1_expected[20] = { 0xc7, 0xbb, 0xd3, 0x74, 0xf2, 0xf6, 0x20, 0x86,
0x61, 0xf4, 0x50, 0xd5, 0xf5, 0x18, 0x44, 0xcc,
0x7a, 0xb7, 0xa5, 0x4a };
begin = esp_timer_get_time();
esp_sha(SHA1, buffer, BUFFER_SZ, sha1_result);
end = esp_timer_get_time();
TEST_ASSERT_EQUAL_HEX8_ARRAY(sha1_expected, sha1_result, sizeof(sha1_expected));
us_sha1 = end - begin;
ESP_LOGI(TAG, "esp_sha() 32KB SHA1 in %u us", us_sha1);
free(buffer);
TEST_PERFORMANCE_CCOMP_LESS_THAN(TIME_SHA1_32KB, "%dus", us_sha1);
}
TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]")
{
const void* ptr;
spi_flash_mmap_handle_t handle;
uint8_t sha1_espsha[20] = { 0 };
uint8_t sha1_mbedtls[20] = { 0 };
uint8_t sha256_espsha[32] = { 0 };
uint8_t sha256_mbedtls[32] = { 0 };
const size_t LEN = 1024 * 1024;
/* mmap() 1MB of flash, we don't care what it is really */
esp_err_t err = spi_flash_mmap(0x0, LEN, SPI_FLASH_MMAP_DATA, &ptr, &handle);
TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
TEST_ASSERT_NOT_NULL(ptr);
/* Compare esp_sha() result to the mbedTLS result, should always be the same */
esp_sha(SHA1, ptr, LEN, sha1_espsha);
int r = mbedtls_sha1_ret(ptr, LEN, sha1_mbedtls);
TEST_ASSERT_EQUAL(0, r);
esp_sha(SHA2_256, ptr, LEN, sha256_espsha);
r = mbedtls_sha256_ret(ptr, LEN, sha256_mbedtls, 0);
TEST_ASSERT_EQUAL(0, r);
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha1_espsha, sha1_mbedtls, sizeof(sha1_espsha), "SHA1 results should match");
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_espsha, sha256_mbedtls, sizeof(sha256_espsha), "SHA256 results should match");
}

View File

@@ -14,4 +14,9 @@ elseif(${target} STREQUAL "esp32c3")
idf_component_register(SRCS "esp_adc_cal_esp32c3.c" idf_component_register(SRCS "esp_adc_cal_esp32c3.c"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES driver efuse) REQUIRES driver efuse)
elseif(${target} STREQUAL "esp32h2")
idf_component_register(SRCS "esp_adc_cal_esp32h2.c"
INCLUDE_DIRS "include"
REQUIRES driver efuse)
endif() endif()

View File

@@ -3,4 +3,4 @@
# #
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_OBJEXCLUDE += esp_adc_cal_esp32s2.o esp_adc_cal_esp32c3.o COMPONENT_OBJEXCLUDE += esp_adc_cal_esp32s2.o esp_adc_cal_esp32c3.o esp_adc_cal_esp32h2.o

View File

@@ -0,0 +1,170 @@
// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/adc.h"
#include "hal/adc_ll.h"
#include "esp_efuse_rtc_calib.h"
#include "esp_adc_cal.h"
#define ADC_CALIB_CHECK(cond, err_msg, ret) do {\
if (!(cond)) { \
ESP_LOGE(LOG_TAG, err_msg); \
return (ret); \
} \
} while(0)
const static char LOG_TAG[] = "adc_calib";
/* ------------------------ Characterization Constants ---------------------- */
// coeff_a and coeff_b are actually floats
// they are scaled to put them into uint32_t so that the headers do not have to be changed
static const int coeff_a_scaling = 65536;
static const int coeff_b_scaling = 1024;
/* -------------------- Characterization Helper Data Types ------------------ */
typedef struct {
uint32_t voltage;
uint32_t digi;
} adc_calib_data_ver1;
typedef struct {
char version_num;
adc_unit_t adc_num;
adc_atten_t atten_level;
union {
adc_calib_data_ver1 ver1;
} efuse_data;
} adc_calib_parsed_info;
static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage)
{
assert(version_num == 1);
esp_err_t ret;
parsed_data_storage->version_num = version_num;
parsed_data_storage->adc_num = adc_num;
parsed_data_storage->atten_level = atten;
// V1 we don't have calibration data for ADC2, using the efuse data of ADC1
uint32_t voltage, digi;
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, atten, &digi, &voltage);
if (ret != ESP_OK) {
return ret;
}
parsed_data_storage->efuse_data.ver1.voltage = voltage;
parsed_data_storage->efuse_data.ver1.digi = digi;
return ret;
}
/* ----------------------- Characterization Functions ----------------------- */
/*
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
* with the previously done measurement when the chip was manufactured.
*/
static void calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars)
{
ESP_LOGD(LOG_TAG, "Calib V1, Cal Voltage = %d, Digi out = %d\n", parsed_data->efuse_data.ver1.voltage, parsed_data->efuse_data.ver1.digi);
chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver1.voltage / parsed_data->efuse_data.ver1.digi;
chars->coeff_b = 0;
}
/* ------------------------- Public API ------------------------------------- */
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
if (adc_encoding_version != 1) {
// current version only accepts encoding ver 1.
return ESP_ERR_INVALID_VERSION;
}
return ESP_OK;
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
esp_err_t ret;
adc_calib_parsed_info efuse_parsed_data = {0};
// Check parameters
ADC_CALIB_CHECK(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, "Invalid unit num", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(chars != NULL, "Invalid characteristic", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(bit_width == ADC_WIDTH_BIT_12, "Invalid bit_width", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(atten < 4, "Invalid attenuation", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
int version_num = esp_efuse_rtc_calib_get_ver();
ADC_CALIB_CHECK(version_num == 1, "No calibration efuse burnt", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
// make sure adc is calibrated.
ret = prepare_calib_data_for(version_num, adc_num, atten, &efuse_parsed_data);
if (ret != ESP_OK) {
abort();
}
calculate_characterization_coefficients(&efuse_parsed_data, chars);
ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%d B:%d\n", adc_num, atten, chars->coeff_a, chars->coeff_b);
// Initialize remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
// in esp32h2 we only use the two point method to calibrate the adc.
return ESP_ADC_CAL_VAL_EFUSE_TP;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
ADC_CALIB_CHECK(chars != NULL, "No characteristic input.", ESP_ERR_INVALID_ARG);
return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
}
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
const esp_adc_cal_characteristics_t *chars,
uint32_t *voltage)
{
// Check parameters
ADC_CALIB_CHECK(chars != NULL, "No characteristic input.", ESP_ERR_INVALID_ARG);
ADC_CALIB_CHECK(voltage != NULL, "No output buffer.", ESP_ERR_INVALID_ARG);
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
//Check if channel is valid on ADC1
ADC_CALIB_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, "Invalid channel", ESP_ERR_INVALID_ARG);
adc_reading = adc1_get_raw(channel);
} else {
//Check if channel is valid on ADC2
ADC_CALIB_CHECK((adc2_channel_t)channel < ADC2_CHANNEL_MAX, "Invalid channel", ESP_ERR_INVALID_ARG);
if (adc2_get_raw(channel, chars->bit_width, &adc_reading) != ESP_OK) {
return ESP_ERR_TIMEOUT; //Timed out waiting for ADC2
}
}
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
return ESP_OK;
}

View File

@@ -28,6 +28,7 @@ esp_err_t esp_event_send_noop(system_event_t *event)
return ESP_OK; return ESP_OK;
} }
#if CONFIG_ESP32_WIFI_ENABLED
static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id) static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id)
{ {
switch (event_id) { switch (event_id) {
@@ -102,6 +103,7 @@ static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id)
return SYSTEM_EVENT_MAX; return SYSTEM_EVENT_MAX;
} }
} }
#endif // CONFIG_ESP32_WIFI_ENABLED
static system_event_id_t esp_event_legacy_ip_event_id(int32_t event_id) static system_event_id_t esp_event_legacy_ip_event_id(int32_t event_id)
{ {
@@ -133,9 +135,13 @@ static system_event_id_t esp_event_legacy_ip_event_id(int32_t event_id)
static system_event_id_t esp_event_legacy_event_id(esp_event_base_t event_base, int32_t event_id) static system_event_id_t esp_event_legacy_event_id(esp_event_base_t event_base, int32_t event_id)
{ {
#if CONFIG_ESP32_WIFI_ENABLED
if (event_base == WIFI_EVENT) { if (event_base == WIFI_EVENT) {
return esp_event_legacy_wifi_event_id(event_id); return esp_event_legacy_wifi_event_id(event_id);
} else if (event_base == IP_EVENT) { }
#endif
if (event_base == IP_EVENT) {
return esp_event_legacy_ip_event_id(event_id); return esp_event_legacy_ip_event_id(event_id);
} else { } else {
ESP_LOGE(TAG, "invalid event base %s", event_base); ESP_LOGE(TAG, "invalid event base %s", event_base);

View File

@@ -0,0 +1,124 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "soc/uart_periph.h"
#include "soc/gpio_periph.h"
#include "soc/soc.h"
#include "soc/usb_serial_jtag_struct.h"
#include "hal/usb_serial_jtag_ll.h"
#include "esp_gdbstub_common.h"
#include "sdkconfig.h"
#define UART_NUM CONFIG_ESP_CONSOLE_UART_NUM
#define GDBSTUB_MEM_REGION_COUNT 9
#define UART_REG_FIELD_LEN 0x84
typedef struct {
intptr_t lower;
intptr_t upper;
} mem_bound_t;
static const mem_bound_t mem_region_table [GDBSTUB_MEM_REGION_COUNT] =
{
{SOC_DROM_LOW, SOC_DROM_HIGH},
{SOC_IROM_LOW, SOC_IROM_HIGH},
{SOC_IRAM_LOW, SOC_IRAM_HIGH},
{SOC_DRAM_LOW, SOC_DRAM_HIGH},
{SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH},
{SOC_DROM_MASK_LOW, SOC_DROM_MASK_HIGH},
{SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH},
// RTC DRAM and RTC DATA are identical with RTC IRAM, hence we skip them
// We shouldn't read the uart registers since it will disturb the debugging via UART,
// so skip UART part of the peripheral registers.
{DR_REG_UART_BASE + UART_REG_FIELD_LEN, SOC_PERIPHERAL_HIGH},
{SOC_DEBUG_LOW, SOC_DEBUG_HIGH},
};
static inline bool check_inside_valid_region(intptr_t addr)
{
for (size_t i = 0; i < GDBSTUB_MEM_REGION_COUNT; i++) {
if (addr >= mem_region_table[i].lower && addr < mem_region_table[i].upper) {
return true;
}
}
return false;
}
void esp_gdbstub_target_init()
{
}
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
int esp_gdbstub_getchar()
{
uint8_t c;
//retry the read until we succeed
while (usb_serial_jtag_ll_read_rxfifo(&c, 1)==0) ;
return c;
}
void esp_gdbstub_putchar(int c)
{
uint8_t cc=c;
//retry the write until we succeed
while (usb_serial_jtag_ll_write_txfifo(&cc, 1)<1) ;
}
void esp_gdbstub_flush()
{
usb_serial_jtag_ll_txfifo_flush();
}
#else
//assume UART gdbstub channel
int esp_gdbstub_getchar()
{
while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_RXFIFO_CNT) == 0) {
;
}
return REG_READ(UART_FIFO_AHB_REG(UART_NUM));
}
void esp_gdbstub_putchar(int c)
{
while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_TXFIFO_CNT) >= 126) {
;
}
REG_WRITE(UART_FIFO_AHB_REG(UART_NUM), c);
}
void esp_gdbstub_flush()
{
//not needed for uart
}
#endif
int esp_gdbstub_readmem(intptr_t addr)
{
if (!check_inside_valid_region(addr)) {
/* see esp_cpu_configure_region_protection */
return -1;
}
uint32_t val_aligned = *(uint32_t *)(addr & (~3));
uint32_t shift = (addr & 3) * 8;
return (val_aligned >> shift) & 0xff;
}

View File

@@ -0,0 +1,15 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once

View File

@@ -81,7 +81,8 @@ bool IRAM_ATTR esp_cpu_in_ocd_debug_mode(void)
#if CONFIG_ESP32_DEBUG_OCDAWARE || \ #if CONFIG_ESP32_DEBUG_OCDAWARE || \
CONFIG_ESP32S2_DEBUG_OCDAWARE || \ CONFIG_ESP32S2_DEBUG_OCDAWARE || \
CONFIG_ESP32S3_DEBUG_OCDAWARE || \ CONFIG_ESP32S3_DEBUG_OCDAWARE || \
CONFIG_ESP32C3_DEBUG_OCDAWARE CONFIG_ESP32C3_DEBUG_OCDAWARE || \
CONFIG_ESP32H2_DEBUG_OCDAWARE
return cpu_ll_is_debugger_attached(); return cpu_ll_is_debugger_attached();
#else #else
return false; // Always return false if "OCD aware" is disabled return false; // Always return false if "OCD aware" is disabled

View File

@@ -36,6 +36,10 @@
#include "esp32c3/rom/rtc.h" #include "esp32c3/rom/rtc.h"
#include "esp32c3/clk.h" #include "esp32c3/clk.h"
#include "esp32c3/rtc.h" #include "esp32c3/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#include "esp32h2/clk.h"
#include "esp32h2/rtc.h"
#endif #endif
#define MHZ (1000000) #define MHZ (1000000)
@@ -53,7 +57,7 @@ static RTC_DATA_ATTR uint64_t s_esp_rtc_time_us = 0, s_rtc_last_ticks = 0;
inline static int IRAM_ATTR s_get_cpu_freq_mhz(void) inline static int IRAM_ATTR s_get_cpu_freq_mhz(void)
{ {
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
return ets_get_cpu_frequency(); return ets_get_cpu_frequency();
#else #else
return g_ticks_per_us_pro; return g_ticks_per_us_pro;
@@ -75,7 +79,7 @@ int IRAM_ATTR esp_clk_xtal_freq(void)
return rtc_clk_xtal_freq_get() * MHZ; return rtc_clk_xtal_freq_get() * MHZ;
} }
#ifndef CONFIG_IDF_TARGET_ESP32C3 #if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
{ {
/* Update scale factors used by esp_rom_delay_us */ /* Update scale factors used by esp_rom_delay_us */

View File

@@ -29,6 +29,8 @@
#include "esp32s3/clk.h" #include "esp32s3/clk.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/clk.h" #include "esp32c3/clk.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/clk.h"
#endif #endif
uint32_t IRAM_ATTR esp_random(void) uint32_t IRAM_ATTR esp_random(void)

View File

@@ -32,6 +32,7 @@ typedef enum {
CHIP_ESP32S2 = 2, //!< ESP32-S2 CHIP_ESP32S2 = 2, //!< ESP32-S2
CHIP_ESP32S3 = 4, //!< ESP32-S3 CHIP_ESP32S3 = 4, //!< ESP32-S3
CHIP_ESP32C3 = 5, //!< ESP32-C3 CHIP_ESP32C3 = 5, //!< ESP32-C3
CHIP_ESP32H2 = 6, //!< ESP32-H2
} esp_chip_model_t; } esp_chip_model_t;
/* Chip feature flags, used in esp_chip_info_t */ /* Chip feature flags, used in esp_chip_info_t */
@@ -39,6 +40,7 @@ typedef enum {
#define CHIP_FEATURE_WIFI_BGN BIT(1) //!< Chip has 2.4GHz WiFi #define CHIP_FEATURE_WIFI_BGN BIT(1) //!< Chip has 2.4GHz WiFi
#define CHIP_FEATURE_BLE BIT(4) //!< Chip has Bluetooth LE #define CHIP_FEATURE_BLE BIT(4) //!< Chip has Bluetooth LE
#define CHIP_FEATURE_BT BIT(5) //!< Chip has Bluetooth Classic #define CHIP_FEATURE_BT BIT(5) //!< Chip has Bluetooth Classic
#define CHIP_FEATURE_IEEE802154 BIT(6) //!< Chip has IEEE 802.15.4
/** /**
* @brief The structure represents information about the chip * @brief The structure represents information about the chip

View File

@@ -26,6 +26,7 @@ typedef enum {
ESP_MAC_WIFI_SOFTAP, ESP_MAC_WIFI_SOFTAP,
ESP_MAC_BT, ESP_MAC_BT,
ESP_MAC_ETH, ESP_MAC_ETH,
ESP_MAC_IEEE802154,
} esp_mac_type_t; } esp_mac_type_t;
/** @cond */ /** @cond */
@@ -39,6 +40,8 @@ typedef enum {
#define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES #define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES #define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES
#elif CONFIG_IDF_TARGET_ESP32H2
#define UNIVERSAL_MAC_ADDR_NUM CONFIG_ESP32H2_UNIVERSAL_MAC_ADDRESSES
#endif #endif
/** @endcond */ /** @endcond */

View File

@@ -0,0 +1,16 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp_private/esp_clk.h"

View File

@@ -41,6 +41,8 @@
#include "esp32s3/rom/ets_sys.h" #include "esp32s3/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h" #include "esp32c3/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/ets_sys.h"
#endif #endif
#define SOC_LOGE(tag, fmt, ...) esp_rom_printf("%s(err): " fmt, tag, ##__VA_ARGS__) #define SOC_LOGE(tag, fmt, ...) esp_rom_printf("%s(err): " fmt, tag, ##__VA_ARGS__)

View File

@@ -9,5 +9,5 @@ entries:
rtc_pm (noflash_text) rtc_pm (noflash_text)
rtc_sleep (noflash_text) rtc_sleep (noflash_text)
rtc_time (noflash_text) rtc_time (noflash_text)
if IDF_TARGET_ESP32C3 = n: if IDF_TARGET_ESP32C3 = n && IDF_TARGET_ESP32H2 = n:
rtc_wdt (noflash_text) rtc_wdt (noflash_text)

View File

@@ -0,0 +1,24 @@
set(srcs "cpu_util_esp32h2.c"
"rtc_clk_init.c"
"rtc_clk.c"
"rtc_init.c"
"rtc_pm.c"
"rtc_sleep.c"
"rtc_time.c"
"chip_info.c"
)
if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "../async_memcpy_impl_gdma.c")
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)
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
set_source_files_properties("${CMAKE_CURRENT_LIST_DIR}/rtc_clk.c" PROPERTIES
COMPILE_FLAGS "-fno-jump-tables -fno-tree-switch-conversion")
endif()

View File

@@ -0,0 +1,18 @@
# ESP32H2-TODO: IDF-3390
choice ESP32H2_UNIVERSAL_MAC_ADDRESSES
bool "Number of universally administered (by IEEE) MAC address"
default ESP32H2_UNIVERSAL_MAC_ADDRESSES_TWO
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.
config ESP32H2_UNIVERSAL_MAC_ADDRESSES_TWO
bool "Two"
select ESP_MAC_ADDR_UNIVERSE_IEEE802154
select ESP_MAC_ADDR_UNIVERSE_BT
endchoice
config ESP32H2_UNIVERSAL_MAC_ADDRESSES
int
default 2 if ESP32H2_UNIVERSAL_MAC_ADDRESSES_TWO

View File

@@ -0,0 +1,26 @@
// Copyright 2013-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_chip_info.h"
#include "esp_efuse.h"
void esp_chip_info(esp_chip_info_t *out_info)
{
memset(out_info, 0, sizeof(*out_info));
out_info->model = CHIP_ESP32H2;
out_info->revision = esp_efuse_get_chip_ver();
out_info->cores = 1;
out_info->features = CHIP_FEATURE_IEEE802154 | CHIP_FEATURE_BLE;
}

View File

@@ -0,0 +1,112 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <assert.h>
#include "soc/cpu.h"
void esp_cpu_configure_region_protection(void)
{
/* Notes on implementation:
*
* 1) Note: ESP32-C3 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 R = PMP_L | PMP_TOR | PMP_R;
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 & DROM (flash cache)
PMP_ENTRY_SET(2, SOC_DROM_LOW, NONE);
_Static_assert(SOC_DEBUG_HIGH < SOC_DROM_LOW, "Invalid PMP entry order");
// 4. DROM (flash cache)
// 5. Gap between DROM & DRAM
// (Note: To save PMP entries these two are merged into one read-only region)
PMP_ENTRY_SET(3, SOC_DRAM_LOW, R);
_Static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid DROM region");
_Static_assert(SOC_DROM_HIGH < SOC_DRAM_LOW, "Invalid PMP entry order");
// 6. DRAM
PMP_ENTRY_SET(4, SOC_DRAM_HIGH, RW);
_Static_assert(SOC_DRAM_LOW < SOC_DRAM_HIGH, "Invalid DRAM region");
// 7. Gap between DRAM and Mask DROM
// 8. Mask DROM
// (Note: to save PMP entries these two are merged into one read-only region)
PMP_ENTRY_SET(5, SOC_DROM_MASK_HIGH, R);
_Static_assert(SOC_DRAM_HIGH < SOC_DROM_MASK_LOW, "Invalid PMP entry order");
_Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid mask DROM region");
// 9. Gap between mask DROM and mask IROM
// 10. Mask IROM
// (Note: to save PMP entries these two are merged into one RX region)
PMP_ENTRY_SET(6, SOC_IROM_MASK_HIGH, RX);
_Static_assert(SOC_DROM_MASK_HIGH < SOC_IROM_MASK_LOW, "Invalid PMP entry order");
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid mask IROM region");
// 11. Gap between mask IROM & IRAM
PMP_ENTRY_SET(7, SOC_IRAM_LOW, NONE);
_Static_assert(SOC_IROM_MASK_HIGH < SOC_IRAM_LOW, "Invalid PMP entry order");
// 12. IRAM
PMP_ENTRY_SET(8, SOC_IRAM_HIGH, RWX);
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid IRAM region");
// 13. Gap between IRAM and IROM
// 14. IROM (flash cache)
// (Note: to save PMP entries these two are merged into one RX region)
PMP_ENTRY_SET(9, SOC_IROM_HIGH, RX);
_Static_assert(SOC_IRAM_HIGH < SOC_IROM_LOW, "Invalid PMP entry order");
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid IROM region");
// 15. Gap between IROM & RTC slow memory
PMP_ENTRY_SET(10, SOC_RTC_IRAM_LOW, NONE);
_Static_assert(SOC_IROM_HIGH < SOC_RTC_IRAM_LOW, "Invalid PMP entry order");
// 16. RTC fast memory
PMP_ENTRY_SET(11, SOC_RTC_IRAM_HIGH, RWX);
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
// 17. Gap between RTC fast memory & peripheral addresses
PMP_ENTRY_SET(12, SOC_PERIPHERAL_LOW, NONE);
_Static_assert(SOC_RTC_IRAM_HIGH < SOC_PERIPHERAL_LOW, "Invalid PMP entry order");
// 18. Peripheral addresses
PMP_ENTRY_SET(13, SOC_PERIPHERAL_HIGH, RW);
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
// 19. End of address space
PMP_ENTRY_SET(14, UINT32_MAX, NONE); // all but last 4 bytes
PMP_ENTRY_SET(15, UINT32_MAX, PMP_L | PMP_NA4); // last 4 bytes
}

View File

@@ -0,0 +1,30 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file i2c_brownout.h
* @brief Register definitions for brownout detector
*
* This file lists register fields of the brownout detector, located on an internal configuration
* bus. These definitions are used via macros defined in i2c_rtc_clk.h.
*/
#define I2C_BOD 0x61
#define I2C_BOD_HOSTID 1
#define I2C_BOD_THRESHOLD 0x5
#define I2C_BOD_THRESHOLD_MSB 2
#define I2C_BOD_THRESHOLD_LSB 0

View File

@@ -0,0 +1,48 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "regi2c_ctrl.h"
/* Analog function control register */
#define ANA_CONFIG_REG 0x6000E044
#define ANA_CONFIG_S (8)
#define ANA_CONFIG_M (0x3FF)
/* Clear to enable APLL */
#define I2C_APLL_M (BIT(14))
/* Clear to enable BBPLL */
#define I2C_BBPLL_M (BIT(17))
/* ROM functions which read/write internal control bus */
uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
uint8_t rom_i2c_readReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb);
void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void rom_i2c_writeReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* Convenience macros for the above functions, these use register definitions
* from i2c_apll.h/i2c_bbpll.h header files.
*/
#define I2C_WRITEREG_MASK_RTC(block, reg_add, indata) \
rom_i2c_writeReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata)
#define I2C_READREG_MASK_RTC(block, reg_add) \
rom_i2c_readReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB)
#define I2C_WRITEREG_RTC(block, reg_add, indata) \
rom_i2c_writeReg(block, block##_HOSTID, reg_add, indata)
#define I2C_READREG_RTC(block, reg_add) \
rom_i2c_readReg(block, block##_HOSTID, reg_add)

View File

@@ -0,0 +1,183 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_bbpll.h
* @brief Register definitions for digital PLL (BBPLL)
*
* This file lists register fields of BBPLL, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* rtc_clk_cpu_freq_set function in rtc_clk.c.
*/
#define I2C_BBPLL 0x66
#define I2C_BBPLL_HOSTID 0
#define I2C_BBPLL_IR_CAL_DELAY 0
#define I2C_BBPLL_IR_CAL_DELAY_MSB 3
#define I2C_BBPLL_IR_CAL_DELAY_LSB 0
#define I2C_BBPLL_IR_CAL_CK_DIV 0
#define I2C_BBPLL_IR_CAL_CK_DIV_MSB 7
#define I2C_BBPLL_IR_CAL_CK_DIV_LSB 4
#define I2C_BBPLL_IR_CAL_EXT_CAP 1
#define I2C_BBPLL_IR_CAL_EXT_CAP_MSB 3
#define I2C_BBPLL_IR_CAL_EXT_CAP_LSB 0
#define I2C_BBPLL_IR_CAL_ENX_CAP 1
#define I2C_BBPLL_IR_CAL_ENX_CAP_MSB 4
#define I2C_BBPLL_IR_CAL_ENX_CAP_LSB 4
#define I2C_BBPLL_IR_CAL_RSTB 1
#define I2C_BBPLL_IR_CAL_RSTB_MSB 5
#define I2C_BBPLL_IR_CAL_RSTB_LSB 5
#define I2C_BBPLL_IR_CAL_START 1
#define I2C_BBPLL_IR_CAL_START_MSB 6
#define I2C_BBPLL_IR_CAL_START_LSB 6
#define I2C_BBPLL_IR_CAL_UNSTOP 1
#define I2C_BBPLL_IR_CAL_UNSTOP_MSB 7
#define I2C_BBPLL_IR_CAL_UNSTOP_LSB 7
#define I2C_BBPLL_OC_REF_DIV 2
#define I2C_BBPLL_OC_REF_DIV_MSB 3
#define I2C_BBPLL_OC_REF_DIV_LSB 0
#define I2C_BBPLL_OC_DCHGP 2
#define I2C_BBPLL_OC_DCHGP_MSB 6
#define I2C_BBPLL_OC_DCHGP_LSB 4
#define I2C_BBPLL_OC_ENB_FCAL 2
#define I2C_BBPLL_OC_ENB_FCAL_MSB 7
#define I2C_BBPLL_OC_ENB_FCAL_LSB 7
#define I2C_BBPLL_OC_DIV_7_0 3
#define I2C_BBPLL_OC_DIV_7_0_MSB 7
#define I2C_BBPLL_OC_DIV_7_0_LSB 0
#define I2C_BBPLL_RSTB_DIV_ADC 4
#define I2C_BBPLL_RSTB_DIV_ADC_MSB 0
#define I2C_BBPLL_RSTB_DIV_ADC_LSB 0
#define I2C_BBPLL_MODE_HF 4
#define I2C_BBPLL_MODE_HF_MSB 1
#define I2C_BBPLL_MODE_HF_LSB 1
#define I2C_BBPLL_DIV_ADC 4
#define I2C_BBPLL_DIV_ADC_MSB 3
#define I2C_BBPLL_DIV_ADC_LSB 2
#define I2C_BBPLL_DIV_DAC 4
#define I2C_BBPLL_DIV_DAC_MSB 4
#define I2C_BBPLL_DIV_DAC_LSB 4
#define I2C_BBPLL_DIV_CPU 4
#define I2C_BBPLL_DIV_CPU_MSB 5
#define I2C_BBPLL_DIV_CPU_LSB 5
#define I2C_BBPLL_OC_ENB_VCON 4
#define I2C_BBPLL_OC_ENB_VCON_MSB 6
#define I2C_BBPLL_OC_ENB_VCON_LSB 6
#define I2C_BBPLL_OC_TSCHGP 4
#define I2C_BBPLL_OC_TSCHGP_MSB 7
#define I2C_BBPLL_OC_TSCHGP_LSB 7
#define I2C_BBPLL_OC_DR1 5
#define I2C_BBPLL_OC_DR1_MSB 2
#define I2C_BBPLL_OC_DR1_LSB 0
#define I2C_BBPLL_OC_DR3 5
#define I2C_BBPLL_OC_DR3_MSB 6
#define I2C_BBPLL_OC_DR3_LSB 4
#define I2C_BBPLL_EN_USB 5
#define I2C_BBPLL_EN_USB_MSB 7
#define I2C_BBPLL_EN_USB_LSB 7
#define I2C_BBPLL_OC_DCUR 6
#define I2C_BBPLL_OC_DCUR_MSB 2
#define I2C_BBPLL_OC_DCUR_LSB 0
#define I2C_BBPLL_INC_CUR 6
#define I2C_BBPLL_INC_CUR_MSB 3
#define I2C_BBPLL_INC_CUR_LSB 3
#define I2C_BBPLL_OC_DHREF_SEL 6
#define I2C_BBPLL_OC_DHREF_SEL_MSB 5
#define I2C_BBPLL_OC_DHREF_SEL_LSB 4
#define I2C_BBPLL_OC_DLREF_SEL 6
#define I2C_BBPLL_OC_DLREF_SEL_MSB 7
#define I2C_BBPLL_OC_DLREF_SEL_LSB 6
#define I2C_BBPLL_OR_CAL_CAP 8
#define I2C_BBPLL_OR_CAL_CAP_MSB 3
#define I2C_BBPLL_OR_CAL_CAP_LSB 0
#define I2C_BBPLL_OR_CAL_UDF 8
#define I2C_BBPLL_OR_CAL_UDF_MSB 4
#define I2C_BBPLL_OR_CAL_UDF_LSB 4
#define I2C_BBPLL_OR_CAL_OVF 8
#define I2C_BBPLL_OR_CAL_OVF_MSB 5
#define I2C_BBPLL_OR_CAL_OVF_LSB 5
#define I2C_BBPLL_OR_CAL_END 8
#define I2C_BBPLL_OR_CAL_END_MSB 6
#define I2C_BBPLL_OR_CAL_END_LSB 6
#define I2C_BBPLL_OR_LOCK 8
#define I2C_BBPLL_OR_LOCK_MSB 7
#define I2C_BBPLL_OR_LOCK_LSB 7
#define I2C_BBPLL_OC_VCO_DBIAS 9
#define I2C_BBPLL_OC_VCO_DBIAS_MSB 1
#define I2C_BBPLL_OC_VCO_DBIAS_LSB 0
#define I2C_BBPLL_BBADC_DELAY2 9
#define I2C_BBPLL_BBADC_DELAY2_MSB 3
#define I2C_BBPLL_BBADC_DELAY2_LSB 2
#define I2C_BBPLL_BBADC_DVDD 9
#define I2C_BBPLL_BBADC_DVDD_MSB 5
#define I2C_BBPLL_BBADC_DVDD_LSB 4
#define I2C_BBPLL_BBADC_DREF 9
#define I2C_BBPLL_BBADC_DREF_MSB 7
#define I2C_BBPLL_BBADC_DREF_LSB 6
#define I2C_BBPLL_BBADC_DCUR 10
#define I2C_BBPLL_BBADC_DCUR_MSB 1
#define I2C_BBPLL_BBADC_DCUR_LSB 0
#define I2C_BBPLL_BBADC_INPUT_SHORT 10
#define I2C_BBPLL_BBADC_INPUT_SHORT_MSB 2
#define I2C_BBPLL_BBADC_INPUT_SHORT_LSB 2
#define I2C_BBPLL_ENT_PLL 10
#define I2C_BBPLL_ENT_PLL_MSB 3
#define I2C_BBPLL_ENT_PLL_LSB 3
#define I2C_BBPLL_DTEST 10
#define I2C_BBPLL_DTEST_MSB 5
#define I2C_BBPLL_DTEST_LSB 4
#define I2C_BBPLL_ENT_ADC 10
#define I2C_BBPLL_ENT_ADC_MSB 7
#define I2C_BBPLL_ENT_ADC_LSB 6

View File

@@ -0,0 +1,30 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_bias.h
* @brief Register definitions for bias
*
* This file lists register fields of BIAS. These definitions are used via macros defined in regi2c_ctrl.h, by
* bootloader_hardware_init function in bootloader_esp32c3.c.
*/
#define I2C_BIAS 0X6A
#define I2C_BIAS_HOSTID 0
#define I2C_BIAS_DREG_1P1_PVT 1
#define I2C_BIAS_DREG_1P1_PVT_MSB 3
#define I2C_BIAS_DREG_1P1_PVT_LSB 0

View File

@@ -0,0 +1,30 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_brownout.h
* @brief Register definitions for brownout detector
*
* This file lists register fields of the brownout detector, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h.
*/
#define I2C_BOD 0x61
#define I2C_BOD_HOSTID 0
#define I2C_BOD_THRESHOLD 0x5
#define I2C_BOD_THRESHOLD_MSB 2
#define I2C_BOD_THRESHOLD_LSB 0

View File

@@ -0,0 +1,68 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_dig_reg.h
* @brief Register definitions for digital to get rtc voltage & digital voltage
* by setting rtc_dbias_Wak & dig_dbias_wak or by analog self-calibration.
*/
#define I2C_DIG_REG 0x6D
#define I2C_DIG_REG_HOSTID 0
#define I2C_DIG_REG_EXT_RTC_DREG 4
#define I2C_DIG_REG_EXT_RTC_DREG_MSB 4
#define I2C_DIG_REG_EXT_RTC_DREG_LSB 0
#define I2C_DIG_REG_ENX_RTC_DREG 4
#define I2C_DIG_REG_ENX_RTC_DREG_MSB 7
#define I2C_DIG_REG_ENX_RTC_DREG_LSB 7
#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP 5
#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP_MSB 4
#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP_LSB 0
#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP 5
#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP_MSB 7
#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP_LSB 7
#define I2C_DIG_REG_EXT_DIG_DREG 6
#define I2C_DIG_REG_EXT_DIG_DREG_MSB 4
#define I2C_DIG_REG_EXT_DIG_DREG_LSB 0
#define I2C_DIG_REG_ENX_DIG_DREG 6
#define I2C_DIG_REG_ENX_DIG_DREG_MSB 7
#define I2C_DIG_REG_ENX_DIG_DREG_LSB 7
#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP 7
#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP_MSB 4
#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP_LSB 0
#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP 7
#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP_MSB 7
#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP_LSB 7
#define I2C_DIG_REG_OR_EN_CONT_CAL 9
#define I2C_DIG_REG_OR_EN_CONT_CAL_MSB 7
#define I2C_DIG_REG_OR_EN_CONT_CAL_LSB 7
#define I2C_DIG_REG_XPD_RTC_REG 13
#define I2C_DIG_REG_XPD_RTC_REG_MSB 2
#define I2C_DIG_REG_XPD_RTC_REG_LSB 2
#define I2C_DIG_REG_XPD_DIG_REG 13
#define I2C_DIG_REG_XPD_DIG_REG_MSB 3
#define I2C_DIG_REG_XPD_DIG_REG_LSB 3

View File

@@ -0,0 +1,63 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_lp_bias.h
* @brief Register definitions for analog to calibrate o_code for getting a more precise voltage.
*
* This file lists register fields of low power dbais, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* rtc_init function in rtc_init.c.
*/
#define I2C_ULP 0x61
#define I2C_ULP_HOSTID 0
#define I2C_ULP_IR_RESETB 0
#define I2C_ULP_IR_RESETB_MSB 0
#define I2C_ULP_IR_RESETB_LSB 0
#define I2C_ULP_IR_FORCE_XPD_CK 0
#define I2C_ULP_IR_FORCE_XPD_CK_MSB 2
#define I2C_ULP_IR_FORCE_XPD_CK_LSB 2
#define I2C_ULP_IR_FORCE_XPD_IPH 0
#define I2C_ULP_IR_FORCE_XPD_IPH_MSB 4
#define I2C_ULP_IR_FORCE_XPD_IPH_LSB 4
#define I2C_ULP_IR_DISABLE_WATCHDOG_CK 0
#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_MSB 6
#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_LSB 6
#define I2C_ULP_O_DONE_FLAG 3
#define I2C_ULP_O_DONE_FLAG_MSB 0
#define I2C_ULP_O_DONE_FLAG_LSB 0
#define I2C_ULP_BG_O_DONE_FLAG 3
#define I2C_ULP_BG_O_DONE_FLAG_MSB 3
#define I2C_ULP_BG_O_DONE_FLAG_LSB 3
#define I2C_ULP_OCODE 4
#define I2C_ULP_OCODE_MSB 7
#define I2C_ULP_OCODE_LSB 0
#define I2C_ULP_IR_FORCE_CODE 5
#define I2C_ULP_IR_FORCE_CODE_MSB 6
#define I2C_ULP_IR_FORCE_CODE_LSB 6
#define I2C_ULP_EXT_CODE 6
#define I2C_ULP_EXT_CODE_MSB 7
#define I2C_ULP_EXT_CODE_LSB 0

View File

@@ -0,0 +1,87 @@
// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/**
* @file regi2c_saradc.h
* @brief Register definitions for analog to calibrate initial code for getting a more precise voltage of SAR ADC.
*
* This file lists register fields of SAR, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* function in adc_ll.h.
*/
#define I2C_SAR_ADC 0X69
#define I2C_SAR_ADC_HOSTID 0
#define ADC_SAR1_ENCAL_GND_ADDR 0x7
#define ADC_SAR1_ENCAL_GND_ADDR_MSB 5
#define ADC_SAR1_ENCAL_GND_ADDR_LSB 5
#define ADC_SAR2_ENCAL_GND_ADDR 0x7
#define ADC_SAR2_ENCAL_GND_ADDR_MSB 7
#define ADC_SAR2_ENCAL_GND_ADDR_LSB 7
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR 0x1
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB 0x3
#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB 0x0
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR 0x0
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB 0x7
#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB 0x0
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3
#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7
#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0
#define ADC_SAR1_DREF_ADDR 0x2
#define ADC_SAR1_DREF_ADDR_MSB 0x6
#define ADC_SAR1_DREF_ADDR_LSB 0x4
#define ADC_SAR2_DREF_ADDR 0x5
#define ADC_SAR2_DREF_ADDR_MSB 0x6
#define ADC_SAR2_DREF_ADDR_LSB 0x4
#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2
#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2
#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0
#define ADC_SARADC_DTEST_RTC_ADDR 0x7
#define ADC_SARADC_DTEST_RTC_ADDR_MSB 1
#define ADC_SARADC_DTEST_RTC_ADDR_LSB 0
#define ADC_SARADC_ENT_TSENS_ADDR 0x7
#define ADC_SARADC_ENT_TSENS_ADDR_MSB 2
#define ADC_SARADC_ENT_TSENS_ADDR_LSB 2
#define ADC_SARADC_ENT_RTC_ADDR 0x7
#define ADC_SARADC_ENT_RTC_ADDR_MSB 3
#define ADC_SARADC_ENT_RTC_ADDR_LSB 3
#define ADC_SARADC1_ENCAL_REF_ADDR 0x7
#define ADC_SARADC1_ENCAL_REF_ADDR_MSB 4
#define ADC_SARADC1_ENCAL_REF_ADDR_LSB 4
#define ADC_SARADC2_ENCAL_REF_ADDR 0x7
#define ADC_SARADC2_ENCAL_REF_ADDR_MSB 6
#define ADC_SARADC2_ENCAL_REF_ADDR_LSB 6
#define I2C_SARADC_TSENS_DAC 0x6
#define I2C_SARADC_TSENS_DAC_MSB 3
#define I2C_SARADC_TSENS_DAC_LSB 0

View File

@@ -0,0 +1,109 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "regi2c_bbpll.h"
#include "regi2c_lp_bias.h"
#include "regi2c_dig_reg.h"
#include "regi2c_bias.h"
#include "regi2c_saradc.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Analog function control register */
#define I2C_MST_ANA_CONF0_REG 0x6000E040
#define I2C_MST_BBPLL_STOP_FORCE_HIGH (BIT(2))
#define I2C_MST_BBPLL_STOP_FORCE_LOW (BIT(3))
#define ANA_CONFIG_REG 0x6000E044
#define ANA_CONFIG_S (8)
#define ANA_CONFIG_M (0x3FF)
#define ANA_I2C_SAR_FORCE_PD BIT(18)
#define ANA_I2C_BBPLL_M BIT(17) /* Clear to enable BBPLL */
#define ANA_I2C_APLL_M BIT(14) /* Clear to enable APLL */
#define ANA_CONFIG2_REG 0x6000E048
#define ANA_CONFIG2_M BIT(18)
#define ANA_I2C_SAR_FORCE_PU BIT(16)
/* ROM functions which read/write internal control bus */
uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
uint8_t rom_i2c_readReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb);
void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void rom_i2c_writeReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
#ifdef BOOTLOADER_BUILD
/**
* If compiling for the bootloader, ROM functions can be called directly,
* without the need of a lock.
*/
#define regi2c_ctrl_read_reg rom_i2c_readReg
#define regi2c_ctrl_read_reg_mask rom_i2c_readReg_Mask
#define regi2c_ctrl_write_reg rom_i2c_writeReg
#define regi2c_ctrl_write_reg_mask rom_i2c_writeReg_Mask
#else
#define i2c_read_reg_raw rom_i2c_readReg
#define i2c_read_reg_mask_raw rom_i2c_readReg_Mask
#define i2c_write_reg_raw rom_i2c_writeReg
#define i2c_write_reg_mask_raw rom_i2c_writeReg_Mask
uint8_t regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add);
uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb);
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions
* from regi2c_bbpll.h/regi2c_dig_reg.h/regi2c_lp_bias.h/regi2c_bias.h header files.
*/
#define REGI2C_WRITE_MASK(block, reg_add, indata) \
regi2c_ctrl_write_reg_mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata)
#define REGI2C_READ_MASK(block, reg_add) \
regi2c_ctrl_read_reg_mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB)
#define REGI2C_WRITE(block, reg_add, indata) \
regi2c_ctrl_write_reg(block, block##_HOSTID, reg_add, indata)
#define REGI2C_READ(block, reg_add) \
regi2c_ctrl_read_reg(block, block##_HOSTID, reg_add)
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,507 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include "sdkconfig.h"
#include "esp32h2/rom/ets_sys.h"
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/uart.h"
#include "esp32h2/rom/gpio.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/efuse_reg.h"
#include "soc/syscon_reg.h"
#include "soc/system_reg.h"
#include "regi2c_ctrl.h"
#include "soc_log.h"
#include "rtc_clk_common.h"
#include "esp_rom_sys.h"
static const char *TAG = "rtc_clk";
#define RTC_PLL_FREQ_320M 320
#define RTC_PLL_FREQ_480M 480
#define DELAY_RTC_CLK_SWITCH 5
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
static int s_cur_pll_freq;
static void rtc_clk_cpu_freq_to_8m(void);
void rtc_clk_32k_enable_internal(x32k_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm);
REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf);
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
} else {
SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE);
CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
}
}
void rtc_clk_32k_enable_external(void)
{
/* TODO ESP32-C3 IDF-2408: external 32k source may need different settings */
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
rtc_clk_32k_enable_internal(cfg);
}
void rtc_clk_32k_bootstrap(uint32_t cycle)
{
/* No special bootstrapping needed for ESP32-C3, '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)
{
uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG);
/* If xtal xpd is controlled by software */
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
/* If xtal xpd software control is on */
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
return !disabled;
}
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{
if (clk_8m_en) {
// CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M); // ESP32H2-TODO: IDF-3396
/* no need to wait once enabled by software */
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CK8M_ENABLE_WAIT_DEFAULT);
esp_rom_delay_us(DELAY_8M_ENABLE);
} else {
// SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
}
/* d256 should be independent configured with 8M
* Maybe we can split this function into 8m and dmd256
*/
if (d256_en) {
// CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
} else {
// SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
}
}
bool rtc_clk_8m_enabled(void)
{
return false;
// return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0; // ESP32H2-TODO: IDF-3396
}
bool rtc_clk_8md256_enabled(void)
{
return false;
// return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0; // ESP32H2-TODO: IDF-3396
}
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
/* Why we need to connect this clock to digital?
* Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead?
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
(slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0);
/* The clk_8m_d256 will be closed when rtc_state in SLEEP,
so if the slow_clk is 8md256, clk_8m must be force power on
*/
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU, (slow_freq == RTC_SLOW_FREQ_8MD256) ? 1 : 0);
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
}
rtc_slow_freq_t rtc_clk_slow_freq_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
}
uint32_t rtc_clk_slow_freq_get_hz(void)
{
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;
}
return 0;
}
void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq)
{
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
}
rtc_fast_freq_t rtc_clk_fast_freq_get(void)
{
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
}
static void rtc_clk_bbpll_disable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
s_cur_pll_freq = 0;
}
static void rtc_clk_bbpll_enable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD |
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
}
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
{
uint8_t div_ref;
uint8_t div7_0;
uint8_t dr1;
uint8_t dr3;
uint8_t dchgp;
uint8_t dcur;
uint8_t dbias;
CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH);
SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW);
if (pll_freq == RTC_PLL_FREQ_480M) {
/* Set this register to let the digital part know 480M PLL is used */
// SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); // ESP32H2-TODO: IDF-3396
/* Configure 480M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 26;
dr1 = 1;
dr3 = 1;
dchgp = 4;
dcur = 0;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 8;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B);
} else {
/* Clear this register to let the digital part know 320M PLL is used */
// CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); // ESP32H2-TODO: IDF-3396
/* Configure 320M PLL */
switch (xtal_freq) {
case RTC_XTAL_FREQ_40M:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
case RTC_XTAL_FREQ_32M:
div_ref = 1;
div7_0 = 6;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
default:
div_ref = 0;
div7_0 = 4;
dr1 = 0;
dr3 = 0;
dchgp = 5;
dcur = 3;
dbias = 2;
break;
}
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69);
}
uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref);
uint8_t i2c_bbpll_div_7_0 = div7_0;
uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3);
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 2);
REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1);
s_cur_pll_freq = pll_freq;
}
/**
* Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
* PLL must already be enabled.
* @param cpu_freq new CPU frequency
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
// int per_conf = DPORT_CPUPERIOD_SEL_80;
if (cpu_freq_mhz == 80) {
/* nothing to do */
} else if (cpu_freq_mhz == 160) {
// per_conf = DPORT_CPUPERIOD_SEL_160;
} else {
SOC_LOGE(TAG, "invalid frequency");
abort();
}
// REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf); // ESP32H2-TODO: IDF-3396
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
ets_update_cpu_frequency(cpu_freq_mhz);
}
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
{
uint32_t source_freq_mhz;
rtc_cpu_freq_src_t source;
uint32_t divider;
uint32_t real_freq_mhz;
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
if (freq_mhz <= xtal_freq) {
divider = xtal_freq / freq_mhz;
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
if (real_freq_mhz != freq_mhz) {
// no suitable divider
return false;
}
source_freq_mhz = xtal_freq;
source = RTC_CPU_FREQ_SRC_XTAL;
} else if (freq_mhz == 80) {
real_freq_mhz = freq_mhz;
source = RTC_CPU_FREQ_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
divider = 6;
} else if (freq_mhz == 160) {
real_freq_mhz = freq_mhz;
source = RTC_CPU_FREQ_SRC_PLL;
source_freq_mhz = RTC_PLL_FREQ_480M;
divider = 3;
} else {
// 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;
}
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
{
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) {
rtc_clk_bbpll_disable();
}
} else if (config->source == RTC_CPU_FREQ_SRC_PLL) {
if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) {
rtc_clk_bbpll_enable();
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
}
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
} else if (config->source == RTC_CPU_FREQ_SRC_8M) {
rtc_clk_cpu_freq_to_8m();
if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) {
rtc_clk_bbpll_disable();
}
}
}
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
{
rtc_cpu_freq_src_t source;
uint32_t source_freq_mhz;
uint32_t div;
uint32_t freq_mhz;
uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL);
switch (soc_clk_sel) {
case DPORT_SOC_CLK_SEL_XTAL: {
source = RTC_CPU_FREQ_SRC_XTAL;
div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1;
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
freq_mhz = source_freq_mhz / div;
}
break;
case DPORT_SOC_CLK_SEL_PLL: {
// ESP32H2-TODO: IDF-3396
source = 0;
div = 0;
source_freq_mhz = 0;
freq_mhz = 0;
break;
}
case DPORT_SOC_CLK_SEL_8M:
source = RTC_CPU_FREQ_SRC_8M;
source_freq_mhz = 8;
div = 1;
freq_mhz = source_freq_mhz;
break;
default:
SOC_LOGE(TAG, "unsupported frequency configuration");
abort();
}
*out_config = (rtc_cpu_freq_config_t) {
.source = source,
.source_freq_mhz = source_freq_mhz,
.div = div,
.freq_mhz = freq_mhz
};
}
void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
{
if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
} else if (config->source == RTC_CPU_FREQ_SRC_PLL &&
s_cur_pll_freq == config->source_freq_mhz) {
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
} else {
/* fallback */
rtc_clk_cpu_freq_set_config(config);
}
}
void rtc_clk_cpu_freq_set_xtal(void)
{
int freq_mhz = (int) rtc_clk_xtal_freq_get();
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
rtc_clk_bbpll_disable();
}
/**
* Switch to XTAL frequency. Does not disable the PLL.
*/
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
{
ets_update_cpu_frequency(freq);
/* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1);
/* no need to adjust the REF_TICK */
/* switch clock source */
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL);
rtc_clk_apb_freq_update(freq * MHZ);
}
static void rtc_clk_cpu_freq_to_8m(void)
{
ets_update_cpu_frequency(8);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0);
REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M);
rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M);
}
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
{
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
if (!clk_val_is_valid(xtal_freq_reg)) {
SOC_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg);
return RTC_XTAL_FREQ_40M;
}
return reg_val_to_clk_val(xtal_freq_reg);
}
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
{
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
}
void rtc_clk_apb_freq_update(uint32_t apb_freq)
{
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
}
uint32_t rtc_clk_apb_freq_get(void)
{
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
// round to the nearest MHz
freq_hz += MHZ / 2;
uint32_t remainder = freq_hz % MHZ;
return freq_hz - remainder;
}
void rtc_clk_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div);
SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD);
}
void rtc_clk_8m_divider_set(uint32_t div)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div);
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD);
}
void rtc_dig_clk8m_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
}
void rtc_dig_clk8m_disable(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
}
/* 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,57 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#define MHZ (1000000)
#define DPORT_CPUPERIOD_SEL_80 0
#define DPORT_CPUPERIOD_SEL_160 1
#define DPORT_SOC_CLK_SEL_XTAL 0
#define DPORT_SOC_CLK_SEL_PLL 1
#define DPORT_SOC_CLK_SEL_8M 2
#define RTC_FAST_CLK_FREQ_8M 8500000
#ifdef __cplusplus
extern "C" {
#endif
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
* lower and upper 16-bit halves. These are the routines to work with such a
* representation.
*/
static inline bool clk_val_is_valid(uint32_t val)
{
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
val != 0 &&
val != UINT32_MAX;
}
static inline uint32_t reg_val_to_clk_val(uint32_t val)
{
return val & UINT16_MAX;
}
static inline uint32_t clk_val_to_reg_val(uint32_t val)
{
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,88 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "esp32h2/rom/ets_sys.h"
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/uart.h"
#include "soc/rtc.h"
#include "soc/rtc_periph.h"
#include "soc/efuse_periph.h"
#include "soc/apb_ctrl_reg.h"
#include "hal/cpu_hal.h"
#include "regi2c_ctrl.h"
#include "soc_log.h"
#include "sdkconfig.h"
#include "rtc_clk_common.h"
#include "esp_rom_uart.h"
static const char *TAG = "rtc_clk_init";
void rtc_clk_init(rtc_clk_config_t cfg)
{
rtc_cpu_freq_config_t old_config, new_config;
/* Set tuning parameters for 8M and 150k clocks.
* Note: this doesn't attempt to set the clocks to precise frequencies.
* Instead, we calibrate these clocks against XTAL frequency later, when necessary.
* - SCK_DCAP value controls tuning of 150k clock.
* The higher the value of DCAP is, the lower is the frequency.
* - CK8M_DFREQ value controls tuning of 8M clock.
* CLK_8M_DFREQ constant gives the best temperature characteristics.
*/
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap);
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq);
/* Configure 150k clock division */
rtc_clk_divider_set(cfg.clk_rtc_clk_div);
/* Configure 8M clock division */
rtc_clk_8m_divider_set(cfg.clk_8m_clk_div);
/* Enable the internal bus used to configure PLLs */
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_APLL_M | ANA_I2C_BBPLL_M);
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) {
SOC_LOGE(TAG, "invalid CPU frequency value");
abort();
}
rtc_clk_cpu_freq_set_config(&new_config);
/* Re-calculate the ccount to make time calculation correct. */
cpu_hal_set_cycle_count( (uint64_t)cpu_hal_get_cycle_count() * cfg.cpu_freq_mhz / freq_before );
/* Slow & fast clocks setup */
if (cfg.slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
rtc_clk_32k_enable(true);
}
if (cfg.fast_freq == RTC_FAST_FREQ_8M) {
bool need_8md256 = cfg.slow_freq == RTC_SLOW_FREQ_8MD256;
rtc_clk_8m_enable(true, need_8md256);
}
rtc_clk_fast_freq_set(cfg.fast_freq);
rtc_clk_slow_freq_set(cfg.slow_freq);
}

Some files were not shown because too many files have changed in this diff Show More