diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index 902f186c10e..6ee615b9bba 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -105,7 +105,8 @@ static void esp32_clock_perip_init(void) soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); if ((rst_reason != RESET_REASON_CPU0_MWDT0) && (rst_reason != RESET_REASON_CPU0_MWDT1) && - (rst_reason != RESET_REASON_CPU0_SW) && (rst_reason != RESET_REASON_CPU0_RTC_WDT)) { + (rst_reason != RESET_REASON_CPU0_SW) && (rst_reason != RESET_REASON_CPU0_RTC_WDT) && + (rst_reason != RESET_REASON_CPU0_JTAG)) { periph_ll_disable_clk_set_rst(PERIPH_UART1_MODULE); periph_ll_disable_clk_set_rst(PERIPH_I2C0_MODULE); diff --git a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi index d61f0762e43..92a8fe51397 100644 --- a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi +++ b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi @@ -76,9 +76,15 @@ }; sramlp: memory@50000000 { + #address-cells = <1>; + #size-cells = <1>; compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x50000000 DT_SIZE_K(16)>; zephyr,memory-region = "SRAMLP "; + + shmlp: memory@0 { + reg = <0x0 0x10>; + }; }; intc: interrupt-controller@60010000 { diff --git a/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi new file mode 100644 index 00000000000..240000f12eb --- /dev/null +++ b/dts/riscv/espressif/esp32c6/esp32c6_lpcore.dtsi @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "espressif,riscv"; + riscv,isa = "rv32imac_zicsr_zifencei"; + reg = <0>; + clock-source = ; + clock-frequency = ; + xtal-freq = ; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + sramlp: memory@50000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mmio-sram"; + reg = <0x50000000 DT_SIZE_K(16)>; + + shmlp: memory@0 { + reg = <0x0 0x10>; + }; + }; + + flash: flash-controller@60002000 { + compatible = "espressif,esp32-flash-controller"; + reg = <0x60002000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <4>; + /* Flash size is specified in SOC/SIP dtsi */ + }; + }; + }; +}; diff --git a/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi new file mode 100644 index 00000000000..cfb4fc103dc --- /dev/null +++ b/dts/riscv/espressif/esp32c6/esp32c6_lpcore_wroom_n4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include "esp32c6_lpcore.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/include/zephyr/dt-bindings/clock/esp32c6_clock.h b/include/zephyr/dt-bindings/clock/esp32c6_clock.h index 9aa39b2c51e..b3264125790 100644 --- a/include/zephyr/dt-bindings/clock/esp32c6_clock.h +++ b/include/zephyr/dt-bindings/clock/esp32c6_clock.h @@ -13,28 +13,28 @@ #define ESP32_CLK_SRC_RC_FAST 2U /* Supported CPU frequencies */ -#define ESP32_CLK_CPU_PLL_80M 80000000 -#define ESP32_CLK_CPU_PLL_160M 160000000 +#define ESP32_CLK_CPU_PLL_80M 80000000 +#define ESP32_CLK_CPU_PLL_160M 160000000 #define ESP32_CLK_CPU_RC_FAST_FREQ 17500000 /* Supported XTAL Frequencies */ -#define ESP32_CLK_XTAL_32M 32000000 -#define ESP32_CLK_XTAL_40M 40000000 +#define ESP32_CLK_XTAL_32M 32000000 +#define ESP32_CLK_XTAL_40M 40000000 /* Supported RTC fast clock sources */ #define ESP32_RTC_FAST_CLK_SRC_RC_FAST 0 #define ESP32_RTC_FAST_CLK_SRC_XTAL_D2 1 /* Supported RTC slow clock frequencies */ -#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW 0 -#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K 1 -#define ESP32_RTC_SLOW_CLK_SRC_RC32K 2 -#define ESP32_RTC_SLOW_CLK_32K_EXT_OSC 9 +#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW 0 +#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K 1 +#define ESP32_RTC_SLOW_CLK_SRC_RC32K 2 +#define ESP32_RTC_SLOW_CLK_32K_EXT_OSC 9 /* RTC slow clock frequencies */ -#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ 136000 -#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K_FREQ 32768 -#define ESP32_RTC_SLOW_CLK_SRC_RC32K_FREQ 32768 +#define ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ 136000 +#define ESP32_RTC_SLOW_CLK_SRC_XTAL32K_FREQ 32768 +#define ESP32_RTC_SLOW_CLK_SRC_RC32K_FREQ 32768 /* Modules IDs * These IDs are actually offsets in CLK and RST Control registers. @@ -44,44 +44,49 @@ * Basic Modules * Registers: DPORT_PERIP_CLK_EN_REG, DPORT_PERIP_RST_EN_REG */ -#define ESP32_LEDC_MODULE 0 -#define ESP32_UART0_MODULE 1 -#define ESP32_UART1_MODULE 2 -#define ESP32_USB_MODULE 3 -#define ESP32_I2C0_MODULE 4 -#define ESP32_I2S1_MODULE 5 -#define ESP32_TIMG0_MODULE 6 -#define ESP32_TIMG1_MODULE 7 -#define ESP32_UHCI0_MODULE 8 -#define ESP32_RMT_MODULE 9 -#define ESP32_PCNT_MODULE 10 -#define ESP32_SPI_MODULE 11 -#define ESP32_SPI2_MODULE 12 -#define ESP32_TWAI0_MODULE 13 -#define ESP32_TWAI1_MODULE 14 -#define ESP32_RNG_MODULE 15 -#define ESP32_RSA_MODULE 16 -#define ESP32_AES_MODULE 17 -#define ESP32_SHA_MODULE 18 -#define ESP32_ECC_MODULE 19 -#define ESP32_HMAC_MODULE 20 -#define ESP32_DS_MODULE 21 -#define ESP32_SDIO_SLAVE_MODULE 22 -#define ESP32_GDMA_MODULE 23 -#define ESP32_MCPWM0_MODULE 24 -#define ESP32_ETM_MODULE 25 -#define ESP32_PARLIO_MODULE 26 -#define ESP32_SYSTIMER_MODULE 27 -#define ESP32_SARADC_MODULE 28 -#define ESP32_TEMPSENSOR_MODULE 29 -#define ESP32_REGDMA_MODULE 30 -#define ESP32_LP_I2C0_MODULE 31 +#define ESP32_LEDC_MODULE 0 +#define ESP32_UART0_MODULE 1 +#define ESP32_UART1_MODULE 2 +#define ESP32_USB_MODULE 3 +#define ESP32_I2C0_MODULE 4 +#define ESP32_I2S1_MODULE 5 +#define ESP32_TIMG0_MODULE 6 +#define ESP32_TIMG1_MODULE 7 +#define ESP32_UHCI0_MODULE 8 +#define ESP32_RMT_MODULE 9 +#define ESP32_PCNT_MODULE 10 +#define ESP32_SPI_MODULE 11 +#define ESP32_SPI2_MODULE 12 +#define ESP32_TWAI0_MODULE 13 +#define ESP32_TWAI1_MODULE 14 +#define ESP32_RNG_MODULE 15 +#define ESP32_RSA_MODULE 16 +#define ESP32_AES_MODULE 17 +#define ESP32_SHA_MODULE 18 +#define ESP32_ECC_MODULE 19 +#define ESP32_HMAC_MODULE 20 +#define ESP32_DS_MODULE 21 +#define ESP32_SDIO_SLAVE_MODULE 22 +#define ESP32_GDMA_MODULE 23 +#define ESP32_MCPWM0_MODULE 24 +#define ESP32_ETM_MODULE 25 +#define ESP32_PARLIO_MODULE 26 +#define ESP32_SYSTIMER_MODULE 27 +#define ESP32_SARADC_MODULE 28 +#define ESP32_TEMPSENSOR_MODULE 29 +#define ESP32_ASSIST_DEBUG_MODULE 30 +/* LP peripherals */ +#define ESP32_LP_I2C0_MODULE 31 +#define ESP32_LP_UART0_MODULE 32 /* Peripherals clock managed by the modem_clock driver must be listed last */ -#define ESP32_WIFI_MODULE 32 -#define ESP32_BT_MODULE 33 -#define ESP32_IEEE802154_MODULE 34 -#define ESP32_COEX_MODULE 35 -#define ESP32_PHY_MODULE 36 -#define ESP32_MODULE_MAX 37 +#define ESP32_WIFI_MODULE 33 +#define ESP32_BT_MODULE 34 +#define ESP32_IEEE802154_MODULE 35 +#define ESP32_COEX_MODULE 36 +#define ESP32_PHY_MODULE 37 +#define ESP32_ANA_I2C_MASTER_MODULE 38 +#define ESP32_MODEM_ETM_MODULE 39 +#define ESP32_MODEM_ADC_COMMON_FE_MODULE 40 +#define ESP32_MODULE_MAX 41 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_ESP32C6_H_ */ diff --git a/soc/espressif/Kconfig b/soc/espressif/Kconfig index 7a3b927957c..483ac468b67 100644 --- a/soc/espressif/Kconfig +++ b/soc/espressif/Kconfig @@ -62,4 +62,6 @@ config RTC_CLK_CAL_CYCLES If the crystal could not start, it will be switched to internal RC. endmenu +rsource "Kconfig.ulp" + endif # SOC_FAMILY_ESPRESSIF_ESP32 diff --git a/soc/espressif/Kconfig.ulp b/soc/espressif/Kconfig.ulp new file mode 100644 index 00000000000..6e542ad7306 --- /dev/null +++ b/soc/espressif/Kconfig.ulp @@ -0,0 +1,85 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +menu "Ultra Low Power (ULP) Coprocessor" + +config ULP_COPROC_ENABLED + bool "Ultra Low Power (ULP) Coprocessor" + help + Enable this feature if you plan to use the ULP Coprocessor. + Once this option is enabled, further ULP co-processor configuration will appear in the menu. + +choice ULP_COPROC_TYPE + prompt "ULP Coprocessor type" + depends on ULP_COPROC_ENABLED + default ULP_COPROC_TYPE_LP_CORE if SOC_SERIES_ESP32C6 + help + Choose the ULP Coprocessor type: ULP FSM (Finite State Machine) or ULP RISC-V. + +config ULP_COPROC_TYPE_FSM + bool "ULP FSM (Finite State Machine)" + depends on SOC_SERIES_ESP32 || SOC_SERIES_ESP32S2 || SOC_SERIES_ESP32S3 + +config ULP_COPROC_TYPE_RISCV + bool "ULP RISC-V" + depends on SOC_SERIES_ESP32S2 || SOC_SERIES_ESP32S3 + +config ULP_COPROC_TYPE_LP_CORE + bool "LP core RISC-V" + depends on SOC_SERIES_ESP32C6 +endchoice + +menu "ULP RISC-V Settings" + depends on ULP_COPROC_TYPE_RISCV + +config ULP_RISCV_INTERRUPT_ENABLE + bool "ULP RISC-V interrupts" + help + Turn on this setting to enabled interrupts on the ULP RISC-V core. + +endmenu + +menu "ULP Debugging Options" + +config ULP_PANIC_OUTPUT_ENABLE + bool "Panic handler outputs to LP UART" + depends on ULP_COPROC_TYPE_LP_CORE + help + Set this option to enable panic handler functionality. If this option is + enabled then the LP Core will output a panic dump over LP UART, + similar to what the main core does. Output depends on LP UART already being + initialized and configured. + Disabling this option will reduce the LP core binary size by not + linking in panic handler functionality. + +config ULP_HP_UART_CONSOLE_PRINT + bool "Route lp_core_printf to the console HP-UART" + depends on ULP_COPROC_TYPE_LP_CORE + help + Set this option to route lp_core_printf to the console HP-UART. + This allows you to easily view print outputs from the LP core, without + having to connect to the LP-UART. This option comes with the following + limitations: + + 1. There is no mutual exclusion between the HP-Core and the LP-Core accessing + the HP-UART, which means that if both cores are logging heavily the output + strings might get mangled together. + 2. The HP-UART can only work while the HP-Core is running, which means that + if the HP-Core is in deep sleep, the LP-Core will not be able to print to the + console HP-UART. + + Due to these limitations it is only recommended to use this option for easy debugging. + For more serious use-cases you should use the LP-UART. + +config ULP_NORESET_UNDER_DEBUG + bool "Avoid resetting LP core when debugger is attached" + depends on ULP_COPROC_TYPE_LP_CORE + default y + help + Enable this feature to avoid resetting LP core in sleep mode when debugger is attached, + otherwise configured HW breakpoints and dcsr.ebreak* bits will be missed. + This is a workaround until it will be fixed in HW. + +endmenu + +endmenu # Ultra Low Power (ULP) Coprocessor diff --git a/soc/espressif/esp32c6/default_lpcore.ld b/soc/espressif/esp32c6/default_lpcore.ld new file mode 100644 index 00000000000..b1fcd3c12b4 --- /dev/null +++ b/soc/espressif/esp32c6/default_lpcore.ld @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include "memory.h" + +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) +/* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_memory_shared.c + */ +#define ALIGNED_COPROC_MEM ALIGN_DOWN(ULP_COPROC_RESERVE_MEM, 0x8) + +#define RODATA_REGION ram +#define RAMABLE_REGION ram +#define ROMABLE_REGION ram + +/* User available memory segments */ +_aligned_coproc_mem = ALIGNED_COPROC_MEM; +_vector_table_org = LPSRAM_IRAM_START; +_vector_table_len = 0x80; +_ram_org = _vector_table_org + _vector_table_len; +_ram_len = _aligned_coproc_mem - _vector_table_len - ULP_SHARED_MEM; +_shared_mem_org = _ram_org + _ram_len; +_shared_mem_len = ULP_SHARED_MEM; + +ENTRY(reset_vector) + +MEMORY +{ + /*first 128byte for exception/interrupt vectors*/ + vector_table(RX) : ORIGIN = _vector_table_org , LENGTH = _vector_table_len + ram(RWX) : ORIGIN = _ram_org, LENGTH = _ram_len + shared_mem_ram(RW) : ORIGIN = _shared_mem_org, LENGTH = _shared_mem_len +} + +SECTIONS +{ + .vector.text : + { + __mtvec_base = .; + KEEP (*(.init.vector .init.vector.*)) + } > vector_table + + . = ORIGIN(ram); + + .text ALIGN(4): + { + *(.text.vectors) /* Default reset vector must link to offset 0x80 */ + __text_region_start = ABSOLUTE(.); + *(.text) + *(.text*) + __text_region_end = ABSOLUTE(.); + } >ram + + #include + + .rodata ALIGN(4): + { + __rodata_region_start = ABSOLUTE(.); + *(.rodata .srodata) + *(.rodata* .srodata*) + __rodata_region_end = .; + + } > ram + +#include + + .rodata.end ALIGN(4): + { + _rodata_reserved_end = ABSOLUTE(.); + } > ram + + .data ALIGN(4): + { + _image_ram_start = ABSOLUTE(.); + *(.data) + *(.data*) + *(.sdata) + *(.sdata*) + + } > ram + + #include + #include + #include + + .data.end ALIGN(4): + { + _image_ram_end = ABSOLUTE(.); + } > ram + + .data.noinit (NOLOAD): + { + . = ALIGN(4); + *(.noinit) + *(.noinit.*) + . = ALIGN(4); + } > ram + + .bss ALIGN(4) : + { + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + PROVIDE(end = .); + _heap_sentry = .; + } >ram + +#include + + __stack_top = ORIGIN(ram) + LENGTH(ram); + +#include + SECTION_PROLOGUE(.riscv.attributes, 0,) + { + KEEP(*(.riscv.attributes)) + KEEP(*(.gnu.attributes)) + } + + . = ORIGIN(shared_mem_ram); + .shared_mem (ALIGN(4)) : + { + KEEP(*(.shared_mem)) + } > shared_mem_ram +} diff --git a/soc/espressif/esp32c6/hpcore_init_ulp.c b/soc/espressif/esp32c6/hpcore_init_ulp.c new file mode 100644 index 00000000000..6ba9ed64317 --- /dev/null +++ b/soc/espressif/esp32c6/hpcore_init_ulp.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "bootloader_flash_priv.h" +#include +#include "ulp_lp_core.h" +#include "lp_core_uart.h" +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +void IRAM_ATTR lp_core_image_init(void) +{ + const uint32_t lpcore_img_off = FIXED_PARTITION_OFFSET(slot0_lpcore_partition); + const uint32_t lpcore_img_size = 0x4000; + int ret = 0; + + LOG_INF("Getting LPU image at %p, size %d", (void *)lpcore_img_off, lpcore_img_size); + + const uint8_t *data = (const uint8_t *)bootloader_mmap(lpcore_img_off, lpcore_img_size); + + ret = ulp_lp_core_load_binary(data, lpcore_img_size); + if (ret) { + LOG_ERR("Failed to load LP core image: %d", ret); + } + + LOG_INF("LP core image loaded"); + + /* Set LP core wakeup source as the HP CPU */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + ret = ulp_lp_core_run(&cfg); + if (ret) { + LOG_ERR("Failed to start LP core: %d", ret); + } +} + +void soc_late_init_hook(void) +{ + lp_core_image_init(); +} diff --git a/soc/espressif/esp32c6/memory.h b/soc/espressif/esp32c6/memory.h index 455c62aba03..c9f5dd85302 100644 --- a/soc/espressif/esp32c6/memory.h +++ b/soc/espressif/esp32c6/memory.h @@ -5,15 +5,18 @@ #pragma once /* LP-SRAM (16kB) memory */ -#define LPSRAM_IRAM_START DT_REG_ADDR(DT_NODELABEL(sramlp)) -#define LPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramlp)) +#define LPSRAM_IRAM_START DT_REG_ADDR(DT_NODELABEL(sramlp)) +#define LPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramlp)) +#define ULP_SHARED_MEM DT_REG_SIZE(DT_NODELABEL(shmlp)) +#define ULP_COPROC_RESERVE_MEM (0x4000) + /* HP-SRAM (512kB) memory */ -#define HPSRAM_START DT_REG_ADDR(DT_NODELABEL(sramhp)) -#define HPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramhp)) -#define HPSRAM_DRAM_START HPSRAM_START -#define HPSRAM_IRAM_START HPSRAM_START +#define HPSRAM_START DT_REG_ADDR(DT_NODELABEL(sramhp)) +#define HPSRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sramhp)) +#define HPSRAM_DRAM_START HPSRAM_START +#define HPSRAM_IRAM_START HPSRAM_START /* ICache size is fixed to 32KB on ESP32-C6 */ -#define ICACHE_SIZE 0x8000 +#define ICACHE_SIZE 0x8000 /** Simplified memory map for the bootloader. * Make sure the bootloader can load into main memory without overwriting itself. @@ -27,13 +30,13 @@ * buffers area (0x4087c610). */ -#define DRAM_BUFFERS_START 0x4086ad08 -#define DRAM_BUFFERS_END 0x4087c610 -#define DRAM_STACK_START DRAM_BUFFERS_END -#define DRAM_ROM_BSS_DATA_START 0x4087e610 +#define DRAM_BUFFERS_START 0x4086ad08 +#define DRAM_BUFFERS_END 0x4087c610 +#define DRAM_STACK_START DRAM_BUFFERS_END +#define DRAM_ROM_BSS_DATA_START 0x4087e610 /* Set the limit for the application runtime dynamic allocations */ -#define DRAM_RESERVED_START DRAM_BUFFERS_END +#define DRAM_RESERVED_START DRAM_BUFFERS_END /* For safety margin between bootloader data section and startup stacks */ #define BOOTLOADER_STACK_OVERHEAD 0x0 @@ -49,14 +52,14 @@ /* Start of the lower region is determined by region size and the end of the higher region */ #define BOOTLOADER_IRAM_LOADER_SEG_START (BOOTLOADER_USER_SRAM_END - BOOTLOADER_IRAM_LOADER_SEG_LEN) -#define BOOTLOADER_IRAM_SEG_START (BOOTLOADER_IRAM_LOADER_SEG_START - BOOTLOADER_IRAM_SEG_LEN) -#define BOOTLOADER_DRAM_SEG_START (BOOTLOADER_IRAM_SEG_START - BOOTLOADER_DRAM_SEG_LEN) +#define BOOTLOADER_IRAM_SEG_START (BOOTLOADER_IRAM_LOADER_SEG_START - BOOTLOADER_IRAM_SEG_LEN) +#define BOOTLOADER_DRAM_SEG_START (BOOTLOADER_IRAM_SEG_START - BOOTLOADER_DRAM_SEG_LEN) /* Flash */ #ifdef CONFIG_FLASH_SIZE -#define FLASH_SIZE CONFIG_FLASH_SIZE +#define FLASH_SIZE CONFIG_FLASH_SIZE #else -#define FLASH_SIZE 0x400000 +#define FLASH_SIZE 0x400000 #endif /* Cached memory */ diff --git a/soc/espressif/esp32c6/soc_lpcore.c b/soc/espressif/esp32c6/soc_lpcore.c new file mode 100644 index 00000000000..e2e5a5d2b53 --- /dev/null +++ b/soc/espressif/esp32c6/soc_lpcore.c @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#include "esp_rom_caps.h" +#include "rom/ets_sys.h" +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_lp_timer_shared.h" +#include "ulp_lp_core_memory_shared.h" +#include "ulp_lp_core_print.h" +#include +#include + +extern void main(void); + +/* Initialize lp core related system functions before calling user's main*/ +void lp_core_startup(void) +{ +#if CONFIG_ULP_HP_UART_CONSOLE_PRINT && ESP_ROM_HAS_LP_ROM + ets_install_putc1(lp_core_print_char); +#endif + + ulp_lp_core_update_wakeup_cause(); + + /* Start Zephyr */ + z_cstart(); + + CODE_UNREACHABLE; +} diff --git a/soc/espressif/esp32c6/start_lpcore.S b/soc/espressif/esp32c6/start_lpcore.S new file mode 100644 index 00000000000..b30015b09b7 --- /dev/null +++ b/soc/espressif/esp32c6/start_lpcore.S @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .text.vectors + .global reset_vector + +/* The reset vector, jumps to startup code */ +reset_vector: + + /* _vector_table: Only 256-byte aligned addresses are allowed */ + la t0, _vector_table + csrw mtvec, t0 + + j __start + +__start: + + /* setup the stack pointer */ + la sp, __stack_top + call lp_core_startup +loop: + j loop diff --git a/soc/espressif/esp32c6/vector_table_lpcore.S b/soc/espressif/esp32c6/vector_table_lpcore.S new file mode 100644 index 00000000000..3fe3f5a308f --- /dev/null +++ b/soc/espressif/esp32c6/vector_table_lpcore.S @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .init.vector,"ax" + + .global _vector_table + .type _vector_table, @function +_vector_table: + .option push + .option norvc + + .rept 30 + j _panic_handler + .endr + j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry + j _panic_handler + + .option pop + .size _vector_table, .-_vector_table diff --git a/soc/espressif/esp32c6/vectors_lpcore.S b/soc/espressif/esp32c6/vectors_lpcore.S new file mode 100644 index 00000000000..360977cadd1 --- /dev/null +++ b/soc/espressif/esp32c6/vectors_lpcore.S @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "riscv/rvruntime-frames.h" +#include + + .equ SAVE_REGS, 32 + .equ CONTEXT_SIZE, (SAVE_REGS * 4) +/* Macro which first allocates space on the stack to save general + * purpose registers, and then save them. GP register is excluded. + * The default size allocated on the stack is CONTEXT_SIZE, but it + * can be overridden. */ +.macro save_general_regs cxt_size=CONTEXT_SIZE + addi sp, sp, -\cxt_size + sw ra, RV_STK_RA(sp) + sw tp, RV_STK_TP(sp) + sw t0, RV_STK_T0(sp) + sw t1, RV_STK_T1(sp) + sw t2, RV_STK_T2(sp) + sw s0, RV_STK_S0(sp) + sw s1, RV_STK_S1(sp) + sw a0, RV_STK_A0(sp) + sw a1, RV_STK_A1(sp) + sw a2, RV_STK_A2(sp) + sw a3, RV_STK_A3(sp) + sw a4, RV_STK_A4(sp) + sw a5, RV_STK_A5(sp) + sw a6, RV_STK_A6(sp) + sw a7, RV_STK_A7(sp) + sw s2, RV_STK_S2(sp) + sw s3, RV_STK_S3(sp) + sw s4, RV_STK_S4(sp) + sw s5, RV_STK_S5(sp) + sw s6, RV_STK_S6(sp) + sw s7, RV_STK_S7(sp) + sw s8, RV_STK_S8(sp) + sw s9, RV_STK_S9(sp) + sw s10, RV_STK_S10(sp) + sw s11, RV_STK_S11(sp) + sw t3, RV_STK_T3(sp) + sw t4, RV_STK_T4(sp) + sw t5, RV_STK_T5(sp) + sw t6, RV_STK_T6(sp) +.endm + +.macro save_mepc + csrr t0, mepc + sw t0, RV_STK_MEPC(sp) +.endm + +/* Restore the general purpose registers (excluding gp) from the context on + * the stack. The context is then deallocated. The default size is CONTEXT_SIZE + * but it can be overridden. */ +.macro restore_general_regs cxt_size=CONTEXT_SIZE + lw ra, RV_STK_RA(sp) + lw tp, RV_STK_TP(sp) + lw t0, RV_STK_T0(sp) + lw t1, RV_STK_T1(sp) + lw t2, RV_STK_T2(sp) + lw s0, RV_STK_S0(sp) + lw s1, RV_STK_S1(sp) + lw a0, RV_STK_A0(sp) + lw a1, RV_STK_A1(sp) + lw a2, RV_STK_A2(sp) + lw a3, RV_STK_A3(sp) + lw a4, RV_STK_A4(sp) + lw a5, RV_STK_A5(sp) + lw a6, RV_STK_A6(sp) + lw a7, RV_STK_A7(sp) + lw s2, RV_STK_S2(sp) + lw s3, RV_STK_S3(sp) + lw s4, RV_STK_S4(sp) + lw s5, RV_STK_S5(sp) + lw s6, RV_STK_S6(sp) + lw s7, RV_STK_S7(sp) + lw s8, RV_STK_S8(sp) + lw s9, RV_STK_S9(sp) + lw s10, RV_STK_S10(sp) + lw s11, RV_STK_S11(sp) + lw t3, RV_STK_T3(sp) + lw t4, RV_STK_T4(sp) + lw t5, RV_STK_T5(sp) + lw t6, RV_STK_T6(sp) + addi sp,sp, \cxt_size +.endm + +.macro restore_mepc + lw t0, RV_STK_MEPC(sp) + csrw mepc, t0 +.endm + + +/* _panic_handler: handle all exception */ + .section .text.handlers,"ax" + .global _panic_handler + .type _panic_handler, @function +_panic_handler: + save_general_regs RV_STK_FRMSZ + save_mepc + + addi t0, sp, RV_STK_FRMSZ /* Restore sp with the value when trap happened */ + + /* Save CSRs */ + sw t0, RV_STK_SP(sp) + csrr t0, mstatus + sw t0, RV_STK_MSTATUS(sp) + csrr t0, mcause + sw t0, RV_STK_MCAUSE(sp) + csrr t0, mtvec + sw t0, RV_STK_MTVEC(sp) + csrr t0, mhartid + sw t0, RV_STK_MHARTID(sp) + csrr t0, mtval + sw t0, RV_STK_MTVAL(sp) + + csrr a1, mcause /* Exception cause */ + + mv a0, sp /* RvExcFrame *regs */ + call ulp_lp_core_panic_handler +_end: + j _end /* loop forever */ + + +/* _interrupt_handler: handle all interrupt */ + .section .text.handlers,"ax" + .global _interrupt_handler + .type _interrupt_handler, @function +_interrupt_handler: + /* Save registers & mepc to stack */ + save_general_regs + save_mepc + + call ulp_lp_core_intr_handler + + /* Restore registers & mepc from stack */ + restore_mepc + restore_general_regs + /* Exit, this will also re-enable the interrupts */ + mret