1 /*
2 * Copyright (c) 2024, Texas Instruments Incorporated
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8
9 #include <ti/drivers/dpl/HwiP.h>
10 #include <ti/drivers/dpl/SwiP.h>
11
12 #include "QueueP.h"
13
14 /* Lowest priority interrupt for CC23X0 */
15 #define INT_PRI_LEVEL7 0x000000C0
16
17 #define NUMPRI 4
18
19 typedef enum
20 {
21 SwiP_State_Idle = 0,
22 SwiP_State_Posted,
23 SwiP_State_Running,
24 SwiP_State_Interrupted
25 } SwiP_State;
26
27 typedef uint32_t SwiP_LockState;
28
29 enum
30 {
31 SwiP_LockState_Locked,
32 SwiP_LockState_Unlocked
33 };
34
35 typedef struct SwiP_Obj
36 {
37 QueueP_Elem elem;
38 QueueP_Handle readyList;
39 SwiP_Params params;
40 SwiP_Fxn fxn;
41 uint32_t trigger;
42 uint32_t state;
43 } SwiP_Obj;
44
45 extern bool HwiP_inSwi(void);
46
47 static void SwiP_handleHwi();
48
49 static const SwiP_Params SwiP_defaultParams = {
50 .arg0 = (uintptr_t)NULL,
51 .arg1 = (uintptr_t)NULL,
52 .priority = ~0, /* max priority */
53 .trigger = 0,
54 };
55
56 static volatile int SwiP_readyMask;
57 static volatile SwiP_LockState SwiP_lockState;
58 static volatile uint32_t SwiP_currentTrigger;
59 static volatile bool SwiP_schedulerRunning;
60 static volatile bool SwiP_initialized = false;
61 static HwiP_Struct SwiP_hwiStruct;
62 static QueueP_Obj SwiP_readyList[NUMPRI];
63
64 /* don't call with n == 0 */
maxbit(int n)65 static int maxbit(int n)
66 {
67 int mask = 1 << (NUMPRI - 1);
68 int max = NUMPRI - 1;
69
70 while (mask)
71 {
72 if (n & mask)
73 {
74 return max;
75 }
76 max--;
77 mask >>= 1;
78 }
79
80 return 0;
81 }
82
83 /*
84 * ======== SwiP_Params_init ========
85 */
SwiP_Params_init(SwiP_Params * params)86 void SwiP_Params_init(SwiP_Params *params)
87 {
88 /* structure copy */
89 *params = SwiP_defaultParams;
90 }
91
92 /*
93 * ======== SwiP_construct ========
94 */
SwiP_construct(SwiP_Struct * handle,SwiP_Fxn swiFxn,SwiP_Params * params)95 SwiP_Handle SwiP_construct(SwiP_Struct *handle, SwiP_Fxn swiFxn, SwiP_Params *params)
96 {
97 SwiP_Obj *swi = (SwiP_Obj *)handle;
98 HwiP_Params hwiParams;
99 uintptr_t hwiKey;
100 uint32_t priority;
101 int i;
102
103 if (handle != NULL)
104 {
105 hwiKey = HwiP_disable();
106
107 if (SwiP_initialized == false)
108 {
109 for (i = 0; i < NUMPRI; i++)
110 {
111 QueueP_init(&SwiP_readyList[i]);
112 }
113 SwiP_readyMask = 0;
114 SwiP_currentTrigger = 0;
115 SwiP_lockState = SwiP_LockState_Unlocked;
116 SwiP_schedulerRunning = false;
117
118 HwiP_Params_init(&hwiParams);
119 hwiParams.priority = INT_PRI_LEVEL7; // use the lowest priority
120 HwiP_construct(&SwiP_hwiStruct, HwiP_swiPIntNum, SwiP_handleHwi, &hwiParams);
121
122 SwiP_initialized = true;
123 }
124
125 HwiP_restore(hwiKey);
126
127 if (params == NULL)
128 {
129 params = (SwiP_Params *)&SwiP_defaultParams;
130 }
131
132 if (params->priority == (~0))
133 {
134 priority = NUMPRI - 1;
135 }
136 else
137 {
138 priority = params->priority;
139 }
140
141 if (priority >= NUMPRI)
142 {
143 return NULL;
144 }
145 else
146 {
147 QueueP_init((QueueP_Obj *)&swi->elem);
148 swi->params = *params;
149 swi->params.priority = priority;
150 swi->fxn = swiFxn;
151 swi->trigger = swi->params.trigger;
152 swi->state = SwiP_State_Idle;
153 swi->readyList = &SwiP_readyList[priority];
154 }
155 }
156
157 return ((SwiP_Handle)swi);
158 }
159
160 /*
161 * ======== SwiP_destruct ========
162 */
SwiP_destruct(SwiP_Struct * handle)163 void SwiP_destruct(SwiP_Struct *handle)
164 {
165 SwiP_Obj *swi = (SwiP_Obj *)handle;
166 uintptr_t hwiKey = HwiP_disable();
167
168 /* if on SwiP_readyList, remove it */
169 QueueP_remove(&swi->elem);
170 if (QueueP_empty(swi->readyList))
171 {
172 SwiP_readyMask &= ~(1 << swi->params.priority);
173 }
174
175 HwiP_restore(hwiKey);
176 }
177
178 /*
179 * ======== SwiP_disable ========
180 */
SwiP_disable(void)181 uintptr_t SwiP_disable(void)
182 {
183 uintptr_t previousHwiState = HwiP_disable();
184
185 SwiP_LockState previousLockState = SwiP_lockState;
186 SwiP_lockState = SwiP_LockState_Locked;
187
188 HwiP_restore(previousHwiState);
189
190 return previousLockState;
191 }
192
193 /*
194 * This is a non-preemptive fixed-priority scheduler implementation.
195 * It runs with interrupts disabled, but enables them for each swi.
196 */
SwiP_dispatch(uintptr_t hwiKey)197 void SwiP_dispatch(uintptr_t hwiKey)
198 {
199 SwiP_Obj *swi;
200 int maxpri;
201
202 while (SwiP_readyMask && (SwiP_lockState == SwiP_LockState_Unlocked))
203 {
204 maxpri = maxbit(SwiP_readyMask);
205 swi = (SwiP_Obj *)QueueP_get(&SwiP_readyList[maxpri]);
206
207 if (QueueP_empty(&SwiP_readyList[maxpri]))
208 {
209 SwiP_readyMask &= ~(1 << maxpri);
210 }
211
212 /*
213 * Prepare the swi for execution. The trigger has to be saved
214 * because the swi might re-post itself with another trigger value.
215 */
216 swi->state = SwiP_State_Running;
217 SwiP_currentTrigger = swi->trigger;
218 swi->trigger = swi->params.trigger;
219
220 /* run the swi with interrupts enabled */
221 HwiP_restore(hwiKey);
222 swi->fxn(swi->params.arg0, swi->params.arg1);
223 hwiKey = HwiP_disable();
224
225 /* If the swi didn't get re-posted, set it to idle now */
226 if (swi->state == SwiP_State_Running)
227 {
228 swi->state = SwiP_State_Idle;
229 }
230 }
231
232 /* Scheduler was set to running immediately after posting the interrupt */
233 SwiP_schedulerRunning = false;
234 }
235
SwiP_handleHwi()236 static void SwiP_handleHwi()
237 {
238 uintptr_t hwiKey = HwiP_disable();
239
240 SwiP_dispatch(hwiKey);
241
242 HwiP_restore(hwiKey);
243 }
244
245 /*
246 * ======== SwiP_getTrigger ========
247 */
SwiP_getTrigger()248 uint32_t SwiP_getTrigger()
249 {
250 return (SwiP_currentTrigger);
251 }
252
253 /*
254 * ======== SwiP_or ========
255 */
SwiP_or(SwiP_Handle handle,uint32_t mask)256 void SwiP_or(SwiP_Handle handle, uint32_t mask)
257 {
258 SwiP_Obj *swi = (SwiP_Obj *)handle;
259 uintptr_t hwiKey = HwiP_disable();
260
261 swi->trigger |= mask;
262
263 HwiP_restore(hwiKey);
264 SwiP_post(swi);
265 }
266
267 /*
268 * ======== SwiP_post ========
269 */
SwiP_post(SwiP_Handle handle)270 void SwiP_post(SwiP_Handle handle)
271 {
272 SwiP_Obj *swi = (SwiP_Obj *)handle;
273 uintptr_t hwiKey = HwiP_disable();
274
275 /* (Re-)post an swi only once */
276 if (swi->state != SwiP_State_Posted)
277 {
278 swi->state = SwiP_State_Posted;
279
280 QueueP_put(&SwiP_readyList[swi->params.priority], (QueueP_Elem *)&swi->elem);
281 SwiP_readyMask |= 1 << swi->params.priority;
282 }
283
284 /* Activate the scheduler when not already running */
285 if ((SwiP_schedulerRunning == false) && (SwiP_lockState == SwiP_LockState_Unlocked))
286 {
287 HwiP_post(HwiP_swiPIntNum);
288 /* Set the scheduler into running state to avoid double posts */
289 SwiP_schedulerRunning = true;
290 }
291
292 HwiP_restore(hwiKey);
293 }
294
295 /*
296 * ======== SwiP_restore ========
297 */
SwiP_restore(uintptr_t key)298 void SwiP_restore(uintptr_t key)
299 {
300 uintptr_t hwiKey = HwiP_disable();
301
302 SwiP_lockState = key;
303
304 /* Determine whether the scheduler needs to run */
305 if (SwiP_readyMask && (key == SwiP_LockState_Unlocked) && (SwiP_schedulerRunning == false))
306 {
307 HwiP_post(HwiP_swiPIntNum);
308 /* Set the scheduler into running state to avoid double posts */
309 SwiP_schedulerRunning = true;
310 }
311
312 HwiP_restore(hwiKey);
313 }
314
315 /*
316 * ======== SwiP_inISR ========
317 */
SwiP_inISR(void)318 bool SwiP_inISR(void)
319 {
320 return (HwiP_inSwi());
321 }