1 /* 2 * Copyright (C) 2024 Nordic Semiconductor ASA 3 * SPDX-License-Identifier: Apache-2.0 4 */ 5 6 #ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ 7 #define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ 8 9 #include <zephyr/arch/riscv/irq.h> 10 11 #if !defined(_ASMLANGUAGE) 12 13 #include <zephyr/devicetree.h> 14 15 #define VPR_CPU DT_INST(0, nordic_vpr) 16 17 #if DT_PROP(VPR_CPU, nordic_bus_width) == 64 18 19 #define SOC_ISR_STACKING_ESF_DECLARE \ 20 struct arch_esf { \ 21 unsigned long s0; \ 22 unsigned long mstatus; \ 23 unsigned long tp; \ 24 struct soc_esf soc_context; \ 25 \ 26 unsigned long t2; \ 27 unsigned long ra; \ 28 unsigned long t0; \ 29 unsigned long t1; \ 30 unsigned long a4; \ 31 unsigned long a5; \ 32 unsigned long a2; \ 33 unsigned long a3; \ 34 unsigned long a0; \ 35 unsigned long a1; \ 36 unsigned long mepc; \ 37 unsigned long _mcause; \ 38 } __aligned(16); 39 40 #else /* DT_PROP(VPR_CPU, nordic_bus_width) == 32 */ 41 42 #define SOC_ISR_STACKING_ESF_DECLARE \ 43 struct arch_esf { \ 44 unsigned long s0; \ 45 unsigned long mstatus; \ 46 unsigned long tp; \ 47 struct soc_esf soc_context; \ 48 \ 49 unsigned long ra; \ 50 unsigned long t2; \ 51 unsigned long t1; \ 52 unsigned long t0; \ 53 unsigned long a5; \ 54 unsigned long a4; \ 55 unsigned long a3; \ 56 unsigned long a2; \ 57 unsigned long a1; \ 58 unsigned long a0; \ 59 unsigned long _mcause; \ 60 unsigned long mepc; \ 61 } __aligned(16); 62 63 #endif /* DT_PROP(VPR_CPU, nordic_bus_width) == 64 */ 64 65 #else /* _ASMLANGUAGE */ 66 67 /* 68 * Size of the HW managed part of the ESF: 69 * sizeof(_mcause) + sizeof(_mepc) 70 */ 71 #define ESF_HW_SIZEOF (0x8) 72 73 /* 74 * Size of the SW managed part of the ESF in case of exception 75 */ 76 #define ESF_SW_EXC_SIZEOF (__struct_arch_esf_SIZEOF - ESF_HW_SIZEOF) 77 78 /* 79 * Size of the SW managed part of the ESF in case of interrupt 80 * sizeof(__padding) + ... + sizeof(soc_context) 81 */ 82 #define ESF_SW_IRQ_SIZEOF (0x20) 83 84 /* 85 * VPR needs aligned(8) SP when doing HW stacking, if this condition is not fulfilled it will move 86 * SP by additional 4 bytes when HW stacking is done. This will be indicated by LSB bit in stacked 87 * MEPC. This bit needs to be saved and then restored because zephyr is managing MEPC and doesn't 88 * know anything about this additional offset. 89 */ 90 #define MEPC_SP_ALIGN_BIT_MASK (0x1UL) 91 92 #define STORE_SP_ALIGN_BIT_FROM_MEPC \ 93 addi t1, sp, __struct_arch_esf_soc_context_OFFSET; \ 94 lr t0, __struct_arch_esf_mepc_OFFSET(sp); \ 95 andi t0, t0, MEPC_SP_ALIGN_BIT_MASK; \ 96 sr t0, __soc_esf_t_sp_align_OFFSET(t1) 97 98 #define RESTORE_SP_ALIGN_BIT_TO_MEPC \ 99 addi t1, sp, __struct_arch_esf_soc_context_OFFSET; \ 100 lr t0, __soc_esf_t_sp_align_OFFSET(t1); \ 101 lr t1, __struct_arch_esf_mepc_OFFSET(sp); \ 102 or t2, t1, t0; \ 103 sr t2, __struct_arch_esf_mepc_OFFSET(sp) 104 105 #define SOC_ISR_SW_STACKING \ 106 csrw mscratch, t0; \ 107 \ 108 csrr t0, mcause; \ 109 srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ 110 bnez t0, stacking_is_interrupt; \ 111 \ 112 csrrw t0, mscratch, zero; \ 113 \ 114 addi sp, sp, -ESF_SW_EXC_SIZEOF; \ 115 DO_CALLER_SAVED(sr); \ 116 j stacking_keep_going; \ 117 \ 118 stacking_is_interrupt: \ 119 addi sp, sp, -ESF_SW_IRQ_SIZEOF; \ 120 \ 121 stacking_keep_going: \ 122 STORE_SP_ALIGN_BIT_FROM_MEPC 123 124 #define SOC_ISR_SW_UNSTACKING \ 125 RESTORE_SP_ALIGN_BIT_TO_MEPC; \ 126 csrr t0, mcause; \ 127 srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ 128 bnez t0, unstacking_is_interrupt; \ 129 \ 130 DO_CALLER_SAVED(lr); \ 131 addi sp, sp, ESF_SW_EXC_SIZEOF; \ 132 j unstacking_keep_going; \ 133 \ 134 unstacking_is_interrupt: \ 135 addi sp, sp, ESF_SW_IRQ_SIZEOF; \ 136 \ 137 unstacking_keep_going: 138 139 #endif /* _ASMLANGUAGE */ 140 141 #endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ */ 142