From a611e91b2f4b4f7c7472ae7fda449dfb4d0a77b8 Mon Sep 17 00:00:00 2001 From: wanlei Date: Thu, 14 Mar 2024 16:27:29 +0800 Subject: [PATCH] feat(esp32c61): new chip add system and esp_timer support --- .../esp_rom/include/esp32c61/rom/libc_stubs.h | 2 +- components/esp_system/fpga_overrides_clk.c | 5 +- .../esp_system/ld/esp32c61/memory.ld.in | 123 +++++ .../esp_system/ld/esp32c61/sections.ld.in | 458 ++++++++++++++++++ .../esp_system/port/arch/riscv/panic_arch.c | 5 - components/esp_system/port/brownout.c | 2 +- components/esp_system/port/cpu_start.c | 8 +- .../port/soc/esp32c61/CMakeLists.txt | 9 + .../esp_system/port/soc/esp32c61/Kconfig.cpu | 24 + .../port/soc/esp32c61/cache_err_int.c | 75 +++ components/esp_system/port/soc/esp32c61/clk.c | 198 ++++++++ .../port/soc/esp32c61/reset_reason.c | 125 +++++ .../port/soc/esp32c61/system_internal.c | 121 +++++ components/esp_system/system_time.c | 3 + components/esp_timer/src/esp_timer.c | 3 + components/esp_timer/src/ets_timer_legacy.c | 4 + components/esp_timer/src/system_time.c | 3 + .../riscv/include/freertos/portmacro.h | 17 +- .../esp32c61/include/soc/Kconfig.soc_caps.in | 4 - .../soc/esp32c61/include/soc/soc_caps.h | 2 +- 20 files changed, 1173 insertions(+), 18 deletions(-) create mode 100644 components/esp_system/port/soc/esp32c61/cache_err_int.c create mode 100644 components/esp_system/port/soc/esp32c61/clk.c create mode 100644 components/esp_system/port/soc/esp32c61/reset_reason.c create mode 100644 components/esp_system/port/soc/esp32c61/system_internal.c diff --git a/components/esp_rom/include/esp32c61/rom/libc_stubs.h b/components/esp_rom/include/esp32c61/rom/libc_stubs.h index 6d9c31a938..6245da56b6 100644 --- a/components/esp_rom/include/esp32c61/rom/libc_stubs.h +++ b/components/esp_rom/include/esp32c61/rom/libc_stubs.h @@ -20,7 +20,7 @@ extern "C" { #endif /* -ESP32-C6 ROM code contains implementations of some of C library functions. +ESP32-C61 ROM code contains implementations of some of C library functions. Whenever a function in ROM needs to use a syscall, it calls a pointer to the corresponding syscall implementation defined in the following struct. diff --git a/components/esp_system/fpga_overrides_clk.c b/components/esp_system/fpga_overrides_clk.c index 4fd5607c6d..a3b4b43de5 100644 --- a/components/esp_system/fpga_overrides_clk.c +++ b/components/esp_system/fpga_overrides_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +23,9 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/rtc.h" #include "esp_private/esp_pmu.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rom/rtc.h" +#include "esp_private/esp_pmu.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/esp_system/ld/esp32c61/memory.ld.in b/components/esp_system/ld/esp32c61/memory.ld.in index e69de29bb2..8b67f377ea 100644 --- a/components/esp_system/ld/esp32c61/memory.ld.in +++ b/components/esp_system/ld/esp32c61/memory.ld.in @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * ESP32-C61 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" +#include "ld.common" + +#define SRAM_SEG_START 0x40800000 +#define SRAM_SEG_END 0x4084E5F0 /* 2nd stage bootloader iram_loader_seg start address */ +#define SRAM_SEG_SIZE SRAM_SEG_END - SRAM_SEG_START + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +/* + * IDRAM0_2_SEG_SIZE_DEFAULT is used when page size is 64KB + */ +#define IDRAM0_2_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 8) +#endif + +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. + */ + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped instruction data */ + irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 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. + */ + sram_seg (RWX) : org = SRAM_SEG_START, len = SRAM_SEG_SIZE + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped constant data */ + drom_seg (R) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20 + + /* (See irom_seg for meaning of 0x20 offset in the above.) */ +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + /** + * lp ram memory (RWX). Persists over deep sleep. // TODO: IDF-5667 + */ +#if CONFIG_ULP_COPROC_ENABLED + lp_ram_seg(RW) : org = 0x50000000 + CONFIG_ULP_COPROC_RESERVE_MEM, + len = 0x4000 - CONFIG_ULP_COPROC_RESERVE_MEM - RESERVE_RTC_MEM +#else + lp_ram_seg(RW) : org = 0x50000000, len = 0x4000 - RESERVE_RTC_MEM +#endif // CONFIG_ULP_COPROC_ENABLED + + /* We reduced the size of lp_ram_seg by RESERVE_RTC_MEM value. + It reserves the amount of LP memory that we use for this memory segment. + This segment is intended for keeping: + - (lower addr) rtc timer data (s_rtc_timer_retain_mem, see esp_clk.c files). + - (higher addr) bootloader rtc data (s_bootloader_retain_mem, when a Kconfig option is on). + The aim of this is to keep data that will not be moved around and have a fixed address. + */ + lp_reserved_seg(RW) : org = 0x50000000 + 0x4000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM +} + +/* Heap ends at top of sram_seg */ +_heap_end = 0x40000000; + +_data_seg_org = ORIGIN(rtc_data_seg); + +/** + * The lines below define location alias for .rtc.data section + * C61 has no distinguished LP(RTC) fast and slow memory sections, instead, there is a unified LP_RAM section + * Thus, the following region segments are not configurable like on other targets + */ +REGION_ALIAS("rtc_iram_seg", lp_ram_seg ); +REGION_ALIAS("rtc_data_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_slow_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_data_location", rtc_iram_seg ); +REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg ); + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_code_seg", irom_seg); +#else + REGION_ALIAS("default_code_seg", sram_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_rodata_seg", drom_seg); +#else + REGION_ALIAS("default_rodata_seg", sram_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +/** + * If rodata default segment is placed in `drom_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 + +#if CONFIG_ESP_SYSTEM_USE_EH_FRAME + ASSERT ((__eh_frame_end > __eh_frame), "Error: eh_frame size is null!"); + ASSERT ((__eh_frame_hdr_end > __eh_frame_hdr), "Error: eh_frame_hdr size is null!"); +#endif diff --git a/components/esp_system/ld/esp32c61/sections.ld.in b/components/esp_system/ld/esp32c61/sections.ld.in index e69de29bb2..c0b76d0af2 100644 --- a/components/esp_system/ld/esp32c61/sections.ld.in +++ b/components/esp_system/ld/esp32c61/sections.ld.in @@ -0,0 +1,458 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ld.common" + +/* 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 : + { + ALIGNED_SYMBOL(4, _rtc_fast_start) + ALIGNED_SYMBOL(4, _rtc_text_start) + + *(.rtc.entry.text) + + mapping[rtc_text] + + *rtc_wake_stub*.*(.text .text.*) + *(.rtc_text_end_test) + + _rtc_text_end = ABSOLUTE(.); + } > lp_ram_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 : + { + ALIGNED_SYMBOL(4, _rtc_force_fast_start) + + mapping[rtc_force_fast] + + *(.rtc.force_fast .rtc.force_fast.*) + + ALIGNED_SYMBOL(4, _rtc_force_fast_end) + } > lp_ram_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. + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + + mapping[rtc_data] + + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) + + _rtc_data_end = ABSOLUTE(.); + } > lp_ram_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) + *rtc_wake_stub*.*(COMMON) + + mapping[rtc_bss] + + _rtc_bss_end = ABSOLUTE(.); + } > lp_ram_seg + + /** + * 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. + */ + .rtc_noinit (NOLOAD): + { + ALIGNED_SYMBOL(4, _rtc_noinit_start) + + *(.rtc_noinit .rtc_noinit.*) + + ALIGNED_SYMBOL(4, _rtc_noinit_end) + } > lp_ram_seg + + /** + * 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 : + { + ALIGNED_SYMBOL(4, _rtc_force_slow_start) + + *(.rtc.force_slow .rtc.force_slow.*) + + ALIGNED_SYMBOL(4, _rtc_force_slow_end) + } > lp_ram_seg + + /** + * This section holds RTC data that should have fixed addresses. + * The data are not initialized at power-up and are retained during deep + * sleep. + */ + .rtc_reserved (NOLOAD): + { + ALIGNED_SYMBOL(4, _rtc_reserved_start) + + /** + * New data can only be added here to ensure existing data are not moved. + * Because data have adhered to the end of the segment and code is relied + * on it. + * >> put new data here << + */ + + *(.rtc_timer_data_in_rtc_mem .rtc_timer_data_in_rtc_mem.*) + KEEP(*(.bootloader_data_rtc_mem .bootloader_data_rtc_mem.*)) + + _rtc_reserved_end = ABSOLUTE(.); + } > rtc_reserved_seg + + _rtc_reserved_length = _rtc_reserved_end - _rtc_reserved_start; + ASSERT((_rtc_reserved_length <= LENGTH(rtc_reserved_seg)), + "RTC reserved segment data does not fit.") + + /* 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_table.text)); + KEEP(*(.exception_vectors.text)); + + ALIGNED_SYMBOL(4, _invalid_pc_placeholder) + + /* Code marked as running out of IRAM */ + _iram_text_start = ABSOLUTE(.); + + mapping[iram0_text] + + } > sram_seg + + /* Marks the end of IRAM code segment */ + .iram0.text_end (NOLOAD) : + { + ALIGNED_SYMBOL(4, _iram_text_end) + } > sram_seg + + .iram0.data : + { + ALIGNED_SYMBOL(16, _iram_data_start) + + mapping[iram0_data] + + _iram_data_end = ABSOLUTE(.); + } > sram_seg + + .iram0.bss (NOLOAD) : + { + ALIGNED_SYMBOL(16, _iram_bss_start) + + mapping[iram0_bss] + + _iram_bss_end = ABSOLUTE(.); + ALIGNED_SYMBOL(16, _iram_end) + } > sram_seg + + /** + * This section is required to skip .iram0.text area because sram_seg and + * sram_seg reflect the same address space on different buses. + */ + .dram0.dummy (NOLOAD): + { + . = ORIGIN(sram_seg) + _iram_end - _iram_start; + } > sram_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.gnu.linkonce.d.*) + *(.data1) + __global_pointer$ = . + 0x800; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + + mapping[dram0_data] + + _data_end = ABSOLUTE(.); + } > sram_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): + { + ALIGNED_SYMBOL(4, _noinit_start) + + *(.noinit .noinit.*) + + ALIGNED_SYMBOL(4, _noinit_end) + } > sram_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + ALIGNED_SYMBOL(8, _bss_start) + + /** + * ldgen places all bss-related data to mapping[dram0_bss] + * (See components/esp_system/app.lf). + */ + mapping[dram0_bss] + + ALIGNED_SYMBOL(8, _bss_end) + } > sram_seg + + ASSERT(((_bss_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), "DRAM segment data does not fit.") + + .flash.text : + { + _stext = .; + /** + * Mark the start of flash.text. + * This can be used by the MMU driver to maintain the virtual address. + */ + _instruction_reserved_start = ABSOLUTE(.); + _text_start = ABSOLUTE(.); + + mapping[flash_text] + + *(.stub) + *(.gnu.linkonce.t.*) + *(.gnu.warning) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + + /** + * 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 + */ + . += _esp_flash_mmap_prefetch_pad_size; + + _text_end = ABSOLUTE(.); + /** + * Mark the flash.text end. + * This can be used for MMU driver to maintain virtual address. + */ + _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 + + /** + * Dummy section represents the .flash.text section but in default_rodata_seg. + * Thus, it must have its alignment and (at least) its size. + */ + .flash_rodata_dummy (NOLOAD): + { + _flash_rodata_dummy_start = .; + + . = ALIGN(ALIGNOF(.flash.text)) + SIZEOF(.flash.text); + + /* Add alignment of MMU page size + 0x20 bytes for the mapping header. */ + . = ALIGN(_esp_mmu_page_size) + 0x20; + } > default_rodata_seg + + .flash.appdesc : ALIGN(0x10) + { + /** + * Mark flash.rodata start. + * This can be used for mmu driver to maintain virtual address + */ + _rodata_reserved_start = ABSOLUTE(.); + _rodata_start = ABSOLUTE(.); + + /* !DO NOT PUT ANYTHING BEFORE THIS! */ + + /* Should be the first. App version info. */ + *(.rodata_desc .rodata_desc.*) + /* Should be the second. Custom app version info. */ + *(.rodata_custom_desc .rodata_custom_desc.*) + + /** + * 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 + ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata) + + .flash.rodata : ALIGN(0x10) + { + _flash_rodata_start = ABSOLUTE(.); + + mapping[flash_rodata] + + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + /** + * C++ constructor tables. + * + * Excluding crtbegin.o/crtend.o since IDF doesn't use the toolchain crt. + * + * RISC-V gcc is configured with --enable-initfini-array so it emits + * .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. + */ + ALIGNED_SYMBOL(4, __init_priority_array_start) + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*)) + __init_priority_array_end = ABSOLUTE(.); + + ALIGNED_SYMBOL(4, __init_array_start) + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) + __init_array_end = ABSOLUTE(.); + + /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ + ALIGNED_SYMBOL(4, soc_reserved_memory_region_start) + KEEP (*(.reserved_memory_address)) + soc_reserved_memory_region_end = ABSOLUTE(.); + + /* System init functions registered via ESP_SYSTEM_INIT_FN */ + ALIGNED_SYMBOL(4, _esp_system_init_fn_array_start) + KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + + _rodata_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.eh_frame_hdr)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.rodata, .eh_frame_hdr) + + .eh_frame_hdr : + { + ALIGNED_SYMBOL(4, __eh_frame_hdr) + + KEEP (*(.eh_frame_hdr)) + + __eh_frame_hdr_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.eh_frame)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) + + .eh_frame : + { + ALIGNED_SYMBOL(4, __eh_frame) + + KEEP (*(.eh_frame)) + /** + * As we are not linking with crtend.o, which includes the CIE terminator + * (see __FRAME_END__ in libgcc sources), it is manually provided here. + */ + LONG(0); + + __eh_frame_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.tdata)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) + + .flash.tdata : + { + _thread_local_data_start = ABSOLUTE(.); + + *(.tdata .tdata.* .gnu.linkonce.td.*) + + . = ALIGN(ALIGNOF(.flash.tbss)); + _thread_local_data_end = ABSOLUTE(.); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + + .flash.tbss (NOLOAD) : + { + _thread_local_bss_start = ABSOLUTE(.); + + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + + _thread_local_bss_end = ABSOLUTE(.); + } > default_rodata_seg + + /** + * This section contains all the rodata that is not used + * at runtime, helping to avoid an increase in binary size. + */ + .flash.rodata_noload (NOLOAD) : + { + /** + * This symbol marks the end of flash.rodata. It can be utilized by the MMU + * driver to maintain the virtual address. + * NOLOAD rodata may not be included in this section. + */ + _rodata_reserved_end = ADDR(.flash.tbss); + + mapping[rodata_noload] + } > default_rodata_seg + + /* Marks the end of data, bss and possibly rodata */ + .dram0.heap_start (NOLOAD) : + { + ALIGNED_SYMBOL(16, _heap_start) + } > sram_seg + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } +} + +ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), + "IRAM0 segment data does not fit.") + +ASSERT(((_heap_start - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), + "DRAM segment data does not fit.") diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index e7c8ee1fce..07378759f1 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -8,11 +8,6 @@ #include "spi_flash_mmap.h" -#if CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 -#include "soc/cache_reg.h" -#else -#include "soc/extmem_reg.h" -#endif #include "soc/soc_caps.h" #include "esp_private/panic_internal.h" #include "esp_private/panic_reason.h" diff --git a/components/esp_system/port/brownout.c b/components/esp_system/port/brownout.c index 37b4fae49f..ef1a5ed67b 100644 --- a/components/esp_system/port/brownout.c +++ b/components/esp_system/port/brownout.c @@ -73,7 +73,7 @@ void esp_brownout_init(void) brownout_hal_config(&cfg); brownout_ll_intr_clear(); -#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8647 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 // TODO: [ESP32C5] IDF-8647, [ESP32C61] IDF-9254 // TODO IDF-6606: LP_RTC_TIMER interrupt source is shared by lp_timer and brownout detector, but lp_timer interrupt // is not used now. An interrupt allocator is needed when lp_timer intr gets supported. esp_intr_alloc(ETS_LP_RTC_TIMER_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_brownout_isr_handler, NULL, NULL); diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 2d979f31a7..5bcc3a05e3 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -50,6 +50,9 @@ #include "esp32c6/rtc.h" #include "esp32c6/rom/cache.h" #include "esp_memprot.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rtc.h" +#include "esp_memprot.h" #elif CONFIG_IDF_TARGET_ESP32C5 #include "esp32c5/rtc.h" #include "esp32c5/rom/cache.h" @@ -181,7 +184,6 @@ static void core_intr_matrix_clear(void) esprv_int_set_vectored(i, true); } #endif // SOC_INT_CLIC_SUPPORTED - } #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE @@ -702,12 +704,12 @@ void IRAM_ATTR call_start_cpu0(void) #endif #endif -#if !CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_IDF_TARGET_ESP32C5 //TODO: IDF-7529, IDF-8638 +#if SOC_DEEP_SLEEP_SUPPORTED //TODO: IDF-7529, IDF-8638, IDF-9245 // Need to unhold the IOs that were hold right before entering deep sleep, which are used as wakeup pins if (rst_reas[0] == RESET_REASON_CORE_DEEP_SLEEP) { esp_deep_sleep_wakeup_io_reset(); } -#endif //#if !CONFIG_IDF_TARGET_ESP32P4 & !CONFIG_IDF_TARGET_ESP32C5 +#endif //#if SOC_DEEP_SLEEP_SUPPORTED #if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP esp_cache_err_int_init(); diff --git a/components/esp_system/port/soc/esp32c61/CMakeLists.txt b/components/esp_system/port/soc/esp32c61/CMakeLists.txt index e69de29bb2..28d8f18863 100644 --- a/components/esp_system/port/soc/esp32c61/CMakeLists.txt +++ b/components/esp_system/port/soc/esp32c61/CMakeLists.txt @@ -0,0 +1,9 @@ +# TODO: IDF-9526, refactor this +set(srcs + "reset_reason.c" + "system_internal.c" + "cache_err_int.c") + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/soc/esp32c61/Kconfig.cpu b/components/esp_system/port/soc/esp32c61/Kconfig.cpu index e69de29bb2..2b5a7e45b8 100644 --- a/components/esp_system/port/soc/esp32c61/Kconfig.cpu +++ b/components/esp_system/port/soc/esp32c61/Kconfig.cpu @@ -0,0 +1,24 @@ +choice ESP_DEFAULT_CPU_FREQ_MHZ + prompt "CPU frequency" + default ESP_DEFAULT_CPU_FREQ_MHZ_40 if IDF_ENV_FPGA + default ESP_DEFAULT_CPU_FREQ_MHZ_160 + help + CPU frequency to be set on application startup. + + config ESP_DEFAULT_CPU_FREQ_MHZ_40 + bool "40 MHz" + depends on IDF_ENV_FPGA + config ESP_DEFAULT_CPU_FREQ_MHZ_80 + bool "80 MHz" + config ESP_DEFAULT_CPU_FREQ_MHZ_120 + bool "120 MHz" + config ESP_DEFAULT_CPU_FREQ_MHZ_160 + bool "160 MHz" +endchoice + +config ESP_DEFAULT_CPU_FREQ_MHZ + int + default 40 if ESP_DEFAULT_CPU_FREQ_MHZ_40 + default 80 if ESP_DEFAULT_CPU_FREQ_MHZ_80 + default 120 if ESP_DEFAULT_CPU_FREQ_MHZ_120 + default 160 if ESP_DEFAULT_CPU_FREQ_MHZ_160 diff --git a/components/esp_system/port/soc/esp32c61/cache_err_int.c b/components/esp_system/port/soc/esp32c61/cache_err_int.c new file mode 100644 index 0000000000..d18659a58d --- /dev/null +++ b/components/esp_system/port/soc/esp32c61/cache_err_int.c @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + The cache has an interrupt that can be raised as soon as an access to a cached + region (flash) is done without the cache being enabled. We use that here + to panic the CPU, which from a debugging perspective is better than grabbing bad + data from the bus. +*/ +#include "esp_rom_sys.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "riscv/interrupt.h" +#include "hal/cache_ll.h" + +static const char *TAG = "CACHE_ERR"; + +const char cache_error_msg[] = "Cache access error"; + +const char *esp_cache_err_panic_string(void) +{ + const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + + /* Return the error string if a cache error is active */ + const char* err_str = access_err_status ? cache_error_msg : NULL; + + return err_str; +} + +bool esp_cache_err_has_active_err(void) +{ + return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + +void esp_cache_err_int_init(void) +{ + const uint32_t core_id = 0; + + /* Disable cache interrupts if enabled. */ + ESP_INTR_DISABLE(ETS_CACHEERR_INUM); + + /** + * Bind all cache errors to ETS_CACHEERR_INUM interrupt. we will deal with + * them in handler by different types + * + * On ESP32C61 boards, the cache is a shared one but buses are still + * distinct. So, we have an bus0 and a bus1 sharing the same cache. + * This error can occur if a bus performs a request but the cache + * is disabled. + */ + esp_rom_route_intr_matrix(core_id, ETS_CACHE_INTR_SOURCE, ETS_CACHEERR_INUM); + + /* Set the type and priority to cache error interrupts. */ + esprv_int_set_type(ETS_CACHEERR_INUM, INTR_TYPE_LEVEL); + esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); + + ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); + /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + /* Then enable cache access error interrupts. */ + cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + + /* Enable the interrupts for cache error. */ + ESP_INTR_ENABLE(ETS_CACHEERR_INUM); +} + +int esp_cache_err_get_cpuid(void) +{ + return 0; +} diff --git a/components/esp_system/port/soc/esp32c61/clk.c b/components/esp_system/port/soc/esp32c61/clk.c new file mode 100644 index 0000000000..20826e1cd5 --- /dev/null +++ b/components/esp_system/port/soc/esp32c61/clk.c @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_clk_internal.h" +#include "esp32c61/rom/ets_sys.h" +#include "esp32c61/rom/uart.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "esp_cpu.h" +#include "hal/wdt_hal.h" +#include "esp_private/esp_modem_clock.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk.h" +#include "esp_private/esp_pmu.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" +#include "ocode_init.h" + +// TODO: [ESP32C61] IDF-9249 + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_RTC_CLK_CAL_CYCLES + +#define MHZ (1000000) + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); + +static const char *TAG = "clk"; + +__attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA + pmu_init(); + if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON) { + esp_ocode_calib_init(); + } + + assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); + + rtc_clk_8m_enable(true); + rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +#elif defined(CONFIG_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_OSC_SLOW); +#elif defined(CONFIG_RTC_CLK_SRC_INT_RC32K) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_RC32K); +#else + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_RC_SLOW); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + esp_rom_output_tx_wait_idle(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM); + + if (res) { + rtc_clk_cpu_freq_set_config(&new_config); + } + + // Re calculate the ccount to make time calculation correct. + esp_cpu_set_cycle_count((uint64_t)esp_cpu_get_cycle_count() * new_freq_mhz / old_freq_mhz); +} + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src) +{ + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = 3; + + do { + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K || rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + rtc_cal_sel_t cal_sel = 0; + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + rtc_clk_32k_enable(true); + cal_sel = RTC_CAL_32K_XTAL; + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + rtc_clk_32k_enable_external(); + cal_sel = RTC_CAL_32K_OSC_SLOW; + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(cal_sel, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz clock not found, switching to internal 150 kHz oscillator"); + rtc_slow_clk_src = SOC_RTC_SLOW_CLK_SRC_RC_SLOW; + } + } + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) { + rtc_clk_rc32k_enable(true); + } + rtc_clk_slow_src_set(rtc_slow_clk_src); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t)(cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +__attribute__((weak)) void esp_perip_clk_init(void) +{ + /* During system initialization, the low-power clock source of the modem + * (WiFi, BLE or Coexist) follows the configuration of the slow clock source + * of the system. If the WiFi, BLE or Coexist module needs a higher + * precision sleep clock (for example, the BLE needs to use the main XTAL + * oscillator (40 MHz) to provide the clock during the sleep process in some + * scenarios), the module needs to switch to the required clock source by + * itself. */ //TODO - WIFI-5233 + soc_rtc_slow_clk_src_t rtc_slow_clk_src = rtc_clk_slow_src_get(); + modem_clock_lpclk_src_t modem_lpclk_src = (modem_clock_lpclk_src_t)(\ + (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) ? MODEM_CLOCK_LPCLK_SRC_RC_SLOW \ + : (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) ? MODEM_CLOCK_LPCLK_SRC_XTAL32K \ + : (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) ? MODEM_CLOCK_LPCLK_SRC_RC32K \ + : (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) ? MODEM_CLOCK_LPCLK_SRC_EXT32K \ + : SOC_RTC_SLOW_CLK_SRC_RC_SLOW); + modem_clock_select_lp_clock_source(PERIPH_WIFI_MODULE, modem_lpclk_src, 0); + + ESP_EARLY_LOGW(TAG, "esp_perip_clk_init() has not been implemented yet"); +} diff --git a/components/esp_system/port/soc/esp32c61/reset_reason.c b/components/esp_system/port/soc/esp32c61/reset_reason.c new file mode 100644 index 0000000000..84d8798417 --- /dev/null +++ b/components/esp_system/port/soc/esp32c61/reset_reason.c @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_system.h" +#include "esp_rom_sys.h" +#include "esp_private/system_internal.h" +#include "soc/rtc_periph.h" +#include "esp32c61/rom/rtc.h" + +// TODO: [ESP32C61] IDF-9267 + +static void esp_reset_reason_clear_hint(void); + +static esp_reset_reason_t s_reset_reason; + +static esp_reset_reason_t get_reset_reason(soc_reset_reason_t rtc_reset_reason, esp_reset_reason_t reset_reason_hint) +{ + switch (rtc_reset_reason) { + case RESET_REASON_CHIP_POWER_ON: + return ESP_RST_POWERON; + + case RESET_REASON_CPU0_SW: + case RESET_REASON_CORE_SW: + if (reset_reason_hint == ESP_RST_PANIC || + reset_reason_hint == ESP_RST_BROWNOUT || + reset_reason_hint == ESP_RST_TASK_WDT || + reset_reason_hint == ESP_RST_INT_WDT) { + return reset_reason_hint; + } + return ESP_RST_SW; + + case RESET_REASON_CORE_DEEP_SLEEP: + return ESP_RST_DEEPSLEEP; + + case RESET_REASON_CORE_MWDT0: + return ESP_RST_TASK_WDT; + + case RESET_REASON_CORE_MWDT1: + return ESP_RST_INT_WDT; + + case RESET_REASON_CORE_RTC_WDT: + case RESET_REASON_SYS_RTC_WDT: + case RESET_REASON_SYS_SUPER_WDT: + case RESET_REASON_CPU0_RTC_WDT: + case RESET_REASON_CPU0_MWDT0: + case RESET_REASON_CPU0_MWDT1: + return ESP_RST_WDT; + + case RESET_REASON_SYS_BROWN_OUT: + return ESP_RST_BROWNOUT; + + case RESET_REASON_CORE_USB_UART: + case RESET_REASON_CORE_USB_JTAG: + return ESP_RST_USB; + + case RESET_REASON_CORE_EFUSE_CRC: + return ESP_RST_EFUSE; + + case RESET_REASON_CPU0_JTAG: + return ESP_RST_JTAG; + + case RESET_REASON_CORE_SDIO: + return ESP_RST_SDIO; + + default: + return ESP_RST_UNKNOWN; + } +} + +static void __attribute__((constructor)) esp_reset_reason_init(void) +{ + esp_reset_reason_t hint = esp_reset_reason_get_hint(); + s_reset_reason = get_reset_reason(esp_rom_get_reset_reason(PRO_CPU_NUM), hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } +} + +esp_reset_reason_t esp_reset_reason(void) +{ + return s_reset_reason; +} + +/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG, + * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the + * deep sleep wake stub entry address and for reset reason hint, since wake stub + * is only used for deep sleep reset, and in this case the reason provided by + * esp_rom_get_reset_reason is unambiguous. + * + * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG): + * the value is replicated in low and high half-words. In addition to that, + * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains + * deep sleep wake stub address. + */ + +#define RST_REASON_BIT 0x80000000 +#define RST_REASON_MASK 0x7FFF +#define RST_REASON_SHIFT 16 + +/* in IRAM, can be called from panic handler */ +void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + assert((hint & (~RST_REASON_MASK)) == 0); + uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT; + REG_WRITE(RTC_RESET_CAUSE_REG, val); +} + +/* in IRAM, can be called from panic handler */ +esp_reset_reason_t esp_reset_reason_get_hint(void) +{ + uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG); + uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK; + uint32_t low = reset_reason_hint & RST_REASON_MASK; + if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) { + return ESP_RST_UNKNOWN; + } + return (esp_reset_reason_t) low; +} +static inline void esp_reset_reason_clear_hint(void) +{ + REG_WRITE(RTC_RESET_CAUSE_REG, 0); +} diff --git a/components/esp_system/port/soc/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c new file mode 100644 index 0000000000..fa61e67022 --- /dev/null +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_private/system_internal.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_rom_sys.h" +#include "riscv/rv_utils.h" +#include "esp_rom_uart.h" +#include "soc/gpio_reg.h" +#include "esp_cpu.h" +#include "soc/rtc.h" +#include "esp_private/rtc_clk.h" +#include "soc/rtc_periph.h" +#include "soc/uart_reg.h" +#include "hal/wdt_hal.h" +#include "esp_private/cache_err_int.h" + +#if SOC_MODEM_CLOCK_SUPPORTED +#include "hal/modem_syscon_ll.h" +#include "hal/modem_lpcon_ll.h" +#endif + +#include "esp32c61/rom/cache.h" +#include "esp32c61/rom/rtc.h" +#include "soc/pcr_reg.h" + +void IRAM_ATTR esp_system_reset_modules_on_exit(void) +{ + // Flush any data left in UART FIFOs before reset the UART peripheral + for (int i = 0; i < SOC_UART_HP_NUM; ++i) { + if (uart_ll_is_enabled(i)) { + esp_rom_output_tx_wait_idle(i); + } + } + + // ESP32C61 TODO: IDF9513, when you run modem, pay attention +#if SOC_MODEM_CLOCK_SUPPORTED + modem_syscon_ll_reset_all(&MODEM_SYSCON); + modem_lpcon_ll_reset_all(&MODEM_LPCON); +#endif + + // Set Peripheral clk rst + SET_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + SET_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); + SET_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); + SET_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); + SET_PERI_REG_MASK(PCR_GDMA_CONF_REG, PCR_GDMA_RST_EN); + SET_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); + + // Clear Peripheral clk rst + CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + CLEAR_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); + CLEAR_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); + CLEAR_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); + CLEAR_PERI_REG_MASK(PCR_GDMA_CONF_REG, PCR_GDMA_RST_EN); + CLEAR_PERI_REG_MASK(PCR_MODEM_CONF_REG, PCR_MODEM_RST_EN); +} + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void IRAM_ATTR esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + + // C61 is a single core SoC, no need to reset and stall the other CPU + + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + + // Disable cache + Cache_Disable_Cache(); + + //TODO: [ESP32C61] IDF-9249, inherit from verify code + // Reset wifi/bluetooth/ethernet/sdio (bb/mac) + // Moved to module internal + // SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, + // SYSTEM_SDIO_RST | // SDIO_HINF_HINF_SDIO_RST? + // SYSTEM_EMAC_RST | SYSTEM_MACPWR_RST | // TODO: IDF-5325 (ethernet) + // REG_WRITE(SYSTEM_CORE_RST_EN_REG, 0); + + esp_system_reset_modules_on_exit(); + + // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_set_to_default_config(); +#endif + + // Reset PRO CPU + esp_rom_software_reset_cpu(0); + while (true) { + ; + } +} diff --git a/components/esp_system/system_time.c b/components/esp_system/system_time.c index 668ddeb88c..fc7cb96fe8 100644 --- a/components/esp_system/system_time.c +++ b/components/esp_system/system_time.c @@ -13,6 +13,7 @@ #include "sdkconfig.h" +//TODO: IDF-9526, refactor this #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S2 @@ -25,6 +26,8 @@ #include "esp32c2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index 6b1b4f1304..5c0ec368cc 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -23,6 +23,7 @@ #include "esp_private/esp_timer_private.h" #include "esp_private/system_internal.h" +//TODO: IDF-9526, refactor this #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S2 @@ -35,6 +36,8 @@ #include "esp32c2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/esp_timer/src/ets_timer_legacy.c b/components/esp_timer/src/ets_timer_legacy.c index 85ebb5bac4..ae315d8506 100644 --- a/components/esp_timer/src/ets_timer_legacy.c +++ b/components/esp_timer/src/ets_timer_legacy.c @@ -21,6 +21,8 @@ #include "freertos/semphr.h" #include "sdkconfig.h" #include "esp_timer.h" + +//TODO: IDF-9526, refactor this // for ETSTimer type #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" @@ -34,6 +36,8 @@ #include "esp32c2/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32C5 #include "esp32c5/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32H2 diff --git a/components/esp_timer/src/system_time.c b/components/esp_timer/src/system_time.c index 0cd4e118f7..493d35b8f4 100644 --- a/components/esp_timer/src/system_time.c +++ b/components/esp_timer/src/system_time.c @@ -17,6 +17,7 @@ #include "esp_private/startup_internal.h" +//TODO: IDF-9526, refactor this #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rtc.h" #elif CONFIG_IDF_TARGET_ESP32S2 @@ -29,6 +30,8 @@ #include "esp32c2/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C61 +#include "esp32c61/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C5 #include "esp32c5/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index 1c1b6402be..0db8b3b798 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -663,6 +663,20 @@ static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_ // ---------------------- Yielding ------------------------- +// TODO: [ESP32C61] IDF-9280, changed in verify code, pls check +#if CONFIG_IDF_TARGET_ESP32C61 +FORCE_INLINE_ATTR bool xPortCanYield(void) +{ +#if SOC_INT_CLIC_SUPPORTED + uint32_t threshold1 = (RV_READ_CSR(MINTTHRESH)) >> (8 - NLBITS); + uint32_t threshold2 = (RV_READ_CSR(MINTSTATUS)) >> (24 + (8 - NLBITS)); + return (threshold1 == 0) && (threshold2 == 0) ; +#else + uint32_t threshold = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG); + return (threshold <= 1); +#endif /* SOC_INT_CLIC_SUPPORTED */ +} +#else FORCE_INLINE_ATTR bool xPortCanYield(void) { @@ -699,8 +713,7 @@ FORCE_INLINE_ATTR bool xPortCanYield(void) return (threshold <= 1); #endif } - - +#endif /* ------------------------------------------------------ Misc --------------------------------------------------------- * - Miscellaneous porting macros diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index be1a58170f..5138133641 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -1138,7 +1138,3 @@ config SOC_WIFI_HE_SUPPORT config SOC_PHY_COMBO_MODULE bool default y - -config SOC_CAPS_NO_RESET_BY_ANA_BOD - bool - default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 505474d50d..5519a88a9a 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -569,4 +569,4 @@ #define SOC_PHY_COMBO_MODULE (1) /*!< Support Wi-Fi, BLE and 15.4*/ /*------------------------------------- No Reset CAPS -------------------------------------*/ -#define SOC_CAPS_NO_RESET_BY_ANA_BOD (1) +// #define SOC_CAPS_NO_RESET_BY_ANA_BOD (1) //TODO: [ESP32C61] IDF-9254