Move Interrupt and NotifyCircSetup modules into tci663x
[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 extern volatile cregister UInt DNUM;
52 /*
53  *************************************************************************
54  *                      Module functions
55  *************************************************************************
56  */
58 /*
59  *  ======== Interrupt_Module_startup ========
60  */
61 Int Interrupt_Module_startup(Int phase)
62 {
63     UInt16 hostId;
64     String name;
65     UInt nameId;
67     /* wait for Startup (because user function might set local procId) */
68     if (!Startup_Module_startupDone()) {
69         return (Startup_NOTDONE);
70     }
71     else if (MultiProc_self() == MultiProc_INVALIDID) {
72         /* if user function is missing, this will eventually fail */
73         return (Startup_NOTDONE);
74     }
76     if (!ti_sdo_utils_MultiProc_Module_startupDone()) {
77         return (Startup_NOTDONE);
78     }
80     if (Interrupt_module->baseId == MultiProc_INVALIDID) {
81         Interrupt_module->baseId = MultiProc_getBaseIdOfCluster();
82     }
83     Assert_isTrue(Interrupt_module->baseId != MultiProc_INVALIDID,
84             Interrupt_A_clusterBaseId);
86     /*  If this assert fails, then MultiProc config has changed to break
87      *  an assumption in Linux rpmsg driver, that HOST is listed first in
88      *  MultiProc name list configuration.
89      */
90     if ((hostId = MultiProc_getId("HOST")) != MultiProc_INVALIDID) {
91         Assert_isTrue((hostId - Interrupt_module->baseId) == 0,
92                 Interrupt_A_hostConfig);
93     }
95     /*  Validate the running executable has been loaded onto the correct
96      *  processor. In other words, make sure CORE0 was loaded onto DSP0
97      *  (i.e. DNUM == 0), CORE1 loaded onto DSP1, etc.
98      */
99     name = MultiProc_getName(MultiProc_self());
100     nameId = (UInt)(name[4] - '0');
102     if (nameId != DNUM) {
103         System_abort("incorrect executable loaded onto processor");
104     }
106     if (!Interrupt_enableKick) {
107         /* do not unlock the kick registers */
108         return (Startup_DONE);
109     }
111     /* only write KICK registers from CORE0 */
112     if (DNUM == 0) {
113         /* TODO: What if CORE0 is not started, but the others are? */
114         if (Interrupt_KICK0 && Interrupt_KICK1) {
115             volatile UInt32 *kick0 = (volatile UInt32 *)Interrupt_KICK0;
116             volatile UInt32 *kick1 = (volatile UInt32 *)Interrupt_KICK1;
118             /* unlock the KICK mechanism in the Bootcfg MMRs if defined */
119             *kick0 = 0x83e70b13;        /* must be written with this value */
120             *kick1 = 0x95a4f1e0;        /* must be written with this value */
121         }
122     }
123     return (Startup_DONE);
126 /*
127  *  ======== Interrupt_intEnable ========
128  *  Enable interrupt
129  *  TODO: fix this with interrupt mask
130  */
131 Void Interrupt_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
133     Hwi_enableInterrupt(intInfo->intVectorId);
136 /*
137  *  ======== Interrupt_intDisable ========
138  *  Disables interrupts
139  *  TODO: fix this with interrupt mask
140  */
141 Void Interrupt_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
143     Hwi_disableInterrupt(intInfo->intVectorId);
146 /*
147  *  ======== Interrupt_intRegister ========
148  *  Register ISR for remote processor interrupt
149  */
150 Void Interrupt_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *unused,
151         Fxn func, UArg arg)
153     UInt key;
154     Hwi_Params hwiAttrs;
155     UInt16 clusterId;
156     volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
157     UInt32 val;
159     /* disable global interrupts */
160     key = Hwi_disable();
162     /* setup the function table with client function and argument */
163     clusterId = remoteProcId - Interrupt_module->baseId;
164     Interrupt_module->clientTab[clusterId].func = func;
165     Interrupt_module->clientTab[clusterId].arg = arg;
167     /* make sure the interrupt gets plugged only once */
168     if (Interrupt_module->numPlugged++ == 0) {
170         /* clear all pending ipc interrupts */
171         val = ipcar[DNUM];
172         ipcar[DNUM] = val;
174         /* register ipc interrupt */
175         Hwi_Params_init(&hwiAttrs);
176         hwiAttrs.maskSetting = Hwi_MaskingOption_SELF;
177         hwiAttrs.eventId = Interrupt_INTERDSPINT;
178         Interrupt_module->hwi = Hwi_create(Interrupt_ipcIntr, Interrupt_isr,
179                 &hwiAttrs, NULL);
180     }
182     /* restore global interrupts */
183     Hwi_restore(key);
186 /*
187  *  ======== Interrupt_intUnregister ========
188  */
189 Void Interrupt_intUnregister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
191     UInt key;
192     UInt16 clusterId;
194     /* disable global interrupts */
195     key = Hwi_disable();
197     if (--Interrupt_module->numPlugged == 0) {
198         Hwi_delete(&Interrupt_module->hwi);
199     }
201     /* clear function table entry */
202     clusterId = remoteProcId - Interrupt_module->baseId;
203     Interrupt_module->clientTab[clusterId].func = NULL;
204     Interrupt_module->clientTab[clusterId].arg = (UArg)(-1);
206     /* restore global interrupts */
207     Hwi_restore(key);
210 /*
211  *  ======== Interrupt_intSend ========
212  *  Send interrupt to the remote processor
213  */
214 Void Interrupt_intSend(UInt16 procId, IInterrupt_IntInfo *unused, UArg arg)
216     UInt32 val;
217     volatile UInt32 *ipcgr = (volatile UInt32 *)Interrupt_IPCGR0;
218     volatile UInt32 *ipcgrh = (volatile UInt32 *)Interrupt_IPCGRH;
219     int clusterId;
220     UInt dnum;
222     /*  bit 0 is set to generate interrupt.
223      *  bits 4-7 is set to specify the interrupt generation source.
224      *  The convention is that bit 4 (SRCS0) is used for core 0,
225      *  bit 5 (SRCS1) for core 1, etc... .
226      */
227     val = (1 << (DNUM + Interrupt_SRCSx_SHIFT)) | 1;
229     if (procId == MultiProc_getId("HOST")) {
230         /* interrupt the host processor,  use IPCGRH register */
231         *ipcgrh = val;
232     }
233     else {
234         /* compute ipcgr address for recipient processor */
235         clusterId = procId - Interrupt_module->baseId;
236         dnum = Interrupt_module->hwTab[clusterId].dnum;
237         ipcgr[dnum] = val;
238     }
241 /*
242  *  ======== Interrupt_intPost ========
243  *  Post an interrupt to local processor
244  */
245 Void Interrupt_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo, UArg arg)
247     int clusterId;
248     int bit;
249     UInt32 val;
250     volatile UInt32 *ipcgr = (volatile UInt32 *)Interrupt_IPCGR0;
252     /* compute srcsx bit of source processor */
253     clusterId = srcProcId - Interrupt_module->baseId;
254     bit = Interrupt_module->hwTab[clusterId].srcsx;
255     val = (1 << bit) | 1;
257     /* raise the interrupt to myself */
258     ipcgr[DNUM] = val;
261 /*
262  *  ======== Interrupt_intClear ========
263  *  Acknowledge interrupt by clearing the corresponding source bit.
264  *  Does not clear the IFR bit by way of ICR write because that should
265  *  only be done during init time.
266  */
267 UInt Interrupt_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *unused)
269     int clusterId;
270     int pos;
271     volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
272     UInt val;
273     UInt stat = 0;
275     /* compute srcsx bit of remote processor */
276     clusterId = remoteProcId - Interrupt_module->baseId;
277     pos = Interrupt_module->hwTab[clusterId].srcsx;
279     /* read ipcar register to get source bits */
280     val = ipcar[DNUM];
282     if (val & (1 << pos)) {
283         /* write ipc acknowledgement register to clear source bit */
284         ipcar[DNUM] = (1 << pos);
285         stat = 1;
286     }
288     return (stat);
291 /*
292  *************************************************************************
293  *                      Internals functions
294  *************************************************************************
295  */
297 /*
298  *  ======== Interrupt_isr ========
299  */
300 Void Interrupt_isr(UArg unused)
302     int clId;
303     Interrupt_ClientEntry *entry;
304     volatile UInt32 *ipcar = (volatile UInt32 *)Interrupt_IPCAR0;
305     UInt32 val;
306     int bit;
308     /* ipc acknowledgement register value */
309     val = ipcar[DNUM];
311     for (clId = 0; clId < ti_sdo_utils_MultiProc_numProcsInCluster; clId++) {
312         bit = Interrupt_module->hwTab[clId].srcsx;
314         if (val & (1 << bit)) {
316             /* clear the interrupt source */
317             ipcar[DNUM] = (1 << bit);
319             /* invoke the client isr */
320             entry = &(Interrupt_module->clientTab[clId]);
322             if (entry->func != NULL) {
323                 (entry->func)(entry->arg);
324             }
325         }
326     }