1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * GPIOTE - GPIO tasks and events
9  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/gpiote.html?cp=5_1_0_5_8
10  *
11  * This model has the following limitations:
12  *  * INTENCLR will always read as 0
13  *  * Unlike in real HW, tasks cannot occur simultaneously, they always happen in some sequence
14  *    so task priority is not accounted for
15  */
16 
17 #include <stdint.h>
18 #include <string.h>
19 #include "NHW_common_types.h"
20 #include "NHW_config.h"
21 #include "NHW_peri_types.h"
22 #include "NRF_GPIOTE.h"
23 #include "NRF_GPIO.h"
24 #include "NRF_PPI.h"
25 #include "irq_ctrl.h"
26 #include "bs_tracing.h"
27 #include "nsi_tasks.h"
28 
29 NRF_GPIOTE_Type NRF_GPIOTE_regs = {0};
30 /* Mapping of peripheral instance to {int controller instance, int number} */
31 static struct nhw_irq_mapping nhw_gpiote_irq_map[NHW_GPIOTE_TOTAL_INST] = NHW_GPIOTE_INT_MAP;
32 
33 static uint32_t GPIOTE_ITEN;
34 static bool gpiote_int_line; /* Is the GPIOTE currently driving its interrupt line high */
35 
36 /* For each GPIO channel, its status */
37 static struct gpiote_ch_status_t {
38 	uint8_t mode;
39 	uint8_t port;  /* GPIO instance */
40 	uint8_t pin;   /* GPIO pin in that instance (psel) */
41 	uint8_t polarity; /* Content of the CONFIG[].polarity field */
42 	/* Level at which the GPIOTE has been driving this pin,
43 	 * or which it has been getting from the GPIO
44 	 * true = high, false = low */
45 	bool level;
46 } gpiote_ch_status[N_GPIOTE_CHANNELS];
47 
48 /**
49  * Initialize the GPIOs model
50  */
nrf_gpiote_init(void)51 static void nrf_gpiote_init(void) {
52 	memset(&NRF_GPIOTE_regs, 0, sizeof(NRF_GPIOTE_regs));
53 }
54 
55 NSI_TASK(nrf_gpiote_init, HW_INIT, 100);
56 
57 static void nrf_gpiote_events_port(void);
58 
59 /*
60  * API to the GPIO components, in which they can signal that their DETECT output signal
61  * has been raised.
62  *
63  * We do not keep track in the GPIOTE about the signal being lowered, as the GPIOTE
64  * only reacts to raising edges.
65  * Therefore it is the responsibility of the GPIO models to call this if and only
66  * if there is a raising edge on their DETECT output signal.
67  */
nrf_gpiote_port_event_raise(unsigned int port)68 void nrf_gpiote_port_event_raise(unsigned int port) {
69 	(void)port; /* unused */
70 	nrf_gpiote_events_port();
71 }
72 
nrf_gpiote_TASKS_OUT(unsigned int n)73 void nrf_gpiote_TASKS_OUT(unsigned int n) {
74 	struct gpiote_ch_status_t *sc = &gpiote_ch_status[n];
75 	if (sc->mode != GPIOTE_CONFIG_MODE_Task) {
76 		return;
77 	}
78 	switch (sc->polarity) {
79 	case GPIOTE_CONFIG_POLARITY_None:
80 		return;
81 	case GPIOTE_CONFIG_POLARITY_LoToHi:
82 		sc->level = true;
83 		break;
84 	case GPIOTE_CONFIG_POLARITY_HiToLo:
85 		sc->level = false;
86 		break;
87 	case GPIOTE_CONFIG_POLARITY_Toggle:
88 		sc->level = !sc->level;
89 		break;
90 	default:	/* LCOV_EXCL_START */
91 		bs_trace_error_time_line("%s: Missconfigured CONFIG.CONFIG[%i]\n", n);
92 		break;
93 	}		/* LCOV_EXCL_STOP */
94 	/* We may be calling the GPIO even if we haven't changed it, but that is fine */
95 	nrf_gpio_peri_change_output(sc->port, sc->pin, sc->level);
96 }
97 
nrf_gpiote_TASKS_SET(unsigned int n)98 void nrf_gpiote_TASKS_SET(unsigned int n) {
99 	struct gpiote_ch_status_t *sc = &gpiote_ch_status[n];
100 	if (sc->mode != GPIOTE_CONFIG_MODE_Task) {
101 		return;
102 	}
103 	sc->level = true;
104 	/* We may be calling the GPIO even if we haven't changed it, but that is fine */
105 	nrf_gpio_peri_change_output(sc->port, sc->pin, sc->level);
106 }
107 
nrf_gpiote_TASKS_CLR(unsigned int n)108 void nrf_gpiote_TASKS_CLR(unsigned int n) {
109 	struct gpiote_ch_status_t *sc = &gpiote_ch_status[n];
110 	if (sc->mode != GPIOTE_CONFIG_MODE_Task) {
111 		return;
112 	}
113 	sc->level = false;
114 	/* We may be calling the GPIO even if we haven't changed it, but that is fine */
115 	nrf_gpio_peri_change_output(sc->port, sc->pin, sc->level);
116 }
117 
nrf_gpiote_eval_interrupt(void)118 static void nrf_gpiote_eval_interrupt(void) {
119 	bool new_int_line = false;
120 	int mask;
121 
122 	for (int i = 0; i < N_GPIOTE_CHANNELS; i++) {
123 		mask = (GPIOTE_ITEN >> i) & 0x1;
124 		if (NRF_GPIOTE_regs.EVENTS_IN[i] && mask) {
125 			new_int_line = true;
126 			break; /* No need to check more */
127 		}
128 	}
129 	mask = (GPIOTE_ITEN & GPIOTE_INTENCLR_PORT_Msk) >> GPIOTE_INTENCLR_PORT_Pos;
130 	if (NRF_GPIOTE_regs.EVENTS_PORT && mask) {
131 		new_int_line = true;
132 	}
133 
134 	int inst = 0;
135 	if (gpiote_int_line == false && new_int_line == true) {
136 		gpiote_int_line = true;
137 		hw_irq_ctrl_raise_level_irq_line(nhw_gpiote_irq_map[inst].cntl_inst,
138 				nhw_gpiote_irq_map[inst].int_nbr);
139 	} else if (gpiote_int_line == true && new_int_line == false) {
140 		gpiote_int_line = false;
141 		hw_irq_ctrl_lower_level_irq_line(nhw_gpiote_irq_map[inst].cntl_inst,
142 				nhw_gpiote_irq_map[inst].int_nbr);
143 	}
144 }
145 
nrf_gpiote_events_in(unsigned int n)146 static void nrf_gpiote_events_in(unsigned int n) {
147 	NRF_GPIOTE_regs.EVENTS_IN[n] = 1;
148 	nrf_gpiote_eval_interrupt();
149 	nrf_ppi_event(GPIOTE_EVENTS_IN_0 + n);
150 }
151 
nrf_gpiote_events_port(void)152 static void nrf_gpiote_events_port(void) {
153 	NRF_GPIOTE_regs.EVENTS_PORT = 1;
154 	nrf_gpiote_eval_interrupt();
155 	nrf_ppi_event(GPIOTE_EVENTS_PORT);
156 }
157 
158 /*
159  * Function to be called (by the GPIO model) when a pin changes
160  * for which an EVENTS_IN is registered
161  */
nrf_gpiote_input_change_ntf(unsigned int port,unsigned int n,bool value)162 static void nrf_gpiote_input_change_ntf(unsigned int port, unsigned int n, bool value)
163 {
164 	int i;
165 	struct gpiote_ch_status_t *sc;
166 	bool generate_event = false;
167 
168 	/* Find event we are connecting this pin to */
169 	for (i = 0; i < N_GPIOTE_CHANNELS; i++) {
170 		sc = &gpiote_ch_status[i];
171 		if (sc->port == port && sc->pin == n) {
172 			break;
173 		}
174 	}
175 	if (i == N_GPIOTE_CHANNELS) { /* LCOV_EXCL_START */
176 		bs_trace_error_time_line("%s: Programming error, received notification from not "
177 					 "connected GPIO port.pin:%i.%i\n", port, n);
178 	} /* LCOV_EXCL_STOP */
179 
180 	switch (sc->polarity) {
181 	case GPIOTE_CONFIG_POLARITY_None:
182 		return;
183 	case GPIOTE_CONFIG_POLARITY_LoToHi:
184 		if ((sc->level == false) && (value == true)) {
185 			generate_event = true;
186 		}
187 		break;
188 	case GPIOTE_CONFIG_POLARITY_HiToLo:
189 		if ((sc->level == true) && (value == false)) {
190 			generate_event = true;
191 		}
192 		break;
193 	case GPIOTE_CONFIG_POLARITY_Toggle:
194 		if (sc->level != value) {
195 			generate_event = true;
196 		}
197 		break;
198 	default:	/* LCOV_EXCL_START */
199 		bs_trace_error_time_line("%s: Missconfigured CONFIG.CONFIG[%i]\n", n);
200 		break;
201 	}		/* LCOV_EXCL_STOP */
202 	sc->level = value;
203 
204 	if (generate_event) {
205 		nrf_gpiote_events_in(i);
206 	}
207 }
208 
209 /*
210  * Register write side-effecting functions
211  */
212 
nrf_gpiote_regw_sideeffects_TASKS_OUT(unsigned int n)213 void nrf_gpiote_regw_sideeffects_TASKS_OUT(unsigned int n) {
214 	if (NRF_GPIOTE_regs.TASKS_OUT[n]) {
215 		NRF_GPIOTE_regs.TASKS_OUT[n] = 0;
216 		nrf_gpiote_TASKS_OUT(n);
217 	}
218 }
219 
nrf_gpiote_regw_sideeffects_TASKS_SET(unsigned int n)220 void nrf_gpiote_regw_sideeffects_TASKS_SET(unsigned int n) {
221 	if (NRF_GPIOTE_regs.TASKS_SET[n]) {
222 		NRF_GPIOTE_regs.TASKS_SET[n] = 0;
223 		nrf_gpiote_TASKS_SET(n);
224 	}
225 }
226 
nrf_gpiote_regw_sideeffects_TASKS_CLR(unsigned int n)227 void nrf_gpiote_regw_sideeffects_TASKS_CLR(unsigned int n) {
228 	if (NRF_GPIOTE_regs.TASKS_CLR[n]) {
229 		NRF_GPIOTE_regs.TASKS_CLR[n] = 0;
230 		nrf_gpiote_TASKS_CLR(n);
231 	}
232 }
233 
nrf_gpiote_regw_sideeffects_EVENTS_IN(unsigned int n)234 void nrf_gpiote_regw_sideeffects_EVENTS_IN(unsigned int n) {
235 	nrf_gpiote_eval_interrupt();
236 }
237 
nrf_gpiote_regw_sideeffects_EVENTS_PORT(void)238 void nrf_gpiote_regw_sideeffects_EVENTS_PORT(void) {
239 	nrf_gpiote_eval_interrupt();
240 
241 }
242 
nrf_gpiote_regw_sideeffects_INTENSET(void)243 void nrf_gpiote_regw_sideeffects_INTENSET(void) {
244 	if (NRF_GPIOTE_regs.INTENSET) {
245 		GPIOTE_ITEN |= NRF_GPIOTE_regs.INTENSET;
246 		NRF_GPIOTE_regs.INTENSET = GPIOTE_ITEN;
247 		nrf_gpiote_eval_interrupt();
248 	}
249 }
250 
nrf_gpiote_regw_sideeffects_INTENCLR(void)251 void nrf_gpiote_regw_sideeffects_INTENCLR(void) {
252 	if (NRF_GPIOTE_regs.INTENCLR) {
253 		GPIOTE_ITEN &= ~NRF_GPIOTE_regs.INTENCLR;
254 		NRF_GPIOTE_regs.INTENCLR = 0;
255 		nrf_gpiote_eval_interrupt();
256 	}
257 }
258 
nrf_gpiote_regw_sideeffects_CONFIG(unsigned int n)259 void nrf_gpiote_regw_sideeffects_CONFIG(unsigned int n) {
260 	struct gpiote_ch_status_t *sc = &gpiote_ch_status[n];
261 	unsigned int mode = NRF_GPIOTE_regs.CONFIG[n] & GPIOTE_CONFIG_MODE_Msk;
262 	unsigned int pin = (NRF_GPIOTE_regs.CONFIG[n] & GPIOTE_CONFIG_PSEL_Msk)
263 				>>GPIOTE_CONFIG_PSEL_Pos;
264 	unsigned int port = (NRF_GPIOTE_regs.CONFIG[n] & GPIOTE_CONFIG_PORT_Msk)
265 				>>GPIOTE_CONFIG_PORT_Pos;
266 	unsigned int polarity = (NRF_GPIOTE_regs.CONFIG[n] & GPIOTE_CONFIG_POLARITY_Msk)
267 				>>GPIOTE_CONFIG_POLARITY_Pos;
268 	unsigned int outinit = (NRF_GPIOTE_regs.CONFIG[n] & GPIOTE_CONFIG_OUTINIT_Msk)
269 				>>GPIOTE_CONFIG_OUTINIT_Pos;
270 
271 	if ((port != sc->port) || (pin != sc->pin)
272 	    || (mode == GPIOTE_CONFIG_MODE_Disabled  && sc->mode != GPIOTE_CONFIG_MODE_Disabled)) {
273 		/* Disconnect the old GPIO pin from the GPIOTE */
274 		nrf_gpio_peri_pin_control(sc->port, sc->pin, 0, 0, 0, NULL, -1);
275 	}
276 
277 	sc->mode = mode;
278 	sc->pin = pin;
279 	sc->port = port;
280 	sc->polarity = polarity;
281 
282 	if (mode == GPIOTE_CONFIG_MODE_Event) {
283 		sc->level = nrf_gpio_get_pin_level(port, pin);
284 		nrf_gpio_peri_pin_control(port, pin, 1, 3, 2, nrf_gpiote_input_change_ntf, -1);
285 	} else if (mode == GPIOTE_CONFIG_MODE_Task) {
286 		sc->level = outinit;
287 		nrf_gpio_peri_pin_control(port, pin, 1, 2, 3, NULL, outinit);
288 	} else if (mode != GPIOTE_CONFIG_MODE_Disabled) { /* LCOV_EXCL_START */
289 		bs_trace_error_time_line("%s: GPIOTE.CONFIG[%u].mode configured to an illegal "
290 					 "value(%u)\n", __func__, n, mode);
291 	} /* LCOV_EXCL_STOP */
292 }
293 
294 /*
295  * Trampolines to automatically call from the PPI
296  */
297 /* Generated with:
298 #! /usr/bin/env python3
299 #GPIOTE.c
300 for task in {"OUT","SET","CLR"}:
301     for i in range(0,8):
302        print("void nrf_gpiote_TASKS_%s_%i(void){ nrf_gpiote_TASKS_%s(%i); }"%(task,i,task,i))
303 #GPIOTE.h
304 for task in {"OUT","SET","CLR"}:
305     for i in range(0,8):
306        print("void nrf_gpiote_TASKS_%s_%i(void);"%(task,i))
307 */
nrf_gpiote_TASKS_SET_0(void)308 void nrf_gpiote_TASKS_SET_0(void){ nrf_gpiote_TASKS_SET(0); }
nrf_gpiote_TASKS_SET_1(void)309 void nrf_gpiote_TASKS_SET_1(void){ nrf_gpiote_TASKS_SET(1); }
nrf_gpiote_TASKS_SET_2(void)310 void nrf_gpiote_TASKS_SET_2(void){ nrf_gpiote_TASKS_SET(2); }
nrf_gpiote_TASKS_SET_3(void)311 void nrf_gpiote_TASKS_SET_3(void){ nrf_gpiote_TASKS_SET(3); }
nrf_gpiote_TASKS_SET_4(void)312 void nrf_gpiote_TASKS_SET_4(void){ nrf_gpiote_TASKS_SET(4); }
nrf_gpiote_TASKS_SET_5(void)313 void nrf_gpiote_TASKS_SET_5(void){ nrf_gpiote_TASKS_SET(5); }
nrf_gpiote_TASKS_SET_6(void)314 void nrf_gpiote_TASKS_SET_6(void){ nrf_gpiote_TASKS_SET(6); }
nrf_gpiote_TASKS_SET_7(void)315 void nrf_gpiote_TASKS_SET_7(void){ nrf_gpiote_TASKS_SET(7); }
nrf_gpiote_TASKS_CLR_0(void)316 void nrf_gpiote_TASKS_CLR_0(void){ nrf_gpiote_TASKS_CLR(0); }
nrf_gpiote_TASKS_CLR_1(void)317 void nrf_gpiote_TASKS_CLR_1(void){ nrf_gpiote_TASKS_CLR(1); }
nrf_gpiote_TASKS_CLR_2(void)318 void nrf_gpiote_TASKS_CLR_2(void){ nrf_gpiote_TASKS_CLR(2); }
nrf_gpiote_TASKS_CLR_3(void)319 void nrf_gpiote_TASKS_CLR_3(void){ nrf_gpiote_TASKS_CLR(3); }
nrf_gpiote_TASKS_CLR_4(void)320 void nrf_gpiote_TASKS_CLR_4(void){ nrf_gpiote_TASKS_CLR(4); }
nrf_gpiote_TASKS_CLR_5(void)321 void nrf_gpiote_TASKS_CLR_5(void){ nrf_gpiote_TASKS_CLR(5); }
nrf_gpiote_TASKS_CLR_6(void)322 void nrf_gpiote_TASKS_CLR_6(void){ nrf_gpiote_TASKS_CLR(6); }
nrf_gpiote_TASKS_CLR_7(void)323 void nrf_gpiote_TASKS_CLR_7(void){ nrf_gpiote_TASKS_CLR(7); }
nrf_gpiote_TASKS_OUT_0(void)324 void nrf_gpiote_TASKS_OUT_0(void){ nrf_gpiote_TASKS_OUT(0); }
nrf_gpiote_TASKS_OUT_1(void)325 void nrf_gpiote_TASKS_OUT_1(void){ nrf_gpiote_TASKS_OUT(1); }
nrf_gpiote_TASKS_OUT_2(void)326 void nrf_gpiote_TASKS_OUT_2(void){ nrf_gpiote_TASKS_OUT(2); }
nrf_gpiote_TASKS_OUT_3(void)327 void nrf_gpiote_TASKS_OUT_3(void){ nrf_gpiote_TASKS_OUT(3); }
nrf_gpiote_TASKS_OUT_4(void)328 void nrf_gpiote_TASKS_OUT_4(void){ nrf_gpiote_TASKS_OUT(4); }
nrf_gpiote_TASKS_OUT_5(void)329 void nrf_gpiote_TASKS_OUT_5(void){ nrf_gpiote_TASKS_OUT(5); }
nrf_gpiote_TASKS_OUT_6(void)330 void nrf_gpiote_TASKS_OUT_6(void){ nrf_gpiote_TASKS_OUT(6); }
nrf_gpiote_TASKS_OUT_7(void)331 void nrf_gpiote_TASKS_OUT_7(void){ nrf_gpiote_TASKS_OUT(7); }
332