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 #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) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
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) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
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) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7)
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