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