zephyr/soc/nordic/common/vpr/soc_isr_stacking.h

142 lines
6.0 KiB
C

/*
* Copyright (C) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_
#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_
#include <zephyr/arch/riscv/irq.h>
#if !defined(_ASMLANGUAGE)
#include <zephyr/devicetree.h>
#define VPR_CPU DT_INST(0, nordic_vpr)
#if DT_PROP(VPR_CPU, nordic_bus_width) == 64
#define SOC_ISR_STACKING_ESF_DECLARE \
struct arch_esf { \
unsigned long s0; \
unsigned long mstatus; \
unsigned long tp; \
struct soc_esf soc_context; \
\
unsigned long t2; \
unsigned long ra; \
unsigned long t0; \
unsigned long t1; \
unsigned long a4; \
unsigned long a5; \
unsigned long a2; \
unsigned long a3; \
unsigned long a0; \
unsigned long a1; \
unsigned long mepc; \
unsigned long _mcause; \
} __aligned(16);
#else /* DT_PROP(VPR_CPU, nordic_bus_width) == 32 */
#define SOC_ISR_STACKING_ESF_DECLARE \
struct arch_esf { \
unsigned long s0; \
unsigned long mstatus; \
unsigned long tp; \
struct soc_esf soc_context; \
\
unsigned long ra; \
unsigned long t2; \
unsigned long t1; \
unsigned long t0; \
unsigned long a5; \
unsigned long a4; \
unsigned long a3; \
unsigned long a2; \
unsigned long a1; \
unsigned long a0; \
unsigned long _mcause; \
unsigned long mepc; \
} __aligned(16);
#endif /* DT_PROP(VPR_CPU, nordic_bus_width) == 64 */
#else /* _ASMLANGUAGE */
/*
* Size of the HW managed part of the ESF:
* sizeof(_mcause) + sizeof(_mepc)
*/
#define ESF_HW_SIZEOF (0x8)
/*
* Size of the SW managed part of the ESF in case of exception
*/
#define ESF_SW_EXC_SIZEOF (__struct_arch_esf_SIZEOF - ESF_HW_SIZEOF)
/*
* Size of the SW managed part of the ESF in case of interrupt
* sizeof(__padding) + ... + sizeof(soc_context)
*/
#define ESF_SW_IRQ_SIZEOF (0x20)
/*
* VPR needs aligned(8) SP when doing HW stacking, if this condition is not fulfilled it will move
* SP by additional 4 bytes when HW stacking is done. This will be indicated by LSB bit in stacked
* MEPC. This bit needs to be saved and then restored because zephyr is managing MEPC and doesn't
* know anything about this additional offset.
*/
#define MEPC_SP_ALIGN_BIT_MASK (0x1UL)
#define STORE_SP_ALIGN_BIT_FROM_MEPC \
addi t1, sp, __struct_arch_esf_soc_context_OFFSET; \
lr t0, __struct_arch_esf_mepc_OFFSET(sp); \
andi t0, t0, MEPC_SP_ALIGN_BIT_MASK; \
sr t0, __soc_esf_t_sp_align_OFFSET(t1)
#define RESTORE_SP_ALIGN_BIT_TO_MEPC \
addi t1, sp, __struct_arch_esf_soc_context_OFFSET; \
lr t0, __soc_esf_t_sp_align_OFFSET(t1); \
lr t1, __struct_arch_esf_mepc_OFFSET(sp); \
or t2, t1, t0; \
sr t2, __struct_arch_esf_mepc_OFFSET(sp)
#define SOC_ISR_SW_STACKING \
csrw mscratch, t0; \
\
csrr t0, mcause; \
srli t0, t0, RISCV_MCAUSE_IRQ_POS; \
bnez t0, stacking_is_interrupt; \
\
csrrw t0, mscratch, zero; \
\
addi sp, sp, -ESF_SW_EXC_SIZEOF; \
DO_CALLER_SAVED(sr); \
j stacking_keep_going; \
\
stacking_is_interrupt: \
addi sp, sp, -ESF_SW_IRQ_SIZEOF; \
\
stacking_keep_going: \
STORE_SP_ALIGN_BIT_FROM_MEPC
#define SOC_ISR_SW_UNSTACKING \
RESTORE_SP_ALIGN_BIT_TO_MEPC; \
csrr t0, mcause; \
srli t0, t0, RISCV_MCAUSE_IRQ_POS; \
bnez t0, unstacking_is_interrupt; \
\
DO_CALLER_SAVED(lr); \
addi sp, sp, ESF_SW_EXC_SIZEOF; \
j unstacking_keep_going; \
\
unstacking_is_interrupt: \
addi sp, sp, ESF_SW_IRQ_SIZEOF; \
\
unstacking_keep_going:
#endif /* _ASMLANGUAGE */
#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ */