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