soc: espressif: esp32c6: Add LP Core

Add ULP Coprocessor support for ESP32C6.

Signed-off-by: Lucas Tamborrino <lucas.tamborrino@espressif.com>
This commit is contained in:
Lucas Tamborrino 2025-01-20 16:49:06 -03:00 committed by Benjamin Cabé
commit 0b9e4e013a
14 changed files with 642 additions and 66 deletions

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/devicetree.h>
#include <zephyr/linker/sections.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/linker/linker-tool.h>
#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 <zephyr/linker/rel-sections.ld>
.rodata ALIGN(4):
{
__rodata_region_start = ABSOLUTE(.);
*(.rodata .srodata)
*(.rodata* .srodata*)
__rodata_region_end = .;
} > ram
#include <zephyr/linker/common-rom/common-rom-kernel-devices.ld>
.rodata.end ALIGN(4):
{
_rodata_reserved_end = ABSOLUTE(.);
} > ram
.data ALIGN(4):
{
_image_ram_start = ABSOLUTE(.);
*(.data)
*(.data*)
*(.sdata)
*(.sdata*)
} > ram
#include <snippets-data-sections.ld>
#include <zephyr/linker/common-ram.ld>
#include <snippets-ram-sections.ld>
.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 <zephyr/linker/ram-end.ld>
__stack_top = ORIGIN(ram) + LENGTH(ram);
#include <zephyr/linker/debug-sections.ld>
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
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include "bootloader_flash_priv.h"
#include <zephyr/storage/flash_map.h>
#include "ulp_lp_core.h"
#include "lp_core_uart.h"
#include <zephyr/logging/log.h>
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();
}

View file

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

View file

@ -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 <soc.h>
#include <kernel_internal.h>
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;
}

View file

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

View file

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

View file

@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "riscv/rvruntime-frames.h"
#include <soc/soc_caps.h>
.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