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