1 /*
2  * Copyright (c) 2017 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * This file includes the RADIO event & signals functionality,
8  * the registers writes sideeffects for tasks, subscriptions, events,
9  * and interrupt masks.
10  * For signals, when a signal is generated:
11  *   Setting the EVENTS registers
12  *   Sending the signal to the PPI
13  *   Generating the corresponding interrupts
14  *   Calling tasks if the corresponding shortcuts are enabled
15  *
16  *
17  */
18 
19 #include <string.h>
20 #include "NHW_common_types.h"
21 #include "NHW_templates.h"
22 #include "NHW_config.h"
23 #include "NHW_peri_types.h"
24 #include "NHW_RADIO.h"
25 #include "NHW_RADIO_utils.h"
26 #include "NHW_RADIO_priv.h"
27 #include "NHW_xPPI.h"
28 #include "irq_ctrl.h"
29 #include "bs_tracing.h"
30 
31 #if NHW_RADIO_IS_54
32 static const ptrdiff_t radio_int_pdiff =
33     offsetof(NRF_RADIO_Type, INTENSET10) - offsetof(NRF_RADIO_Type, INTENSET00);
34 #endif
35 
36 #if (NHW_HAS_DPPI)
37 /* Mapping of peripheral instance to DPPI instance */
38 static uint nhw_RADIO_dppi_map[NHW_RADIO_TOTAL_INST] = NHW_RADIO_DPPI_MAP;
39 #endif
40 static uint32_t RADIO_INTEN[NHW_RADIO_N_INT]; //interrupt enable
41 extern NRF_RADIO_Type NRF_RADIO_regs;
42 
43 extern void nhw_RADIO_fake_task_TRXEN_TIFS(void);
44 
nhwra_signalif_reset(void)45 void nhwra_signalif_reset(void){
46   memset(RADIO_INTEN, 0, sizeof(RADIO_INTEN));
47 }
48 
nhw_RADIO_eval_interrupt(uint inst)49 static void nhw_RADIO_eval_interrupt(uint inst) {
50   static bool radio_int_line[NHW_RADIO_N_INT]; /* Is the RADIO currently driving this interrupt line high */
51   /* Mapping of interrupt line to {int controller instance, int number} */
52   static struct nhw_irq_mapping nhw_radio_irq_map[NHW_RADIO_N_INT] = NHW_RADIO_INT_MAP;
53 
54   (void)inst;
55 
56 #define _RADIO_CHECK_INTERRUPT(event, inten, intenset) \
57   if (NRF_RADIO_regs.EVENTS_##event && (inten &  RADIO_ ## intenset ## event ##_Msk)){ \
58     new_int_line = true; \
59   }
60 
61 #if NHW_RADIO_IS_54
62   #define RADIO_CHECK_INTERRUPT(event, inten) \
63     _RADIO_CHECK_INTERRUPT(event, inten, INTENSET00_ )
64 #else
65   #define RADIO_CHECK_INTERRUPT(event, inten) \
66 		_RADIO_CHECK_INTERRUPT(event, inten, INTENSET_)
67 #endif
68 
69   for (int i = 0; i < NHW_RADIO_N_INT; i ++) {
70     bool new_int_line = false;
71 
72     RADIO_CHECK_INTERRUPT(READY, RADIO_INTEN[i])
73     RADIO_CHECK_INTERRUPT(ADDRESS, RADIO_INTEN[i])
74     RADIO_CHECK_INTERRUPT(PAYLOAD, RADIO_INTEN[i])
75     RADIO_CHECK_INTERRUPT(END, RADIO_INTEN[i])
76     RADIO_CHECK_INTERRUPT(DISABLED, RADIO_INTEN[i])
77     RADIO_CHECK_INTERRUPT(DEVMATCH, RADIO_INTEN[i])
78     RADIO_CHECK_INTERRUPT(DEVMISS, RADIO_INTEN[i])
79 #if !NHW_RADIO_IS_54
80     RADIO_CHECK_INTERRUPT(RSSIEND, RADIO_INTEN[i])
81 #endif
82     RADIO_CHECK_INTERRUPT(BCMATCH, RADIO_INTEN[i])
83     RADIO_CHECK_INTERRUPT(CRCOK, RADIO_INTEN[i])
84     RADIO_CHECK_INTERRUPT(CRCERROR, RADIO_INTEN[i])
85     RADIO_CHECK_INTERRUPT(FRAMESTART, RADIO_INTEN[i])
86     RADIO_CHECK_INTERRUPT(EDEND, RADIO_INTEN[i])
87     RADIO_CHECK_INTERRUPT(EDSTOPPED, RADIO_INTEN[i])
88     RADIO_CHECK_INTERRUPT(CCAIDLE, RADIO_INTEN[i])
89     RADIO_CHECK_INTERRUPT(CCABUSY, RADIO_INTEN[i])
90     RADIO_CHECK_INTERRUPT(CCASTOPPED, RADIO_INTEN[i])
91     RADIO_CHECK_INTERRUPT(RATEBOOST, RADIO_INTEN[i])
92     RADIO_CHECK_INTERRUPT(TXREADY, RADIO_INTEN[i])
93     RADIO_CHECK_INTERRUPT(RXREADY, RADIO_INTEN[i])
94     RADIO_CHECK_INTERRUPT(MHRMATCH, RADIO_INTEN[i])
95     RADIO_CHECK_INTERRUPT(SYNC, RADIO_INTEN[i])
96     RADIO_CHECK_INTERRUPT(PHYEND, RADIO_INTEN[i])
97     RADIO_CHECK_INTERRUPT(CTEPRESENT, RADIO_INTEN[i])
98 
99     hw_irq_ctrl_toggle_level_irq_line_if(&radio_int_line[i],
100                                           new_int_line,
101                                           &nhw_radio_irq_map[i]);
102   }
103 }
104 
nhw_RADIO_regw_sideeffects_INTENSET(unsigned int int_l)105 void nhw_RADIO_regw_sideeffects_INTENSET(unsigned int int_l) {
106 #if NHW_RADIO_IS_54
107   uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_RADIO_regs.INTENSET00 + int_l*radio_int_pdiff);
108 #else
109   uint32_t *INTENSET = (uint32_t *)(uintptr_t)&NRF_RADIO_regs.INTENSET;
110 #endif
111 
112   if (*INTENSET){ /* LCOV_EXCL_BR_LINE */
113     RADIO_INTEN[int_l] |= *INTENSET;
114     *INTENSET = RADIO_INTEN[int_l];
115     nhw_RADIO_eval_interrupt(0);
116   }
117 }
118 
nhw_RADIO_regw_sideeffects_INTENCLR(unsigned int int_l)119 void nhw_RADIO_regw_sideeffects_INTENCLR(unsigned int int_l) {
120 #if NHW_RADIO_IS_54
121   uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_RADIO_regs.INTENSET00 + int_l*radio_int_pdiff);
122   uint32_t *INTENCLR = (uint32_t *)((uintptr_t)&NRF_RADIO_regs.INTENCLR00 + int_l*radio_int_pdiff);
123 #else
124   uint32_t *INTENSET = (uint32_t *)(uintptr_t)&NRF_RADIO_regs.INTENSET;
125   uint32_t *INTENCLR = (uint32_t *)(uintptr_t)&NRF_RADIO_regs.INTENCLR;
126 #endif
127 
128   if (*INTENCLR){/* LCOV_EXCL_BR_LINE */
129     RADIO_INTEN[int_l] &= ~*INTENCLR;
130     *INTENSET = RADIO_INTEN[int_l];
131     *INTENCLR = 0;
132     nhw_RADIO_eval_interrupt(0);
133   }
134 }
135 
136 NHW_SIDEEFFECTS_EVENTS(RADIO)
137 
NHW_SIGNAL_EVENT_ns_si(RADIO,READY)138 static NHW_SIGNAL_EVENT_ns_si(RADIO, READY)
139 static NHW_SIGNAL_EVENT_ns_si(RADIO, ADDRESS)
140 NHW_SIGNAL_EVENT_si(RADIO, PAYLOAD)
141 static NHW_SIGNAL_EVENT_ns_si(RADIO, END)
142 static NHW_SIGNAL_EVENT_ns_si(RADIO, DISABLED)
143 NHW_SIGNAL_EVENT_si(RADIO, DEVMATCH)
144 NHW_SIGNAL_EVENT_si(RADIO, DEVMISS)
145 #if !NHW_RADIO_IS_54
146 NHW_SIGNAL_EVENT_si(RADIO, RSSIEND)
147 #endif
148 NHW_SIGNAL_EVENT_si(RADIO, BCMATCH)
149 NHW_SIGNAL_EVENT_si(RADIO, CRCOK)
150 NHW_SIGNAL_EVENT_si(RADIO, CRCERROR)
151 static NHW_SIGNAL_EVENT_ns_si(RADIO, FRAMESTART)
152 static NHW_SIGNAL_EVENT_ns_si(RADIO, EDEND)
153 NHW_SIGNAL_EVENT_si(RADIO, EDSTOPPED)
154 static NHW_SIGNAL_EVENT_ns_si(RADIO, CCAIDLE)
155 static NHW_SIGNAL_EVENT_ns_si(RADIO, CCABUSY)
156 NHW_SIGNAL_EVENT_si(RADIO, CCASTOPPED)
157 NHW_SIGNAL_EVENT_si(RADIO, RATEBOOST)
158 static NHW_SIGNAL_EVENT_ns_si(RADIO, TXREADY)
159 static NHW_SIGNAL_EVENT_ns_si(RADIO, RXREADY)
160 NHW_SIGNAL_EVENT_si(RADIO, MHRMATCH)
161 NHW_SIGNAL_EVENT_si(RADIO, SYNC)
162 static NHW_SIGNAL_EVENT_ns_si(RADIO, PHYEND)
163 NHW_SIGNAL_EVENT_si(RADIO, CTEPRESENT)
164 
165 void nhw_RADIO_signal_EVENTS_READY(unsigned int inst) {
166   nhw_RADIO_signal_EVENTS_READY_noshort(inst);
167 
168   NHW_SHORT_si(RADIO, READY, START)
169   NHW_SHORT_si(RADIO, READY, EDSTART)
170 }
171 
nhw_RADIO_signal_EVENTS_ADDRESS(unsigned int inst)172 void nhw_RADIO_signal_EVENTS_ADDRESS(unsigned int inst) {
173   nhw_RADIO_signal_EVENTS_ADDRESS_noshort(inst);
174 
175   NHW_SHORT_si(RADIO, ADDRESS, RSSISTART)
176   NHW_SHORT_si(RADIO, ADDRESS, BCSTART)
177 }
178 
nhw_RADIO_signal_EVENTS_END(unsigned int inst)179 void nhw_RADIO_signal_EVENTS_END(unsigned int inst) {
180   nhw_RADIO_signal_EVENTS_END_noshort(inst);
181 
182 #if !NHW_RADIO_IS_54
183   NHW_SHORT_si(RADIO, END, DISABLE)
184 #endif
185   NHW_SHORT_si(RADIO, END, START)
186 }
187 
nhw_RADIO_signal_EVENTS_DISABLED(unsigned int inst)188 void nhw_RADIO_signal_EVENTS_DISABLED(unsigned int inst) {
189   nhw_RADIO_signal_EVENTS_DISABLED_noshort(inst);
190 
191   /*
192    * Everything indicates that, when the HW TIFS is enabled
193    * what happens is that these DISABLED_[TR]XEN shorts are
194    * effectively disabled and the tasks_[TR]XEN is instead
195    * triggered when a HW counter/timer triggers a bit later
196    */
197   if (nhwra_is_HW_TIFS_enabled()) {
198      /* This is a fake task meant to start a HW timer for the TIFS
199       * which has effect only if the TIFS was enabled.
200       * In that case, the TXEN or RXEN will be triggered in a small
201       * while (as per the TIFS configuration/Timer_TIFS), instead of right now */
202       nhw_RADIO_fake_task_TRXEN_TIFS();
203   } else {
204     /* Otherwise the normal TXEN/RXEN shortcuts apply */
205     NHW_SHORT_si(RADIO, DISABLED, TXEN)
206     NHW_SHORT_si(RADIO, DISABLED, RXEN)
207   }
208 
209 #if !NHW_RADIO_IS_54
210   NHW_SHORT_si(RADIO, DISABLED, RSSISTOP)
211 #endif
212 }
213 
nhw_RADIO_signal_EVENTS_FRAMESTART(unsigned int inst)214 void nhw_RADIO_signal_EVENTS_FRAMESTART(unsigned int inst) {
215   nhw_RADIO_signal_EVENTS_FRAMESTART_noshort(inst);
216 
217   NHW_SHORT_si(RADIO, FRAMESTART, BCSTART)
218 }
219 
nhw_RADIO_signal_EVENTS_EDEND(unsigned int inst)220 void nhw_RADIO_signal_EVENTS_EDEND(unsigned int inst) {
221   nhw_RADIO_signal_EVENTS_EDEND_noshort(inst);
222 
223   NHW_SHORT_si(RADIO, EDEND, DISABLE)
224 }
225 
nhw_RADIO_signal_EVENTS_CCAIDLE(unsigned int inst)226 void nhw_RADIO_signal_EVENTS_CCAIDLE(unsigned int inst) {
227   nhw_RADIO_signal_EVENTS_CCAIDLE_noshort(inst);
228 
229   NHW_SHORT_si(RADIO, CCAIDLE, STOP)
230   NHW_SHORT_si(RADIO, CCAIDLE, TXEN)
231 }
232 
nhw_RADIO_signal_EVENTS_CCABUSY(unsigned int inst)233 void nhw_RADIO_signal_EVENTS_CCABUSY(unsigned int inst) {
234   nhw_RADIO_signal_EVENTS_CCABUSY_noshort(inst);
235 
236   NHW_SHORT_si(RADIO, CCABUSY, DISABLE)
237 }
238 
nhw_RADIO_signal_EVENTS_TXREADY(unsigned int inst)239 void nhw_RADIO_signal_EVENTS_TXREADY(unsigned int inst) {
240   nhw_RADIO_signal_EVENTS_TXREADY_noshort(inst);
241 
242   NHW_SHORT_si(RADIO, TXREADY, START)
243 }
244 
nhw_RADIO_signal_EVENTS_RXREADY(unsigned int inst)245 void nhw_RADIO_signal_EVENTS_RXREADY(unsigned int inst) {
246   nhw_RADIO_signal_EVENTS_RXREADY_noshort(inst);
247 
248   NHW_SHORT_si(RADIO, RXREADY, START)
249   NHW_SHORT_si(RADIO, RXREADY, CCASTART)
250 }
251 
nhw_RADIO_signal_EVENTS_PHYEND(unsigned int inst)252 void nhw_RADIO_signal_EVENTS_PHYEND(unsigned int inst) {
253   nhw_RADIO_signal_EVENTS_PHYEND_noshort(inst);
254 
255   NHW_SHORT_si(RADIO, PHYEND, DISABLE)
256   NHW_SHORT_si(RADIO, PHYEND, START)
257 }
258 
259 
260 extern NRF_RADIO_Type NRF_RADIO_regs;
261 
262 
NHW_SIDEEFFECTS_TASKS_si(RADIO,TXEN)263 NHW_SIDEEFFECTS_TASKS_si(RADIO, TXEN)
264 NHW_SIDEEFFECTS_TASKS_si(RADIO, RXEN)
265 NHW_SIDEEFFECTS_TASKS_si(RADIO, START)
266 NHW_SIDEEFFECTS_TASKS_si(RADIO, STOP)
267 NHW_SIDEEFFECTS_TASKS_si(RADIO, DISABLE)
268 
269 void nhw_RADIO_regw_sideeffects_TASKS_RSSISTART(void) {
270   //We don't need to model this yet
271   if ( NRF_RADIO_regs.TASKS_RSSISTART ){
272     NRF_RADIO_regs.TASKS_RSSISTART = 0;
273     bs_trace_warning_line_time("RADIO: Sampling RSSI by writing to TASK_RSSISTART register is not supported by the model yet\n");
274   }
275 }
276 
277 #if !NHW_RADIO_IS_54
nhw_RADIO_regw_sideeffects_TASKS_RSSISTOP(void)278 void nhw_RADIO_regw_sideeffects_TASKS_RSSISTOP(void) {
279   //We don't need to model this yet
280   if ( NRF_RADIO_regs.TASKS_RSSISTOP ){
281     NRF_RADIO_regs.TASKS_RSSISTOP = 0;
282     bs_trace_warning_line_time("RADIO: Sampling RSSI by writing to TASK_RSSISTOP register is not supported by the model yet\n");
283   }
284 }
285 #endif
286 
287 NHW_SIDEEFFECTS_TASKS_si(RADIO, BCSTART)
288 NHW_SIDEEFFECTS_TASKS_si(RADIO, BCSTOP)
289 NHW_SIDEEFFECTS_TASKS_si(RADIO, EDSTART)
290 NHW_SIDEEFFECTS_TASKS_si(RADIO, EDSTOP)
291 NHW_SIDEEFFECTS_TASKS_si(RADIO, CCASTART)
292 NHW_SIDEEFFECTS_TASKS_si(RADIO, CCASTOP)
293 #if NHW_RADIO_IS_54
294 NHW_SIDEEFFECTS_TASKS_si(RADIO, SOFTRESET)
295 #endif
296 
297 #if (NHW_HAS_DPPI)
298 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, TXEN)
299 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, RXEN)
300 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, START)
301 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, STOP)
302 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, DISABLE)
303 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, RSSISTART)
304 #if !NHW_RADIO_IS_54
305 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, RSSISTOP)
306 #endif
307 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, BCSTART)
308 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, BCSTOP)
309 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, EDSTART)
310 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, EDSTOP)
311 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, CCASTART)
312 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, CCASTOP)
313 #if NHW_RADIO_IS_54
314 NHW_SIDEEFFECTS_SUBSCRIBE_si(RADIO, SOFTRESET)
315 #endif
316 #endif /* NHW_HAS_DPPI */
317