]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - packages/ti/sdo/ipc/family/tci663x/Interrupt.c
Linux: Update user AF_RPMSG define for 5.15+ kernels
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / tci663x / Interrupt.c
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);
142 /*
143  *  ======== Interrupt_intEnable ========
144  *  Enable interrupt
145  *  TODO: fix this with interrupt mask
146  */
147 Void Interrupt_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
149     Hwi_enableInterrupt(intInfo->intVectorId);
152 /*
153  *  ======== Interrupt_intDisable ========
154  *  Disables interrupts
155  *  TODO: fix this with interrupt mask
156  */
157 Void Interrupt_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
159     Hwi_disableInterrupt(intInfo->intVectorId);
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)
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);
218 /*
219  *  ======== Interrupt_intUnregister ========
220  */
221 Void Interrupt_intUnregister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
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);
242 /*
243  *  ======== Interrupt_intSend ========
244  *  Send interrupt to the remote processor
245  */
246 Void Interrupt_intSend(UInt16 procId, IInterrupt_IntInfo *unused, UArg arg)
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     }
279 /*
280  *  ======== Interrupt_intPost ========
281  *  Post an interrupt to local processor
282  */
283 Void Interrupt_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo, UArg arg)
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
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)
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);
349 /*
350  *************************************************************************
351  *                      Internals functions
352  *************************************************************************
353  */
355 /*
356  *  ======== Interrupt_isr ========
357  */
358 Void Interrupt_isr(UArg unused)
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     }