ec24a7e9cda3ff1f88d128456e41441fceac790c
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / vayu / InterruptDsp.c
1 /*
2  * Copyright (c) 2012-2014, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the 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 "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== InterruptDsp.c ========
34  *  Mailbox based interrupt manager
35  */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Startup.h>
38 #include <xdc/runtime/System.h>
39 #include <xdc/runtime/Assert.h>
41 #include <ti/sysbios/family/shared/vayu/IntXbar.h>
43 #include <ti/sysbios/family/c64p/Hwi.h>
44 #include <ti/sysbios/family/c64p/EventCombiner.h>
46 #include <ti/sdo/utils/_MultiProc.h>
47 #include <ti/sdo/ipc/_Ipc.h>
49 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
51 #include "package/internal/InterruptDsp.xdc.h"
53 /* Register access method. */
54 #define REG16(A)   (*(volatile UInt16 *) (A))
55 #define REG32(A)   (*(volatile UInt32 *) (A))
57 #define PROCID(IDX)               (InterruptDsp_procIdTable[IDX])
58 #define MBX_TABLE_IDX(SRC, DST)   ((PROCID(SRC) * InterruptDsp_NUM_CORES) + \
59                                     PROCID(DST))
60 #define SUBMBX_IDX(IDX)           (InterruptDsp_mailboxTable[IDX] & 0xFF)
61 #define MBX_USER_IDX(IDX)         ((InterruptDsp_mailboxTable[IDX] >> 8) & 0xFF)
62 #define MBX_BASEADDR_IDX(IDX)     ((InterruptDsp_mailboxTable[IDX] >> 16) & 0xFFFF)
64 #define MAILBOX_REG_VAL(M)        (0x1 << (2 * M))
66 #define MAILBOX_MESSAGE(IDX)      (InterruptDsp_mailboxBaseAddr[  \
67                                     MBX_BASEADDR_IDX(IDX)] + 0x40 \
68                                     + (0x4 * SUBMBX_IDX(IDX)))
69 #define MAILBOX_STATUS(IDX)       (InterruptDsp_mailboxBaseAddr[  \
70                                     MBX_BASEADDR_IDX(IDX)] + 0xC0 \
71                                     + (0x4 * SUBMBX_IDX(IDX)))
73 #define MAILBOX_IRQSTATUS_CLR_DSP(IDX)   (InterruptDsp_mailboxBaseAddr[ \
74                                            MBX_BASEADDR_IDX(IDX)] +     \
75                                            (0x10 * MBX_USER_IDX(IDX)) + 0x104)
76 #define MAILBOX_IRQENABLE_SET_DSP(IDX)   (InterruptDsp_mailboxBaseAddr[ \
77                                            MBX_BASEADDR_IDX(IDX)] +     \
78                                            (0x10 * MBX_USER_IDX(IDX)) + 0x108)
79 #define MAILBOX_IRQENABLE_CLR_DSP(IDX)   (InterruptDsp_mailboxBaseAddr[ \
80                                            MBX_BASEADDR_IDX(IDX)] +     \
81                                            (0x10 * MBX_USER_IDX(IDX)) + 0x10C)
82 #define MAILBOX_EOI_REG(IDX)             (InterruptDsp_mailboxBaseAddr[ \
83                                            MBX_BASEADDR_IDX(IDX)] + 0x140)
84 #define EVENT_GROUP_SIZE                 32
86 /*
87  *************************************************************************
88  *                      Module functions
89  *************************************************************************
90  */
92 /*
93  *  ======== InterruptDsp_Module_startup ========
94  */
95 Int InterruptDsp_Module_startup(Int phase)
96 {
97     extern cregister volatile UInt DNUM;
99     if (IntXbar_Module_startupDone()) {
100         /* connect mailbox interrupts at startup */
101         if (DNUM == 0) {               /* DSP1 */
102             IntXbar_connect(24, 284);  // eve1 mailbox 0 user 1
103             IntXbar_connect(25, 293);  // eve2 mailbox 0 user 1
104             IntXbar_connect(26, 249);  // system mailbox 5 user 0
106             InterruptDsp_module->interruptTable[6] = 57;    // IPU1-0
107             InterruptDsp_module->interruptTable[9] = 57;    // IPU1-1
109             /* plug eve3 and eve4 mbxs only if eve3 and eve4 exists */
110             if ((MultiProc_getId("EVE3") != MultiProc_INVALIDID) ||
111                 (MultiProc_getId("EVE4") != MultiProc_INVALIDID)) {
112                 IntXbar_connect(27, 302);  // eve3 mailbox 0 user 1
113                 IntXbar_connect(28, 311);  // eve4 mailbox 0 user 1
114             }
116             /* plug mbx7 only if DSP2 or IPU2 exists */
117             if ((MultiProc_getId("DSP2") != MultiProc_INVALIDID) ||
118                 (MultiProc_getId("IPU2") != MultiProc_INVALIDID) ||
119                 (MultiProc_getId("IPU2-0") != MultiProc_INVALIDID)) {
120                 IntXbar_connect(29, 257);  // system mailbox 7 user 0
121                 InterruptDsp_module->interruptTable[7] = 60;    // IPU2-0
122             }
124             /* plug mbx8 only if IPU2-1 exists */
125             if (MultiProc_getId("IPU2-1") != MultiProc_INVALIDID) {
126                 IntXbar_connect(30, 261);  // system mailbox 8 user 0
127                 InterruptDsp_module->interruptTable[10] = 61;    // IPU2-1
128             }
129         }
130         else if (DNUM == 1) {          /* DSP2 */
131             IntXbar_connect(24, 287);  // eve1 mailbox 1 user 1
132             IntXbar_connect(25, 296);  // eve2 mailbox 1 user 1
133             IntXbar_connect(26, 253);  // system mailbox 6 user 0
135             InterruptDsp_module->interruptTable[7] = 57;    // IPU2-0
136             InterruptDsp_module->interruptTable[10] = 57;   // IPU2-1
138             /* plug eve3 and eve4 mbxs only if eve3 and eve4 exists */
139             if ((MultiProc_getId("EVE3") != MultiProc_INVALIDID) ||
140                 (MultiProc_getId("EVE4") != MultiProc_INVALIDID)) {
141                 IntXbar_connect(27, 305);  // eve3 mailbox 1 user 1
142                 IntXbar_connect(28, 314);  // eve4 mailbox 1 user 1
143             }
145             /* plug mbx7 only if DSP1 or IPU1 exists */
146             if ((MultiProc_getId("DSP1") != MultiProc_INVALIDID) ||
147                 (MultiProc_getId("IPU1") != MultiProc_INVALIDID) ||
148                 (MultiProc_getId("IPU1-0") != MultiProc_INVALIDID)) {
149                 IntXbar_connect(29, 258);  // system mailbox 7 user 1
150                 InterruptDsp_module->interruptTable[6] = 60;    // IPU1-0
151             }
153             /* plug mbx8 only if IPU1-1 exists */
154             if (MultiProc_getId("IPU1-1") != MultiProc_INVALIDID) {
155                 IntXbar_connect(30, 262);  // system mailbox 8 user 1
156                 InterruptDsp_module->interruptTable[9] = 61;    // IPU1-1
157             }
158         }
159         return (Startup_DONE);
160     }
162     return (Startup_NOTDONE);
165 /*
166  *  ======== InterruptDsp_intEnable ========
167  *  Enable remote processor interrupt
168  */
169 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
171     UInt16 index;
173     Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
174             (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
176     index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
178     REG32(MAILBOX_IRQENABLE_SET_DSP(index))=MAILBOX_REG_VAL(SUBMBX_IDX(index));
181 /*
182  *  ======== InterruptDsp_intDisable ========
183  *  Disables remote processor interrupt
184  */
185 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
187     UInt16 index;
189     Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
190             (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
192     index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
194     REG32(MAILBOX_IRQENABLE_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
197 /*
198  *  ======== InterruptDsp_intRegister ========
199  */
200 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
201                               Fxn func, UArg arg)
203     UInt        key;
204     UInt        eventId;
205     UInt        combinedEventId;
206     Int         index;
207     Hwi_Params  params;
208     InterruptDsp_FxnTable *table;
210     Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
211                    (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
213     index = PROCID(remoteProcId);
215     /* Disable global interrupts */
216     key = Hwi_disable();
218     table = &(InterruptDsp_module->fxnTable[index]);
219     table->func = func;
220     table->arg  = arg;
222     InterruptDsp_intClear(remoteProcId, intInfo);
224     /* Make sure the interrupt only gets plugged once */
225     eventId = InterruptDsp_module->interruptTable[index];
227     InterruptDsp_module->numPlugged++;
229     if (InterruptDsp_module->numPlugged == 1) {
230         EventCombiner_dispatchPlug(eventId,
231             (Hwi_FuncPtr)InterruptDsp_intShmStub, eventId, TRUE);
233         Hwi_Params_init(&params);
234         combinedEventId = eventId / EVENT_GROUP_SIZE;
235         params.eventId = combinedEventId;
236         params.arg = combinedEventId;
237         params.enableInt = TRUE;
238         Hwi_create(intInfo->intVectorId, &ti_sysbios_family_c64p_EventCombiner_dispatch,
239                    &params, NULL);
240         Hwi_enableInterrupt(intInfo->intVectorId);
241     }
242     else {
243         EventCombiner_dispatchPlug(eventId,
244                 (Hwi_FuncPtr)InterruptDsp_intShmStub, eventId, TRUE);
245     }
247     /* Enable the mailbox interrupt to the DSP */
248     InterruptDsp_intEnable(remoteProcId, intInfo);
250     /* Restore global interrupts */
251     Hwi_restore(key);
254 /*
255  *  ======== InterruptDsp_intUnregister ========
256  */
257 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
258                                 IInterrupt_IntInfo *intInfo)
260     Hwi_Handle  hwiHandle;
261     Int         index;
262     UInt        eventId;
263     InterruptDsp_FxnTable *table;
265     Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
266                    (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
268     index = PROCID(remoteProcId);
270     /* Disable the mailbox interrupt source */
271     InterruptDsp_intDisable(remoteProcId, intInfo);
273     /* Make sure the interrupt only gets plugged once */
274     eventId = InterruptDsp_module->interruptTable[index];
276     InterruptDsp_module->numPlugged--;
278     EventCombiner_disableEvent(eventId);
280     if (InterruptDsp_module->numPlugged == 0) {
281         /* Delete the Hwi */
282         hwiHandle = Hwi_getHandle(intInfo->intVectorId);
283         Hwi_delete(&hwiHandle);
284     }
286     table = &(InterruptDsp_module->fxnTable[index]);
287     table->func = NULL;
288     table->arg  = 0;
291 /*
292  *  ======== InterruptDsp_intSend ========
293  *  Send interrupt to the remote processor
294  */
295 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
296                           UArg arg)
298     UInt key;
299     UInt16 index;
301     index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
303     /*
304      *  Before writing to a mailbox, check whether it already contains a
305      *  message.  If so, don't write to the mailbox since we want one and only
306      *  one message per interrupt.  Disable interrupts between reading
307      *  the MSGSTATUS_X register and writing to the mailbox to protect from
308      *  another thread doing an intSend at the same time
309      *
310      *  Note regarding possible race condition between local 'intSend' and
311      *  remote 'intClear':
312      *  It is possible that we we read the MAILBOX_MSGSTATUS_X register during
313      *  the remote side's intClear.  Therefore, we might choose _not_ to send
314      *  write to the mailbox even though the mailbox is about to be cleared a
315      *  few cycles later. In this case, the interrupt will be lost.
316      *  This is OK, however. intClear should always be called by the Notify
317      *  driver _before_ shared memory is read, so the event will be picked up
318      *  anyway by the previous interrupt that caused intClear to be called.
319      */
320     key = Hwi_disable();
321     if (REG32(MAILBOX_STATUS(index)) == 0) {
322         REG32(MAILBOX_MESSAGE(index)) = arg;
323     }
324     Hwi_restore(key);
327 /*
328  *  ======== InterruptDsp_intPost ========
329  */
330 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
331                           UArg arg)
333     UInt key;
334     UInt16 index;
336     index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
338     key = Hwi_disable();
339     if (REG32(MAILBOX_STATUS(index)) == 0) {
340         REG32(MAILBOX_MESSAGE(index)) = arg;
341     }
342     Hwi_restore(key);
345 /*
346  *  ======== InterruptDsp_intClear ========
347  *  Clear interrupt
348  */
349 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
351     UInt arg;
352     UInt16 index;
354     index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
356     arg = REG32(MAILBOX_MESSAGE(index));
357     REG32(MAILBOX_IRQSTATUS_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
359     /* Write to EOI (End Of Interrupt) register */
360     REG32(MAILBOX_EOI_REG(index)) = 0x1;
362     return (arg);
365 /*
366  *************************************************************************
367  *                      Internals functions
368  *************************************************************************
369  */
371 /*
372  *  ======== InterruptDsp_intShmStub ========
373  */
374 Void InterruptDsp_intShmStub(UArg arg)
376     UInt16 index;
377     UInt16 selfIdx;
378     UInt16 loopIdx;
379     InterruptDsp_FxnTable *table;
381     selfIdx = MultiProc_self();
383     /*
384      * Loop through each Sub-mailbox to determine which one generated
385      * interrupt.
386      */
387     for (loopIdx = 0; loopIdx < MultiProc_getNumProcsInCluster(); loopIdx++) {
389         if (loopIdx == selfIdx) {
390             continue;
391         }
393         index = MBX_TABLE_IDX(loopIdx, selfIdx);
395         if ((REG32(MAILBOX_STATUS(index)) != 0) &&
396             (REG32(MAILBOX_IRQENABLE_SET_DSP(index)) &
397              MAILBOX_REG_VAL(SUBMBX_IDX(index)))) {
398             table = &(InterruptDsp_module->fxnTable[PROCID(loopIdx)]);
399             (table->func)(table->arg);
400         }
401     }