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