1 /*
2 * Copyright (c) 2017, Texas Instruments Incorporated
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/__assert.h>
10 #include <kernel/zephyr/dpl/dpl.h>
11 #include <ti/drivers/dpl/HwiP.h>
12
13 #include <inc/hw_types.h>
14 #include <inc/hw_ints.h>
15 #include <driverlib/rom.h>
16 #if defined(CONFIG_SOC_SERIES_CC32XX)
17 #include <driverlib/rom_map.h>
18 #endif
19 #include <driverlib/interrupt.h>
20
21 /*
22 * IRQ_CONNECT requires we know the ISR signature and argument
23 * at build time; whereas SimpleLink plugs the interrupts
24 * at run time, so we create an ISR shim, and register that.
25 * The callback argument doesn't change after the ISR is registered.
26 */
27 struct sl_isr_args
28 {
29 HwiP_Fxn cb;
30 uintptr_t arg;
31 };
32
sl_isr(const void * isr_arg)33 static void sl_isr(const void *isr_arg)
34 {
35 HwiP_Fxn cb = ((struct sl_isr_args *)isr_arg)->cb;
36 uintptr_t arg = ((struct sl_isr_args *)isr_arg)->arg;
37
38 /* Call the SimpleLink ISR Handler: */
39 if (cb) {
40 cb(arg);
41 }
42 }
43
44 #if defined(CONFIG_SOC_SERIES_CC32XX)
45 static struct sl_isr_args sl_UDMA_cb = {NULL, 0};
46 static struct sl_isr_args sl_UDMAERR_cb = {NULL, 0};
47 static struct sl_isr_args sl_NWPIC_cb = {NULL, 0};
48 static struct sl_isr_args sl_LSPI_cb = {NULL, 0};
49
50 /* Must hardcode the IRQ for IRQ_CONNECT macro. Must be <= CONFIG_NUM_IRQS.*/
51 #define EXCEPTION_UDMA 46 /* == INT_UDMA (62) - 16 */
52 #define EXCEPTION_UDMAERR 47 /* == INT_UDMAERR (63) - 16 */
53 #define EXCEPTION_NWPIC 171 /* == INT_NWPIC (187) - 16 */
54 #define EXCEPTION_LSPI 177 /* == INT_LSPI (193) - 16 */
55
HwiP_create(int interruptNum,HwiP_Fxn hwiFxn,HwiP_Params * params)56 HwiP_Handle HwiP_create(int interruptNum, HwiP_Fxn hwiFxn, HwiP_Params *params)
57 {
58 HwiP_Handle handle = 0;
59 uint32_t priority = ~0;
60 uintptr_t arg = 0;
61
62 if (params) {
63 priority = params->priority;
64 arg = params->arg;
65 }
66
67 /*
68 * SimpleLink only uses the NWPIC, UDMA, UDMAERR and LSPI interrupts:
69 */
70 __ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
71 INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
72 "Unexpected interruptNum: %d\r\n",
73 interruptNum);
74 /*
75 * Priority expected is either:
76 * INT_PRIORITY_LVL_1,
77 * or ~0 or 255 (meaning lowest priority)
78 * ~0 and 255 are meant to be the same as INT_PRIORITY_LVL_7.
79 * For ~0 or 255, we want 7; but Zephyr IRQ_CONNECT adds +1,
80 * so we pass 6 for those TI drivers passing prio = ~0.
81 */
82 __ASSERT((INT_PRIORITY_LVL_1 == priority) ||
83 (0xff == (priority & 0xff)),
84 "Expected priority: 0x%x or 0x%x, got: 0x%x\r\n",
85 INT_PRIORITY_LVL_1, 0xff, (unsigned int)priority);
86
87 switch(interruptNum) {
88 case INT_UDMA:
89 sl_UDMA_cb.cb = hwiFxn;
90 sl_UDMA_cb.arg = arg;
91 IRQ_CONNECT(EXCEPTION_UDMA, 6, sl_isr, &sl_UDMA_cb, 0);
92 break;
93 case INT_UDMAERR:
94 sl_UDMAERR_cb.cb = hwiFxn;
95 sl_UDMAERR_cb.arg = arg;
96 IRQ_CONNECT(EXCEPTION_UDMAERR, 6, sl_isr, &sl_UDMAERR_cb, 0);
97 break;
98 case INT_NWPIC:
99 sl_NWPIC_cb.cb = hwiFxn;
100 sl_NWPIC_cb.arg = arg;
101 IRQ_CONNECT(EXCEPTION_NWPIC, 1, sl_isr, &sl_NWPIC_cb, 0);
102 break;
103 case INT_LSPI:
104 sl_LSPI_cb.cb = hwiFxn;
105 sl_LSPI_cb.arg = arg;
106 IRQ_CONNECT(EXCEPTION_LSPI, 6, sl_isr, &sl_LSPI_cb, 0);
107 break;
108 default:
109 return(handle);
110 }
111 irq_enable(interruptNum - 16);
112
113 return (HwiP_Handle)interruptNum;
114 }
115
116 /* Can't actually de-register an interrupt in Zephyr, so just disable: */
HwiP_delete(HwiP_Handle handle)117 void HwiP_delete(HwiP_Handle handle)
118 {
119 int interruptNum = (int)handle;
120
121 __ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
122 INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
123 "Unexpected interruptNum: %d\r\n",
124 interruptNum);
125
126 irq_disable(interruptNum - 16);
127 }
128 #elif defined(CONFIG_SOC_SERIES_CC13X2_CC26X2) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
129 /* INT_PENDSV is already taken by Zephyr, so let's use INT_SWEV0 to support
130 * SwiP since this line is usually unused. Change this to a different
131 * interrupt if desired.
132 */
133 int HwiP_swiPIntNum = INT_SWEV0;
134
135 typedef struct _HwiP_Obj {
136 uint32_t intNum;
137 struct sl_isr_args * cb;
138 } HwiP_Obj;
139
140 static struct sl_isr_args sl_OSC_COMB_cb = {NULL, 0};
141 static struct sl_isr_args sl_AUX_COMB_cb = {NULL, 0};
142 static struct sl_isr_args sl_RFC_HW_COMB_cb = {NULL, 0};
143 static struct sl_isr_args sl_RFC_CPE_0_cb = {NULL, 0};
144 static struct sl_isr_args sl_SWEV0_cb = {NULL, 0};
145 static struct sl_isr_args sl_AUX_SWEV0_cb = {NULL, 0};
146 static struct sl_isr_args sl_AUX_SWEV1_cb = {NULL, 0};
147
148 /*
149 * ======== HwiP_construct ========
150 */
HwiP_construct(HwiP_Struct * handle,int interruptNum,HwiP_Fxn hwiFxn,HwiP_Params * params)151 HwiP_Handle HwiP_construct(HwiP_Struct *handle, int interruptNum,
152 HwiP_Fxn hwiFxn, HwiP_Params *params)
153 {
154 HwiP_Obj *obj = (HwiP_Obj *)handle;
155 uintptr_t arg = 0;
156 uint8_t priority = INT_PRI_LEVEL7; /* default to lowest priority */
157 bool enable = true;
158
159 if (handle == NULL) {
160 return NULL;
161 }
162
163 if (params) {
164 priority = params->priority;
165 arg = params->arg;
166 enable = params->enableInt;
167 }
168
169 /*
170 * Currently only support INT_OSC_COMB, INT_AUX_COMB, INT_SWEV0
171 */
172 __ASSERT(INT_OSC_COMB == interruptNum || INT_AUX_COMB == interruptNum
173 || INT_RFC_HW_COMB == interruptNum
174 || INT_RFC_CPE_0 == interruptNum
175 || INT_SWEV0 == interruptNum
176 || INT_AUX_SWEV0 == interruptNum
177 || INT_AUX_SWEV1 == interruptNum,
178 "Unexpected interruptNum: %d\r\n",
179 interruptNum);
180
181 /*
182 * Priority expected is either:
183 * INT_PRI_LEVEL1 to INT_PRI_LEVEL7,
184 * or ~0 or 255 (meaning lowest priority)
185 * ~0 and 255 are meant to be the same as INT_PRI_LEVEL7.
186 * For ~0 or 255, we want 7; but Zephyr IRQ_CONNECT adds +1
187 * to reserve INT_PRI_LEVEL0,
188 * so we pass 6 for those TI drivers passing prio = ~0.
189 */
190 __ASSERT((INT_PRI_LEVEL7 == priority) ||
191 (INT_PRI_LEVEL6 == priority) ||
192 (INT_PRI_LEVEL5 == priority) ||
193 (INT_PRI_LEVEL4 == priority) ||
194 (INT_PRI_LEVEL3 == priority) ||
195 (INT_PRI_LEVEL2 == priority) ||
196 (INT_PRI_LEVEL1 == priority) ||
197 (0xFF == priority),
198 "Unexpected priority level, got: 0x%x\r\n",
199 (unsigned int)priority);
200
201 if (0xFF == priority) {
202 priority = INT_PRI_LEVEL7;
203 }
204
205 /* The priority for IRQ_CONNECT is encoded in the top 3 bits */
206 priority = (priority >> 5) - 1;
207
208 switch(interruptNum) {
209 case INT_RFC_CPE_0:
210 sl_RFC_CPE_0_cb.cb = hwiFxn;
211 sl_RFC_CPE_0_cb.arg = arg;
212 obj->cb = &sl_RFC_CPE_0_cb;
213 irq_connect_dynamic(INT_RFC_CPE_0 - 16, priority, sl_isr, &sl_RFC_CPE_0_cb, 0);
214 break;
215 case INT_RFC_HW_COMB:
216 sl_RFC_HW_COMB_cb.cb = hwiFxn;
217 sl_RFC_HW_COMB_cb.arg = arg;
218 obj->cb = &sl_RFC_HW_COMB_cb;
219 irq_connect_dynamic(INT_RFC_HW_COMB - 16, priority, sl_isr, &sl_RFC_HW_COMB_cb, 0);
220 break;
221 case INT_OSC_COMB:
222 sl_OSC_COMB_cb.cb = hwiFxn;
223 sl_OSC_COMB_cb.arg = arg;
224 obj->cb = &sl_OSC_COMB_cb;
225 irq_connect_dynamic(INT_OSC_COMB - 16, priority, sl_isr, &sl_OSC_COMB_cb, 0);
226 break;
227 case INT_AUX_COMB:
228 sl_AUX_COMB_cb.cb = hwiFxn;
229 sl_AUX_COMB_cb.arg = arg;
230 obj->cb = &sl_AUX_COMB_cb;
231 irq_connect_dynamic(INT_AUX_COMB - 16, priority, sl_isr, &sl_AUX_COMB_cb, 0);
232 break;
233 case INT_SWEV0:
234 sl_SWEV0_cb.cb = hwiFxn;
235 sl_SWEV0_cb.arg = arg;
236 obj->cb = &sl_SWEV0_cb;
237 irq_connect_dynamic(INT_SWEV0 - 16, priority, sl_isr, &sl_SWEV0_cb, 0);
238 break;
239 case INT_AUX_SWEV0:
240 sl_AUX_SWEV0_cb.cb = hwiFxn;
241 sl_AUX_SWEV0_cb.arg = arg;
242 obj->cb = &sl_AUX_SWEV0_cb;
243 irq_connect_dynamic(INT_AUX_SWEV0 - 16, priority, sl_isr, &sl_AUX_SWEV0_cb, 0);
244 break;
245 case INT_AUX_SWEV1:
246 sl_AUX_SWEV1_cb.cb = hwiFxn;
247 sl_AUX_SWEV1_cb.arg = arg;
248 obj->cb = &sl_AUX_SWEV1_cb;
249 irq_connect_dynamic(INT_AUX_SWEV1 - 16, priority, sl_isr, &sl_AUX_SWEV1_cb, 0);
250 break;
251 default:
252 return(NULL);
253 }
254 if (enable)
255 {
256 irq_enable(interruptNum - 16);
257 }
258
259 obj->intNum = interruptNum;
260
261 return (HwiP_Handle)handle;
262 }
263 #endif
264
HwiP_Params_init(HwiP_Params * params)265 void HwiP_Params_init(HwiP_Params *params)
266 {
267 params->arg = 0;
268 params->priority = ~0;
269 params->enableInt = true;
270 }
271
272 /* Zephyr has no functions for clearing an interrupt, so use driverlib: */
HwiP_clearInterrupt(int interruptNum)273 void HwiP_clearInterrupt(int interruptNum)
274 {
275 #if defined(CONFIG_SOC_SERIES_CC13X2_CC26X2) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
276 IntPendClear((unsigned long)interruptNum);
277 #elif defined(CONFIG_SOC_SERIES_CC32XX)
278 MAP_IntPendClear((unsigned long)interruptNum);
279 #endif
280 }
281
HwiP_enableInterrupt(int interruptNum)282 void HwiP_enableInterrupt(int interruptNum)
283 {
284 irq_enable(interruptNum - 16);
285 }
286
HwiP_disableInterrupt(int interruptNum)287 void HwiP_disableInterrupt(int interruptNum)
288 {
289 irq_disable(interruptNum - 16);
290 }
291
HwiP_disable(void)292 uintptr_t HwiP_disable(void)
293 {
294 uintptr_t key;
295
296 key = irq_lock();
297
298 return (key);
299 }
300
HwiP_restore(uintptr_t key)301 void HwiP_restore(uintptr_t key)
302 {
303 irq_unlock(key);
304 }
305
306 #if defined(CONFIG_SOC_SERIES_CC13X2_CC26X2) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
HwiP_post(int interruptNum)307 void HwiP_post(int interruptNum)
308 {
309 IntPendSet((uint32_t)interruptNum);
310 }
311
HwiP_setFunc(HwiP_Handle hwiP,HwiP_Fxn fxn,uintptr_t arg)312 void HwiP_setFunc(HwiP_Handle hwiP, HwiP_Fxn fxn, uintptr_t arg)
313 {
314 HwiP_Obj *obj = (HwiP_Obj *)hwiP;
315
316 uintptr_t key = HwiP_disable();
317
318 obj->cb->cb = fxn;
319 obj->cb->arg = arg;
320
321 HwiP_restore(key);
322 }
323
HwiP_destruct(HwiP_Struct * hwiP)324 void HwiP_destruct(HwiP_Struct *hwiP)
325 {
326 HwiP_Obj *obj = (HwiP_Obj *)hwiP->data;
327
328 int interruptNum = obj->intNum;
329
330 irq_disable(interruptNum - 16);
331
332 obj->cb->cb = NULL;
333 obj->cb->arg = (uintptr_t)NULL;
334 obj->cb = NULL;
335 }
336 #endif
337