1 /*
2 * Copyright (c) 2012-2014 Texas Instruments Incorporated - http://www.ti.com
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/Assert.h>
38 #include <xdc/runtime/Startup.h>
39 #include <xdc/runtime/System.h>
41 #include <ti/sysbios/family/c64p/Hwi.h>
42 #include <ti/sysbios/family/c64p/EventCombiner.h>
43 #include <ti/sysbios/family/shared/vayu/IntXbar.h>
45 #include <ti/sdo/ipc/_Ipc.h>
46 #include <ti/sdo/ipc/family/vayu/NotifySetup.h>
47 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
48 #include <ti/sdo/utils/_MultiProc.h>
50 #include "package/internal/InterruptDsp.xdc.h"
52 /* Register access method. */
53 #define REG16(A) (*(volatile UInt16 *) (A))
54 #define REG32(A) (*(volatile UInt32 *) (A))
56 #define PROCID(IDX) (InterruptDsp_procIdTable[IDX])
57 #define MBX_TABLE_IDX(SRC, DST) ((PROCID(SRC) * InterruptDsp_NUM_CORES) + \
58 PROCID(DST))
59 #define SUBMBX_IDX(IDX) (InterruptDsp_mailboxTable[IDX] & 0xFF)
60 #define MBX_USER_IDX(IDX) ((InterruptDsp_mailboxTable[IDX] >> 8) & 0xFF)
61 #define MBX_BASEADDR_IDX(IDX) ((InterruptDsp_mailboxTable[IDX] >> 16) & 0xFFFF)
63 #define MAILBOX_REG_VAL(M) (0x1 << (2 * M))
65 #define MAILBOX_MESSAGE(IDX) (InterruptDsp_mailboxBaseAddr[ \
66 MBX_BASEADDR_IDX(IDX)] + 0x40 \
67 + (0x4 * SUBMBX_IDX(IDX)))
68 #define MAILBOX_STATUS(IDX) (InterruptDsp_mailboxBaseAddr[ \
69 MBX_BASEADDR_IDX(IDX)] + 0xC0 \
70 + (0x4 * SUBMBX_IDX(IDX)))
72 #define MAILBOX_IRQSTATUS_CLR_DSP(IDX) (InterruptDsp_mailboxBaseAddr[ \
73 MBX_BASEADDR_IDX(IDX)] + \
74 (0x10 * MBX_USER_IDX(IDX)) + 0x104)
75 #define MAILBOX_IRQENABLE_SET_DSP(IDX) (InterruptDsp_mailboxBaseAddr[ \
76 MBX_BASEADDR_IDX(IDX)] + \
77 (0x10 * MBX_USER_IDX(IDX)) + 0x108)
78 #define MAILBOX_IRQENABLE_CLR_DSP(IDX) (InterruptDsp_mailboxBaseAddr[ \
79 MBX_BASEADDR_IDX(IDX)] + \
80 (0x10 * MBX_USER_IDX(IDX)) + 0x10C)
81 #define MAILBOX_EOI_REG(IDX) (InterruptDsp_mailboxBaseAddr[ \
82 MBX_BASEADDR_IDX(IDX)] + 0x140)
83 #define EVENT_GROUP_SIZE 32
85 /*
86 *************************************************************************
87 * Module functions
88 *************************************************************************
89 */
91 /*
92 * ======== InterruptDsp_Module_startup ========
93 */
94 Int InterruptDsp_Module_startup(Int phase)
95 {
96 extern cregister volatile UInt DNUM;
98 if (IntXbar_Module_startupDone()) {
99 /* connect mailbox interrupts at startup */
100 if (DNUM == 0) { /* DSP1 */
101 IntXbar_connect(24, 284); // eve1 mailbox 0 user 1
102 IntXbar_connect(25, 293); // eve2 mailbox 0 user 1
103 IntXbar_connect(26, 249); // system mailbox 5 user 0
105 InterruptDsp_module->interruptTable[6] = 57; // IPU1-0
106 InterruptDsp_module->interruptTable[9] = 57; // IPU1-1
108 /* plug eve3 and eve4 mbxs only if eve3 and eve4 exists */
109 if ((MultiProc_getId("EVE3") != MultiProc_INVALIDID) ||
110 (MultiProc_getId("EVE4") != MultiProc_INVALIDID)) {
111 IntXbar_connect(27, 302); // eve3 mailbox 0 user 1
112 IntXbar_connect(28, 311); // eve4 mailbox 0 user 1
113 }
115 /* plug mbx7 only if DSP2 or IPU2 exists */
116 if ((MultiProc_getId("DSP2") != MultiProc_INVALIDID) ||
117 (MultiProc_getId("IPU2") != MultiProc_INVALIDID) ||
118 (MultiProc_getId("IPU2-0") != MultiProc_INVALIDID)) {
119 IntXbar_connect(29, 257); // system mailbox 7 user 0
120 InterruptDsp_module->interruptTable[7] = 60; // IPU2-0
121 }
123 /* plug mbx8 only if IPU2-1 exists */
124 if (MultiProc_getId("IPU2-1") != MultiProc_INVALIDID) {
125 IntXbar_connect(30, 261); // system mailbox 8 user 0
126 InterruptDsp_module->interruptTable[10] = 61; // IPU2-1
127 }
128 }
129 else if (DNUM == 1) { /* DSP2 */
130 IntXbar_connect(24, 287); // eve1 mailbox 1 user 1
131 IntXbar_connect(25, 296); // eve2 mailbox 1 user 1
132 IntXbar_connect(26, 253); // system mailbox 6 user 0
134 InterruptDsp_module->interruptTable[7] = 57; // IPU2-0
135 InterruptDsp_module->interruptTable[10] = 57; // IPU2-1
137 /* plug eve3 and eve4 mbxs only if eve3 and eve4 exists */
138 if ((MultiProc_getId("EVE3") != MultiProc_INVALIDID) ||
139 (MultiProc_getId("EVE4") != MultiProc_INVALIDID)) {
140 IntXbar_connect(27, 305); // eve3 mailbox 1 user 1
141 IntXbar_connect(28, 314); // eve4 mailbox 1 user 1
142 }
144 /* plug mbx7 only if DSP1 or IPU1 exists */
145 if ((MultiProc_getId("DSP1") != MultiProc_INVALIDID) ||
146 (MultiProc_getId("IPU1") != MultiProc_INVALIDID) ||
147 (MultiProc_getId("IPU1-0") != MultiProc_INVALIDID)) {
148 IntXbar_connect(29, 258); // system mailbox 7 user 1
149 InterruptDsp_module->interruptTable[6] = 60; // IPU1-0
150 }
152 /* plug mbx8 only if IPU1-1 exists */
153 if (MultiProc_getId("IPU1-1") != MultiProc_INVALIDID) {
154 IntXbar_connect(30, 262); // system mailbox 8 user 1
155 InterruptDsp_module->interruptTable[9] = 61; // IPU1-1
156 }
157 }
158 return (Startup_DONE);
159 }
161 return (Startup_NOTDONE);
162 }
164 /*
165 * ======== InterruptDsp_intEnable ========
166 * Enable remote processor interrupt
167 */
168 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
169 {
170 UInt16 index;
172 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
173 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
175 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
177 REG32(MAILBOX_IRQENABLE_SET_DSP(index))=MAILBOX_REG_VAL(SUBMBX_IDX(index));
178 }
180 /*
181 * ======== InterruptDsp_intDisable ========
182 * Disables remote processor interrupt
183 */
184 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
185 {
186 UInt16 index;
188 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
189 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
191 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
193 REG32(MAILBOX_IRQENABLE_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
194 }
196 /*
197 * ======== InterruptDsp_intRegister ========
198 */
199 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
200 Fxn func, UArg arg)
201 {
202 UInt key;
203 Int index;
204 InterruptDsp_FxnTable *table;
206 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
207 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
209 index = PROCID(remoteProcId);
211 /* Disable global interrupts */
212 key = Hwi_disable();
214 table = &(InterruptDsp_module->fxnTable[index]);
215 table->func = func;
216 table->arg = arg;
218 InterruptDsp_intClear(remoteProcId, intInfo);
220 /* plug the cpu interrupt */
221 NotifySetup_plugHwi(remoteProcId, intInfo->intVectorId,
222 InterruptDsp_intShmStub);
224 /* Enable the mailbox interrupt to the DSP */
225 InterruptDsp_intEnable(remoteProcId, intInfo);
227 /* Restore global interrupts */
228 Hwi_restore(key);
229 }
231 /*
232 * ======== InterruptDsp_intUnregister ========
233 */
234 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
235 IInterrupt_IntInfo *intInfo)
236 {
237 Int index;
238 InterruptDsp_FxnTable *table;
240 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
241 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
243 index = PROCID(remoteProcId);
245 /* Disable the mailbox interrupt source */
246 InterruptDsp_intDisable(remoteProcId, intInfo);
248 /* unplug isr and unprogram the event dispatcher */
249 NotifySetup_unplugHwi(remoteProcId, intInfo->intVectorId);
251 table = &(InterruptDsp_module->fxnTable[index]);
252 table->func = NULL;
253 table->arg = 0;
254 }
256 /*
257 * ======== InterruptDsp_intSend ========
258 * Send interrupt to the remote processor
259 */
260 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
261 UArg arg)
262 {
263 UInt key;
264 UInt16 index;
266 index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
268 /*
269 * Before writing to a mailbox, check whether it already contains a
270 * message. If so, wait for the message to be read since we want one
271 * and only one message per interrupt. Disable interrupts between reading
272 * the MSGSTATUS_X register and writing to the mailbox to protect from
273 * another thread doing an intSend at the same time.
274 */
275 key = Hwi_disable();
276 while (REG32(MAILBOX_STATUS(index)) != 0) {
277 Hwi_restore(key);
278 key = Hwi_disable();
279 }
280 REG32(MAILBOX_MESSAGE(index)) = arg;
281 Hwi_restore(key);
282 }
284 /*
285 * ======== InterruptDsp_intPost ========
286 */
287 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
288 UArg arg)
289 {
290 UInt key;
291 UInt16 index;
293 index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
295 key = Hwi_disable();
296 if (REG32(MAILBOX_STATUS(index)) == 0) {
297 REG32(MAILBOX_MESSAGE(index)) = arg;
298 }
299 Hwi_restore(key);
300 }
302 /*
303 * ======== InterruptDsp_intClear ========
304 * Clear interrupt
305 */
306 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
307 {
308 UInt arg;
309 UInt16 index;
311 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
313 arg = REG32(MAILBOX_MESSAGE(index));
314 REG32(MAILBOX_IRQSTATUS_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
316 /* Write to EOI (End Of Interrupt) register */
317 REG32(MAILBOX_EOI_REG(index)) = 0x1;
319 return (arg);
320 }
322 /*
323 *************************************************************************
324 * Internals functions
325 *************************************************************************
326 */
328 /*
329 * ======== InterruptDsp_intShmStub ========
330 */
331 Void InterruptDsp_intShmStub(UInt16 idx)
332 {
333 UInt16 srcVirtId;
334 InterruptDsp_FxnTable *table;
336 srcVirtId = idx / InterruptDsp_NUM_CORES;
337 table = &(InterruptDsp_module->fxnTable[srcVirtId]);
338 (table->func)(table->arg);
339 }