ec24a7e9cda3ff1f88d128456e41441fceac790c
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);
163 }
165 /*
166 * ======== InterruptDsp_intEnable ========
167 * Enable remote processor interrupt
168 */
169 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
170 {
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));
179 }
181 /*
182 * ======== InterruptDsp_intDisable ========
183 * Disables remote processor interrupt
184 */
185 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
186 {
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));
195 }
197 /*
198 * ======== InterruptDsp_intRegister ========
199 */
200 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
201 Fxn func, UArg arg)
202 {
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(¶ms);
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 ¶ms, 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);
252 }
254 /*
255 * ======== InterruptDsp_intUnregister ========
256 */
257 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
258 IInterrupt_IntInfo *intInfo)
259 {
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;
289 }
291 /*
292 * ======== InterruptDsp_intSend ========
293 * Send interrupt to the remote processor
294 */
295 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
296 UArg arg)
297 {
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);
325 }
327 /*
328 * ======== InterruptDsp_intPost ========
329 */
330 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
331 UArg arg)
332 {
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);
343 }
345 /*
346 * ======== InterruptDsp_intClear ========
347 * Clear interrupt
348 */
349 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
350 {
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);
363 }
365 /*
366 *************************************************************************
367 * Internals functions
368 *************************************************************************
369 */
371 /*
372 * ======== InterruptDsp_intShmStub ========
373 */
374 Void InterruptDsp_intShmStub(UArg arg)
375 {
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 }
402 }