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