1 /*
2 * Copyright (c) 2014-2015 Texas Instruments Incorporated - http://www.ti.com
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
14 * distribution.
15 *
16 * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
33 /*
34 * ======== Interrupt.c ========
35 */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Startup.h>
39 #include <xdc/runtime/System.h>
41 #include <ti/sysbios/hal/Hwi.h>
43 #include <ti/sdo/ipc/family/tci663x/MultiProcSetup.h>
44 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
45 #include <ti/sdo/utils/_MultiProc.h>
47 #include "package/internal/Interrupt.xdc.h"
49 #define ARM_SOURCE_OFFSET 31
50 #define ARM_HWI_OFFSET 32
52 #if defined(xdc_target__isaCompatible_64P)
53 extern cregister volatile UInt DNUM;
54 #elif defined(xdc_target__isaCompatible_v7A)
55 /* ARM does not support DNUM */
56 #endif
58 /*
59 *************************************************************************
60 * Module functions
61 *************************************************************************
62 */
64 /*
65 * ======== Interrupt_Module_startup ========
66 */
67 Int Interrupt_Module_startup(Int phase)
68 {
69 UInt16 hostId;
70 String name;
71 UInt nameId;
73 /* wait for Startup (because user function might set local procId) */
74 if (!Startup_Module_startupDone()) {
75 return (Startup_NOTDONE);
76 }
77 else if (MultiProc_self() == MultiProc_INVALIDID) {
78 /* if user function is missing, this will eventually fail */
79 return (Startup_NOTDONE);
80 }
82 if (!ti_sdo_utils_MultiProc_Module_startupDone()) {
83 return (Startup_NOTDONE);
84 }
86 if (Interrupt_module->baseId == MultiProc_INVALIDID) {
87 Interrupt_module->baseId = MultiProc_getBaseIdOfCluster();
88 }
89 Assert_isTrue(Interrupt_module->baseId != MultiProc_INVALIDID,
90 Interrupt_A_clusterBaseId);
92 /* If this assert fails, then MultiProc config has changed to break
93 * an assumption in Linux rpmsg driver, that HOST is listed first in
94 * MultiProc name list configuration.
95 */
96 if ((hostId = MultiProc_getId("HOST")) != MultiProc_INVALIDID) {
97 Assert_isTrue((hostId - Interrupt_module->baseId) == 0,
98 Interrupt_A_hostConfig);
99 }
101 #if defined(xdc_target__isaCompatible_64P)
102 /* Validate the running executable has been loaded onto the correct
103 * processor. In other words, make sure CORE0 was loaded onto DSP0
104 * (i.e. DNUM == 0), CORE1 loaded onto DSP1, etc.
105 */
106 name = MultiProc_getName(MultiProc_self());
107 nameId = (UInt)(name[4] - '0');
109 if (nameId != DNUM) {
110 System_abort("incorrect executable loaded onto processor");
111 }
112 #elif defined(xdc_target__isaCompatible_v7A)
113 /* Host doesn't necessarily follow the same naming conventions
114 */
115 #endif
117 if (!Interrupt_enableKick) {
118 /* do not unlock the kick registers */
119 return (Startup_DONE);
120 }
122 #if defined(xdc_target__isaCompatible_64P)
123 /* only write KICK registers from CORE0 */
124 if (DNUM == 0) {
125 /* TODO: What if CORE0 is not started, but the others are? */
126 if (Interrupt_KICK0 && Interrupt_KICK1) {
127 volatile UInt32 *kick0 = (volatile UInt32 *)Interrupt_KICK0;
128 volatile UInt32 *kick1 = (volatile UInt32 *)Interrupt_KICK1;
130 /* unlock the KICK mechanism in the Bootcfg MMRs if defined */
131 *kick0 = 0x83e70b13; /* must be written with this value */
132 *kick1 = 0x95a4f1e0; /* must be written with this value */
133 }
134 }
135 #elif defined(xdc_target__isaCompatible_v7A)
136 /* reserved for RTOS HOST
137 */
138 #endif
139 return (Startup_DONE);
140 }
142 /*
143 * ======== Interrupt_intEnable ========
144 * Enable interrupt
145 * TODO: fix this with interrupt mask
146 */
147 Void Interrupt_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
148 {
149 Hwi_enableInterrupt(intInfo->intVectorId);
150 }
152 /*
153 * ======== Interrupt_intDisable ========
154 * Disables interrupts
155 * TODO: fix this with interrupt mask
156 */
157 Void Interrupt_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
158 {
159 Hwi_disableInterrupt(intInfo->intVectorId);
160 }
162 /*
163 * ======== Interrupt_intRegister ========
164 * Register ISR for remote processor interrupt
165 */
166 Void Interrupt_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *unused,
167 Fxn func, UArg arg)
168 {
169 UInt key;
170 Hwi_Params hwiAttrs;
171 UInt16 clusterId;
172 #if defined(xdc_target__isaCompatible_64P)
173 volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
174 #elif defined(xdc_target__isaCompatible_v7A)
175 volatile UInt32 *ipcarh = (volatile UInt32 *)Interrupt_IPCARH;
176 #endif
177 UInt32 val;
179 /* disable global interrupts */
180 key = Hwi_disable();
182 /* setup the function table with client function and argument */
183 clusterId = remoteProcId - Interrupt_module->baseId;
184 Interrupt_module->clientTab[clusterId].func = func;
185 Interrupt_module->clientTab[clusterId].arg = arg;
187 /* make sure the interrupt gets plugged only once */
188 if (Interrupt_module->numPlugged++ == 0) {
190 #if defined(xdc_target__isaCompatible_64P)
191 /* clear all pending ipc interrupts */
192 val = ipcar[DNUM];
193 ipcar[DNUM] = val;
194 #elif defined(xdc_target__isaCompatible_v7A)
195 /* Verify that this works for ARM */
196 val = *ipcarh;
197 *ipcarh = val;
198 #endif
200 /* register ipc interrupt */
201 Hwi_Params_init(&hwiAttrs);
202 hwiAttrs.maskSetting = Hwi_MaskingOption_SELF;
203 #if defined(xdc_target__isaCompatible_64P)
204 hwiAttrs.eventId = Interrupt_INTERDSPINT,
205 Interrupt_module->hwi = Hwi_create(Interrupt_ipcIntr, Interrupt_isr,
206 &hwiAttrs, NULL);
207 #elif defined(xdc_target__isaCompatible_v7A)
208 Interrupt_module->hwi =
209 Hwi_create(Interrupt_INTERDSPINT + ARM_HWI_OFFSET,
210 Interrupt_isr, &hwiAttrs, NULL);
211 #endif
212 }
214 /* restore global interrupts */
215 Hwi_restore(key);
216 }
218 /*
219 * ======== Interrupt_intUnregister ========
220 */
221 Void Interrupt_intUnregister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
222 {
223 UInt key;
224 UInt16 clusterId;
226 /* disable global interrupts */
227 key = Hwi_disable();
229 if (--Interrupt_module->numPlugged == 0) {
230 Hwi_delete(&Interrupt_module->hwi);
231 }
233 /* clear function table entry */
234 clusterId = remoteProcId - Interrupt_module->baseId;
235 Interrupt_module->clientTab[clusterId].func = NULL;
236 Interrupt_module->clientTab[clusterId].arg = (UArg)(-1);
238 /* restore global interrupts */
239 Hwi_restore(key);
240 }
242 /*
243 * ======== Interrupt_intSend ========
244 * Send interrupt to the remote processor
245 */
246 Void Interrupt_intSend(UInt16 procId, IInterrupt_IntInfo *unused, UArg arg)
247 {
248 UInt32 val;
249 volatile UInt32 *ipcgr = (volatile UInt32 *)Interrupt_IPCGR0;
250 volatile UInt32 *ipcgrh = (volatile UInt32 *)Interrupt_IPCGRH;
251 int clusterId;
252 UInt dnum;
254 #if defined(xdc_target__isaCompatible_64P)
255 /* bit 0 is set to generate interrupt.
256 * bits 4-7 is set to specify the interrupt generation source.
257 * The convention is that bit 4 (SRCS0) is used for core 0,
258 * bit 5 (SRCS1) for core 1, etc... .
259 */
260 val = (1 << (DNUM + Interrupt_SRCSx_SHIFT)) | 1;
261 #elif defined(xdc_target__isaCompatible_v7A)
262 /* Host sets the first bit instead of using DNUM
263 */
264 val = (1 << ARM_SOURCE_OFFSET) | 1;
265 #endif
267 if (procId == MultiProc_getId("HOST")) {
268 /* interrupt the host processor, use IPCGRH register */
269 *ipcgrh = val;
270 }
271 else {
272 /* compute ipcgr address for recipient processor */
273 clusterId = procId - Interrupt_module->baseId;
274 dnum = Interrupt_module->hwTab[clusterId].dnum;
275 ipcgr[dnum] = val;
276 }
277 }
279 /*
280 * ======== Interrupt_intPost ========
281 * Post an interrupt to local processor
282 */
283 Void Interrupt_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo, UArg arg)
284 {
285 int clusterId;
286 int bit;
287 UInt32 val;
288 #if defined(xdc_target__isaCompatible_64P)
289 volatile UInt32 *ipcgr = (volatile UInt32 *)Interrupt_IPCGR0;
290 #elif defined(xdc_target__isaCompatible_v7A)
291 volatile UInt32 *ipcgrh = (volatile UInt32 *)Interrupt_IPCGRH;
292 #endif
294 /* compute srcsx bit of source processor */
295 clusterId = srcProcId - Interrupt_module->baseId;
296 bit = Interrupt_module->hwTab[clusterId].srcsx;
297 val = (1 << bit) | 1;
299 #if defined(xdc_target__isaCompatible_64P)
300 /* raise the interrupt to myself */
301 ipcgr[DNUM] = val;
302 #elif defined(xdc_target__isaCompatible_v7A)
303 *ipcgrh = val;
304 #endif
305 }
307 /*
308 * ======== Interrupt_intClear ========
309 * Acknowledge interrupt by clearing the corresponding source bit.
310 * Does not clear the IFR bit by way of ICR write because that should
311 * only be done during init time.
312 */
313 UInt Interrupt_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *unused)
314 {
315 int clusterId;
316 int pos;
317 #if defined(xdc_target__isaCompatible_64P)
318 volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
319 #elif defined(xdc_target__isaCompatible_v7A)
320 volatile UInt32 *ipcarh = (volatile UInt32 *)Interrupt_IPCARH;
321 #endif
322 UInt val;
323 UInt stat = 0;
325 /* compute srcsx bit of remote processor */
326 clusterId = remoteProcId - Interrupt_module->baseId;
327 pos = Interrupt_module->hwTab[clusterId].srcsx;
329 #if defined(xdc_target__isaCompatible_64P)
330 /* read ipcar register to get source bits */
331 val = ipcar[DNUM];
332 #elif defined(xdc_target__isaCompatible_v7A)
333 val = *ipcarh;
334 #endif
336 if (val & (1 << pos)) {
337 #if defined(xdc_target__isaCompatible_64P)
338 /* write ipc acknowledgement register to clear source bit */
339 ipcar[DNUM] = (1 << pos);
340 #elif defined(xdc_target__isaCompatible_v7A)
341 *ipcarh = (1 << pos);
342 #endif
343 stat = 1;
344 }
346 return (stat);
347 }
349 /*
350 *************************************************************************
351 * Internals functions
352 *************************************************************************
353 */
355 /*
356 * ======== Interrupt_isr ========
357 */
358 Void Interrupt_isr(UArg unused)
359 {
360 int clId;
361 Interrupt_ClientEntry *entry;
362 #if defined(xdc_target__isaCompatible_64P)
363 volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
364 #elif defined(xdc_target__isaCompatible_v7A)
365 volatile UInt32 *ipcarh = (volatile UInt32 *)Interrupt_IPCARH;
366 #endif
367 UInt32 val;
368 int bit;
370 #if defined(xdc_target__isaCompatible_64P)
371 /* ipc acknowledgement register value */
372 val = ipcar[DNUM];
373 #elif defined(xdc_target__isaCompatible_v7A)
374 val = *ipcarh;
375 #endif
377 for (clId = 0; clId < ti_sdo_utils_MultiProc_numProcsInCluster; clId++) {
378 bit = Interrupt_module->hwTab[clId].srcsx;
380 if (val & (1 << bit)) {
382 #if defined(xdc_target__isaCompatible_64P)
383 /* clear the interrupt source */
384 ipcar[DNUM] = (1 << bit);
385 #elif defined(xdc_target__isaCompatible_v7A)
386 *ipcarh = (1 << bit);
387 #endif
389 /* invoke the client isr */
390 entry = &(Interrupt_module->clientTab[clId]);
392 if (entry->func != NULL) {
393 (entry->func)(entry->arg);
394 }
395 }
396 }
397 }