1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * GPIO - General purpose input/output
9 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/gpio.html?cp=5_1_0_5_7
10 *
11 * This model has the following limitations:
12 * * Note a.1:
13 * PIN_CNF.PULL is ignored. If a pin input is disconnected and not driven externally it will
14 * just remain at zero/low.
15 * * Note a.2:
16 * PIN_CNF.DRIVE / drive strength is ignored
17 * It is not possible to connect two outputs together building a logical AND or OR
18 * * Note a.3:
19 * Reading OUTCLR & DIRCLR reads always 0
20 * * Note a.4: There is no modeling of system idle/off, and as such a DETECT raising edge from the
21 * GPIO will not cause the system to exit those states.
22 *
23 * This model has the following approximations:
24 * * Note b.1:
25 * If a DIR bit is cleared for a pin which was being driven as a high output,
26 * that pin will be lowered immediately (like if it was driven low)
27 * * Note b.2:
28 * All drives are instantaneous.
29 * * Note b.3:
30 * During pin reconfigurations, there can be spurious transitions in the pins outputs
31 * which may not correspond to how the real HW would behave
32 * * Note b.4:
33 * In real HW, after a write to LATCH, the DETECT event output to the GPIOTE is kept low for
34 * a few clocks, before being raised again (if it needs to), in the model the new pulse/raise
35 * is sent instantaneously to the GPIOTE
36 *
37 * 5340 notes:
38 * * Note 53.1: Unlike in real HW, the Net and App cores GPIO peripherals are mapped to different/separate
39 * simulated ports.
40 *
41 * * Note 53.2: MCUSEL is ignored at this point. (see point above)
42 *
43 * * Note 53.3: Like in real HW DETECTMODE & DETECTMODE_SEC control the generation of DETECT_SEC & DETEC_NONSEC,
44 * which are connected to GPIOTE0 (GPIOTESEC) and GPIOTE1 respectively.
45 * But, all pins sense output (be them secure or not) is used as input for *both*.
46 * Note: This only affects the app core GPIOs, the net core GPIOs do not have the DETECT_SEC signal
47 * connected to anything.
48 *
49 * 53 & 54 notes:
50 * * Note 534.1: Split security distinctions are ignored
51 * == there is no distinction for accesses from secure or non secure bus masters or the S/NS address ranges.
52 * Accessing either through the S or NS address range all registers are equally accessible.
53 *
54 * * Note 534.2: A possible secure/non secure pin configuration in the SPU is ignored
55 *
56 * 54L notes:
57 * * Note 54.1: PIN_CNF[n].CTRLSEL is ignored by now, but other peripherals can still take over a pin (irrespectively of .CTRLSEL)
58 * If another peripheral HW model has taken ownership of a pin, you will get a warning if you try to drive it through
59 * the GPIO registers. You will be able to read a pin input level even if another peripheral has control over it,
60 * while the pin input driver is enabled.
61 *
62 * * Note 54.2: As we do not check pins secure configuration, at this point both DETECT_SEC & DETEC_NONSEC are generated
63 * at the same time from all pins sense outputs
64 *
65 * * Note 54.3: Considerations regarding the LATCH register split security (different behavior depending on S/NS master access)
66 * are ignored (due to Note 534.1)
67 */
68
69 #include <stdint.h>
70 #include <stdbool.h>
71 #include <string.h>
72 #include "NHW_common_types.h"
73 #include "NHW_config.h"
74 #include "NHW_common_types.h"
75 #include "NHW_config.h"
76 #include "NHW_peri_types.h"
77 #include "NRF_GPIO.h"
78 #include "NRF_GPIOTE.h"
79 #include "bs_tracing.h"
80 #include "nsi_tasks.h"
81
82 NRF_GPIO_Type NRF_GPIO_regs[NHW_GPIO_TOTAL_INST];
83
84 struct gpio_status {
85 uint32_t IO_level; /* Actual levels in the pins */
86 uint32_t O_level;
87
88 uint32_t DETECT; /* Sense output / unlatched/non-sticky detect */
89 uint32_t LDETECT; /* Latched sense output */
90 bool DETECT_signal; /* Individual detect signal to the GPIOTE (for 5340 == DETECT_NSEC) */
91 bool DETECT_SEC_signal; /* Only used for 5340 */
92
93 uint32_t INPUT_mask; /* As a 32bit mask, PIN_CNF[*].INPUT (0: enabled; 1: disabled)*/
94 uint32_t SENSE_mask; /* As a 32bit mask, PIN_CNF[*].SENSE.en (1: enabled; 0: disabled)*/
95 uint32_t SENSE_inv; /* As a 32bit mask, PIN_CNF[*].SENSE.inv (1: inverted;0: not inverted) */
96
97 /*
98 * Is the output driven by another peripheral (1) or the GPIO directly (0).
99 * Note that we don't keep track of who "owns" a pin, only that somebody else does
100 */
101 uint32_t out_override;
102 /* Out value provided by other peripherals */
103 uint32_t external_OUT;
104
105 /* Is the pin input controlled by a peripheral(1) or the GPIO(0) */
106 uint32_t input_override;
107 /* If input_override, is the peripheral configuring the input buffer as connected (1) or disconnected (0) */
108 uint32_t input_override_connected;
109
110 /* Is "dir" controlled by a peripheral(1) or the GPIO(0) */
111 uint32_t dir_override;
112 /* If dir_override is set, is the peripheral configuring the output as connected (1) or disconnected (0) */
113 uint32_t dir_override_set;
114
115 /* Callbacks for peripherals to be informed of input changes */
116 nrf_gpio_input_callback_hw_t per_intoggle_callbacks[NHW_GPIO_MAX_PINS_PER_PORT];
117 void *per_intoggle_cb_data[NHW_GPIO_MAX_PINS_PER_PORT];
118
119 int nbr_pins;
120 int partner_GPIOTE;
121 int has_sense;
122 };
123
124 static struct gpio_status gpio_st[NHW_GPIO_TOTAL_INST];
125
126 /* Callbacks for test code to be informed of input/output changes: */
127 static nrf_gpio_input_callback_t test_intoggle_callback;
128 static nrf_gpio_input_callback_t test_outtoggle_callback;
129
130 /*
131 * Initialize the GPIOs model
132 */
nrf_gpio_init(void)133 static void nrf_gpio_init(void) {
134 memset(NRF_GPIO_regs, 0, sizeof(NRF_GPIO_regs));
135
136 int GPIO_n_ports_pins[NHW_GPIO_TOTAL_INST] = NHW_GPIO_NBR_PINS;
137 int GPIOTE_partners[NHW_GPIO_TOTAL_INST] = NHW_GPIO_PARTNER_GPIOTE;
138 int has_sense[NHW_GPIO_TOTAL_INST] = NHW_GPIO_HAS_PIN_SENSE;
139
140 for (int p = 0; p < NHW_GPIO_TOTAL_INST; p ++) {
141 for (int n = 0; n < GPIO_n_ports_pins[p]; n++) {
142 NRF_GPIO_regs[p].PIN_CNF[n] = 0x2; /* Disconnected out of reset */
143 }
144 gpio_st[p].INPUT_mask = UINT32_MAX; /* All disconnected out of reset */
145 gpio_st[p].nbr_pins = GPIO_n_ports_pins[p];
146 gpio_st[p].partner_GPIOTE = GPIOTE_partners[p];
147 gpio_st[p].has_sense = has_sense[p];
148 }
149
150 nrf_gpio_backend_init();
151 }
152
153 NSI_TASK(nrf_gpio_init, HW_INIT, 100);
154
nrf_gpio_get_number_pins_in_port(int port)155 unsigned int nrf_gpio_get_number_pins_in_port(int port) {
156 return gpio_st[port].nbr_pins;
157 }
158
159 static void nrf_gpio_eval_outputs(unsigned int port);
160 static void nrf_gpio_eval_inputs(unsigned int port);
161 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value);
162
163 /*
164 * Register a test callback to be called whenever a pin IN register changes
165 */
nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr)166 void nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr) {
167 test_intoggle_callback = fptr;
168 }
169
170 /*
171 * Register a test callback to be called whenever an *output* pin changes
172 */
nrf_gpio_test_register_out_callback(nrf_gpio_input_callback_t fptr)173 void nrf_gpio_test_register_out_callback(nrf_gpio_input_callback_t fptr) {
174 test_outtoggle_callback = fptr;
175 }
176
177 /*
178 * Change a pin input value
179 *
180 * Note: The pin must not be currently driven by the SOC, or you will get an error
181 *
182 * Inputs:
183 * * port: Which GPIO port
184 * * n: which pin in that GPIO port
185 * * value: true: high, false: low
186 */
nrf_gpio_test_change_pin_level(unsigned int port,unsigned int n,bool value)187 void nrf_gpio_test_change_pin_level(unsigned int port, unsigned int n, bool value) {
188 nrf_gpio_eval_input(port, n, value);
189 }
190
191 /*
192 * Get a pin level
193 *
194 * Inputs:
195 * * port: Which GPIO port
196 * * n: which pin in that GPIO port
197 * Return: true (high), false (low)
198 */
nrf_gpio_get_pin_level(unsigned int port,unsigned int n)199 bool nrf_gpio_get_pin_level(unsigned int port, unsigned int n) {
200 return (gpio_st[port].IO_level >> n) & 0x1;
201 }
202
203 #define CHECK_PIN_EXISTS(port, n, dir) \
204 if (port >= NHW_GPIO_TOTAL_INST || (uint)n >= (uint)gpio_st[port].nbr_pins) { \
205 bs_trace_error_time_line("%s: Error, attempted to toggle "dir" for nonexistent " \
206 "GPIO port %i, pin %i\n", \
207 __func__, port, n); \
208 }
209
get_enabled_inputs(unsigned int port)210 static inline uint32_t get_enabled_inputs(unsigned int port){
211 struct gpio_status *st = &gpio_st[port];
212 return (~st->input_override & ~st->INPUT_mask)
213 | (st->input_override & st->input_override_connected);
214 }
215
get_dir(unsigned int port)216 static inline uint32_t get_dir(unsigned int port){
217 struct gpio_status *st = &gpio_st[port];
218 return (~st->dir_override & NRF_GPIO_regs[port].DIR)
219 | (st->dir_override & st->dir_override_set);
220 }
221
222 /*
223 * Function with which another peripheral can claim configuration control of a pin.
224 *
225 * Inputs:
226 * * port: Which GPIO port
227 * * n : which pin in that GPIO port
228 * * override_output:
229 * * -1 : Don't change
230 * * 0 : Leave for GPIO control (GPIO OUT register sets the output value)
231 * * 1 : Take external control of pin output value (peripheral sets the output value
232 * with nrf_gpio_peri_change_output() )
233 * * override_input:
234 * * -1 : Don't change
235 * * 0 : Leave input to be controlled by the GPIO module
236 * * 2 : Take external control of input, and disconnect
237 * * 3 : Take external control of input, and connect
238 * * override_dir:
239 * * -1 : Don't change
240 * * 0 : Leave DIR to be controlled by the GPIO module
241 * * 2 : Take external control of DIR, and disconnect (not driving output)
242 * * 3 : Take external control of DIR, and connect (driving output)
243 * * fptr: Function to be called whenever that input toggles (if enabled).
244 * Set to NULL if not needed.
245 * * new_level:
246 * * -1: Don't change
247 * * 0: low
248 * * 1: high
249 */
nrf_gpio_peri_pin_control(unsigned int port,unsigned int n,int override_output,int override_input,int override_dir,nrf_gpio_input_callback_hw_t fptr,void * fptr_data,int new_level)250 void nrf_gpio_peri_pin_control(unsigned int port, unsigned int n,
251 int override_output, int override_input, int override_dir,
252 nrf_gpio_input_callback_hw_t fptr, void *fptr_data, int new_level) {
253
254 struct gpio_status *st = &gpio_st[port];
255
256 if (port >= NHW_GPIO_TOTAL_INST || (int)n >= st->nbr_pins) { /* LCOV_EXCL_BR_LINE */
257 bs_trace_error_time_line("Programming error\n"); /* LCOV_EXCL_LINE */
258 }
259
260 uint32_t mask = 1<<n;
261 bool need_output_eval = false;
262 bool need_input_eval = false;
263
264 if (override_output >= 0) {
265 st->out_override &= ~mask;
266 st->out_override |= (uint32_t)(override_output?1:0) << n;
267 need_output_eval = true;
268 }
269 if (override_input >= 0) {
270 st->input_override &= ~mask;
271 st->input_override |= (uint32_t)(override_input?1:0) << n;
272
273 st->input_override_connected &= ~mask;
274 st->input_override_connected |= (uint32_t)(override_input==3?1:0) << n;
275
276 need_input_eval = true;
277 }
278 if (override_dir >= 0) {
279 st->dir_override &= ~mask;
280 st->dir_override |= (uint32_t)(override_dir?1:0) << n;
281
282 st->dir_override_set &= ~mask;
283 st->dir_override_set |= (uint32_t)(override_dir==3?1:0) << n;
284
285 need_output_eval = true;
286 }
287 st->per_intoggle_callbacks[n] = fptr;
288 st->per_intoggle_cb_data[n] = fptr_data;
289 if (new_level >= 0) {
290 st->external_OUT &= ~((uint32_t)1 << n);
291 st->external_OUT |= (uint32_t)(new_level?1:0) << n;
292 need_output_eval = true;
293 }
294
295 if (need_output_eval) {
296 nrf_gpio_eval_outputs(port);
297 }
298 if (need_input_eval) {
299 nrf_gpio_eval_inputs(port);
300 }
301 }
302
303 /*
304 * A peripheral wants to toggle a GPIO output to a new value <value>.
305 * Note: The value may be the same as it was, in which case nothing will happen.
306 *
307 * Inputs:
308 * * port is the GPIO port
309 * * n is the pin number inside that GPIO port (0..31)
310 * * value is the new output value high (true) or low (false)
311 */
nrf_gpio_peri_change_output(unsigned int port,unsigned int n,bool value)312 void nrf_gpio_peri_change_output(unsigned int port, unsigned int n, bool value)
313 {
314 CHECK_PIN_EXISTS(port, n, "output"); /* LCOV_EXCL_BR_LINE */
315
316 struct gpio_status *st = &gpio_st[port];
317
318 if (((st->out_override >> n) & 0x1) != 1) { /* LCOV_EXCL_START */
319 bs_trace_error_time_line("%s: Programming error, a peripheral is trying to toggle "
320 "a GPIO output it does not own, GPIO port %i, pin %i\n",
321 __func__, port, n);
322 }
323
324 if (((get_dir(port) >> n) & 0x1) != 1) {
325 bs_trace_warning_time_line("%s: A peripheral is trying to toggle "
326 "a GPIO output but the output is disabled, "
327 "GPIO port %i, pin %i\n",
328 __func__, port, n);
329 } /* LCOV_EXCL_STOP */
330
331 st->external_OUT &= ~((uint32_t)1 << n);
332 st->external_OUT |= (uint32_t)value << n;
333 nrf_gpio_eval_outputs(port);
334 }
335
nrf_gpio_update_detect_signal(unsigned int port)336 static void nrf_gpio_update_detect_signal(unsigned int port) {
337 struct gpio_status *st = &gpio_st[port];
338
339 if (NRF_GPIO_regs[port].DETECTMODE == 0){ //gpio.detect signal from not latched detect
340 st->DETECT_signal = (st->DETECT != 0);
341 } else {//gpio.detect signal from latched detect
342 st->DETECT_signal = (st->LDETECT != 0);
343 }
344
345 #if defined(NRF5340)
346 if (NRF_GPIO_regs[port].DETECTMODE_SEC == 0){
347 st->DETECT_SEC_signal = (st->DETECT != 0);
348 } else {//gpio.detect signal from latched detect
349 st->DETECT_SEC_signal = (st->LDETECT != 0);
350 }
351 #endif
352 }
353
354 /*
355 * Evaluate sense output (after a change of input or configuration)
356 */
nrf_gpio_eval_sense(unsigned int port)357 static void nrf_gpio_eval_sense(unsigned int port){
358 struct gpio_status *st = &gpio_st[port];
359
360 if (!st->has_sense) {
361 return;
362 }
363
364 /* Note SENSE_dir inverts the output */
365 st->DETECT = (NRF_GPIO_regs[port].IN ^ st->SENSE_inv) & st->SENSE_mask;
366 st->LDETECT |= st->DETECT;
367 NRF_GPIO_regs[port].LATCH = st->LDETECT;
368
369 bool old_DETECT_signal = st->DETECT_signal;
370 #if defined(NRF5340)
371 bool old_DETECT_SEC_signal = st->DETECT_SEC_signal;
372 #endif
373 nrf_gpio_update_detect_signal(port);
374
375 if ((st->DETECT_signal == true) && (old_DETECT_signal==false) && (st->partner_GPIOTE>=0)) {
376 nrf_gpiote_port_detect_raise(st->partner_GPIOTE, port);
377 }
378
379 #if defined(NRF5340)
380 if ((port == NHW_GPIO_APP_P0) || (port == NHW_GPIO_APP_P1)) {
381 if ((st->DETECT_SEC_signal == true) && (old_DETECT_SEC_signal==false)) {
382 nrf_gpiote_port_detect_raise(NHW_GPIOTE_APP0, port);
383 }
384 }
385 #endif
386 }
387
388 /*
389 * Return the level of the DETECT output signal for a GPIO instance
390 *
391 * input: port: The GPIO instance number
392 */
nrf_gpio_get_detect_level(unsigned int port)393 bool nrf_gpio_get_detect_level(unsigned int port){
394 return gpio_st[port].DETECT_signal;
395 }
396
397 /*
398 * Get the level of the IN signal for GPIO <port> pin <n>
399 */
nrf_gpio_get_IN(unsigned int port,unsigned int n)400 bool nrf_gpio_get_IN(unsigned int port, unsigned int n) {
401 return (NRF_GPIO_regs[port].IN >> n) & 0x1;
402 }
403
404 /*
405 * The input has changed and the driver is connected,
406 * notify as necessary
407 */
nrf_gpio_input_change_sideeffects(unsigned int port,unsigned int n)408 static void nrf_gpio_input_change_sideeffects(unsigned int port, unsigned int n)
409 {
410 struct gpio_status *st = &gpio_st[port];
411 bool level = nrf_gpio_get_IN(port,n);
412
413 if (st->per_intoggle_callbacks[n] != NULL) {
414 st->per_intoggle_callbacks[n](port, n, level, st->per_intoggle_cb_data[n]);
415 }
416 if (test_intoggle_callback != NULL) {
417 test_intoggle_callback(port, n, level);
418 }
419 }
420
421 /*
422 * An input pin has toggled or the input configuration has changed,
423 * propagate it
424 */
nrf_gpio_eval_inputs(unsigned int port)425 static void nrf_gpio_eval_inputs(unsigned int port)
426 {
427 uint32_t new_IN = gpio_st[port].IO_level & get_enabled_inputs(port);
428
429 uint32_t diff = new_IN ^ NRF_GPIO_regs[port].IN;
430
431 NRF_GPIO_regs[port].IN = new_IN;
432
433 for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
434 nrf_gpio_input_change_sideeffects(port, n);
435 diff &= ~(1 << n);
436 }
437
438 nrf_gpio_eval_sense(port);
439 }
440
441 /*
442 * An input *may* be changing to a new value <value>.
443 * Note: The value may be the same as it was, in which case nothing will happen.
444 *
445 * This function is meant to be called from something which drives the input
446 * **externally**
447 *
448 * Inputs:
449 * * port is the GPIO port
450 * * n is the pin number inside that GPIO port (0..31)
451 * * value: is the input high (true) or low (false)
452 */
nrf_gpio_eval_input(unsigned int port,unsigned int n,bool value)453 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value)
454 {
455 CHECK_PIN_EXISTS(port, n, "input"); /* LCOV_EXCL_BR_LINE */
456
457 uint32_t dir = get_dir(port);
458
459 if ((dir >> n) & 0x1) { /* LCOV_EXCL_START */
460 bs_trace_warning_time_line("%s: Attempted to drive externally a pin which is "
461 "currently being driven by the SOC. It will be ignored."
462 "GPIO port %i, pin %i\n",
463 __func__, port, n);
464 return;
465 } /* LCOV_EXCL_STOP */
466
467 int diff = ((gpio_st[port].IO_level >> n) & 0x1) ^ (uint32_t)value;
468
469 if (diff == 0) {
470 /* No toggle */
471 return;
472 }
473
474 gpio_st[port].IO_level ^= (uint32_t)1 << n;
475
476 nrf_gpio_eval_inputs(port);
477 }
478
479 /*
480 * The output is being changed, propagate it as necessary and/or record it.
481 */
nrf_gpio_output_change_sideeffects(unsigned int port,unsigned int n,bool value)482 static void nrf_gpio_output_change_sideeffects(unsigned int port,unsigned int n, bool value)
483 {
484 nrf_gpio_backend_write_output_change(port, n, value);
485 if (test_outtoggle_callback != NULL) {
486 test_outtoggle_callback(port, n, value);
487 }
488 nrf_gpio_backend_short_propagate(port, n, value);
489 }
490
491 /*
492 * Reevaluate outputs after a configuration or OUT/external_OUT change
493 */
nrf_gpio_eval_outputs(unsigned int port)494 static void nrf_gpio_eval_outputs(unsigned int port)
495 {
496 /* Actual level in the pin, but only of the bits driven by output: */
497 struct gpio_status *st = &gpio_st[port];
498
499 uint32_t dir = get_dir(port); /* Which pins are driven by output */
500
501 uint32_t out = (~st->out_override & NRF_GPIO_regs[port].OUT)
502 | (st->out_override & st->external_OUT);
503
504 uint32_t new_output = dir & out;
505
506 uint32_t diff = new_output ^ st->O_level;
507
508 if (diff == 0) {
509 return;
510 }
511
512 st->O_level = new_output;
513
514 st->IO_level &= ~dir;
515 st->IO_level |= st->O_level;
516
517 for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
518 nrf_gpio_output_change_sideeffects(port, n, (new_output >> n) & 0x1);
519 diff &= ~(1 << n);
520 }
521
522 /* Inputs may be connected to pins driven by outputs, let's check */
523 nrf_gpio_eval_inputs(port);
524 }
525
526
527 /*
528 * Register write side-effecting functions:
529 */
530
nrf_gpio_regw_sideeffects_OUT(unsigned int port)531 void nrf_gpio_regw_sideeffects_OUT(unsigned int port) {
532 nrf_gpio_eval_outputs(port);
533 }
534
nrf_gpio_regw_sideeffects_OUTSET(unsigned int port)535 void nrf_gpio_regw_sideeffects_OUTSET(unsigned int port) {
536 if (NRF_GPIO_regs[port].OUTSET) {
537 NRF_GPIO_regs[port].OUT |= NRF_GPIO_regs[port].OUTSET;
538 nrf_gpio_eval_outputs(port);
539 }
540 NRF_GPIO_regs[port].OUTSET = NRF_GPIO_regs[port].OUT;
541 }
542
nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port)543 void nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port) {
544 if (NRF_GPIO_regs[port].OUTCLR) {
545 NRF_GPIO_regs[port].OUT &= ~NRF_GPIO_regs[port].OUTCLR;
546 NRF_GPIO_regs[port].OUTCLR = 0;
547 nrf_gpio_eval_outputs(port);
548 }
549 }
550
nrf_gpio_regw_sideeffects_DIR(unsigned int port)551 void nrf_gpio_regw_sideeffects_DIR(unsigned int port) {
552 /* Mirror change into PIN_CNF[*].DIR */
553 for (int n = 0; n < gpio_st[port].nbr_pins; n++ ) {
554 NRF_GPIO_regs[port].PIN_CNF[n] &= ~GPIO_PIN_CNF_DIR_Msk;
555 NRF_GPIO_regs[port].PIN_CNF[n] |= (NRF_GPIO_regs[port].DIR >> n) & 0x1;
556 }
557
558 nrf_gpio_eval_outputs(port);
559 }
560
nrf_gpio_regw_sideeffects_DIRSET(unsigned int port)561 void nrf_gpio_regw_sideeffects_DIRSET(unsigned int port) {
562 if (NRF_GPIO_regs[port].DIRSET) {
563 NRF_GPIO_regs[port].DIR |= NRF_GPIO_regs[port].DIRSET;
564 nrf_gpio_regw_sideeffects_DIR(port);
565 }
566 NRF_GPIO_regs[port].DIRSET = NRF_GPIO_regs[port].DIR;
567 }
568
nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port)569 void nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port) {
570 if (NRF_GPIO_regs[port].DIRCLR) {
571 NRF_GPIO_regs[port].DIR &= ~NRF_GPIO_regs[port].DIRCLR;
572 NRF_GPIO_regs[port].DIRCLR = 0;
573 nrf_gpio_regw_sideeffects_DIR(port);
574 }
575 }
576
nrf_gpio_regw_sideeffects_LATCH(unsigned int port)577 void nrf_gpio_regw_sideeffects_LATCH(unsigned int port) {
578 struct gpio_status *st = &gpio_st[port];
579
580 if (!st->has_sense) {
581 return;
582 }
583
584 /* LATCH contains what SW wrote: */
585 uint32_t sw_input = NRF_GPIO_regs[port].LATCH;
586
587 /* Whatever bits SW set to 1, it is trying to clear: */
588 st->LDETECT &= ~sw_input;
589
590 /* But where the sense output is high, the bits are kept high: */
591 st->LDETECT |= st->DETECT;
592
593 NRF_GPIO_regs[port].LATCH = st->LDETECT;
594
595 nrf_gpio_update_detect_signal(port);
596
597 /*
598 * Note the text from the spec:
599 * If one or more bits in the LATCH register are '1' after the CPU has
600 * performed a clear operation on the LATCH registers, a rising edge will be generated
601 * on the LDETECT signal.
602 * "the CPU has performed a clear operation" == after writing LATCH with any bit to 1
603 */
604 if (sw_input != 0 && st->LDETECT != 0 && NRF_GPIO_regs[port].DETECTMODE == 1 && (st->partner_GPIOTE>=0)) {
605 nrf_gpiote_port_detect_raise(st->partner_GPIOTE, port);
606 }
607
608 #if defined(NRF5340)
609 if ((port == NHW_GPIO_APP_P0) || (port == NHW_GPIO_APP_P1)) {
610 if ((sw_input != 0) && (st->LDETECT != 0) && (NRF_GPIO_regs[port].DETECTMODE_SEC == 1)) {
611 nrf_gpiote_port_detect_raise(NHW_GPIOTE_APP0, port);
612 }
613 }
614 #endif
615 }
616
617 /* For 5340: To be called for either DETECTMODE or DETECTMODE_SEC */
nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port)618 void nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port) {
619 nrf_gpio_eval_sense(port);
620 }
621
nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port,unsigned int n)622 void nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port, unsigned int n) {
623
624 struct gpio_status *st = &gpio_st[port];
625
626 bool need_output_eval = false;
627 bool need_input_eval = false;
628 bool need_sense_eval = false;
629
630 uint dir = NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DIR_Msk;
631
632 if (dir != ((NRF_GPIO_regs[port].DIR >> n) & 0x1)) {
633 NRF_GPIO_regs[port].DIR ^= 1 << n;
634 need_output_eval = true;
635 }
636
637 /* Note: DRIVE and PULL are not yet used in this model
638 int pull = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_PULL_Msk)
639 >> GPIO_PIN_CNF_PULL_Pos;
640
641 int drive = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DRIVE_Msk)
642 >> GPIO_PIN_CNF_DRIVE_Pos;
643 */
644
645 uint input = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_INPUT_Msk)
646 >> GPIO_PIN_CNF_INPUT_Pos;
647 if (input != ((st->INPUT_mask >> n) & 0x1)) {
648 st->INPUT_mask ^= 1 << n;
649 need_input_eval = true;
650 }
651
652 int sense = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_SENSE_Msk)
653 >> GPIO_PIN_CNF_SENSE_Pos;
654 if (((sense >> 1) & 0x1) != ((st->SENSE_mask >> n) & 0x1)) {
655 st->SENSE_mask ^= 1 << n;
656 need_sense_eval = true;
657 }
658 if ((sense & 0x1) != ((st->SENSE_inv >> n) & 0x1)) {
659 st->SENSE_inv ^= 1 << n;
660 need_sense_eval = true;
661 }
662
663 if (need_output_eval) {
664 nrf_gpio_eval_outputs(port);
665 }
666 if (need_input_eval) {
667 nrf_gpio_eval_inputs(port);
668 }
669 if (need_sense_eval) {
670 nrf_gpio_eval_sense(port);
671 }
672 }
673