1 /*
2 * Copyright (c) 2012-2013, 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/hal/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) { /* DSP1 */
102 IntXbar_connect(33, 287); // eve1 mailbox
103 IntXbar_connect(34, 296); // eve2 mailbox
104 IntXbar_connect(35, 305); // eve3 mailbox
105 IntXbar_connect(36, 314); // eve4 mailbox
106 IntXbar_connect(37, 258); // system mailbox 7
107 IntXbar_connect(38, 254); // system mailbox 6 user 1
108 }
109 else { /* DSP0 */
110 IntXbar_connect(33, 284); // eve1 mailbox
111 IntXbar_connect(34, 293); // eve2 mailbox
112 IntXbar_connect(35, 302); // eve3 mailbox
113 IntXbar_connect(36, 311); // eve4 mailbox
114 IntXbar_connect(37, 257); // system mailbox 7
115 IntXbar_connect(38, 253); // system mailbox 6 user 0
116 }
117 return (Startup_DONE);
118 }
120 return (Startup_NOTDONE);
121 }
123 /*!
124 * ======== InterruptDsp_intEnable ========
125 * Enable remote processor interrupt
126 */
127 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
128 {
129 UInt16 index;
131 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
132 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
134 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
136 REG32(MAILBOX_IRQENABLE_SET_DSP(index))=MAILBOX_REG_VAL(SUBMBX_IDX(index));
137 }
139 /*!
140 * ======== InterruptDsp_intDisable ========
141 * Disables remote processor interrupt
142 */
143 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
144 {
145 UInt16 index;
147 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
148 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
150 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
152 REG32(MAILBOX_IRQENABLE_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
153 }
155 /*!
156 * ======== InterruptDsp_intRegister ========
157 */
158 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
159 Fxn func, UArg arg)
160 {
161 UInt key;
162 UInt eventId;
163 UInt combinedEventId;
164 Int index;
165 Hwi_Params params;
166 InterruptDsp_FxnTable *table;
168 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
169 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
171 index = PROCID(remoteProcId);
173 /* Disable global interrupts */
174 key = Hwi_disable();
176 table = &(InterruptDsp_module->fxnTable[index]);
177 table->func = func;
178 table->arg = arg;
180 InterruptDsp_intClear(remoteProcId, intInfo);
182 /* Make sure the interrupt only gets plugged once */
183 eventId = InterruptDsp_dspInterruptTable[index];
185 InterruptDsp_module->numPlugged++;
187 if (InterruptDsp_module->numPlugged == 1) {
188 EventCombiner_dispatchPlug(eventId,
189 (Hwi_FuncPtr)InterruptDsp_intShmStub, eventId, TRUE);
190 Hwi_Params_init(¶ms);
192 combinedEventId = eventId / EVENT_GROUP_SIZE;
194 params.eventId = combinedEventId;
195 params.arg = combinedEventId;
196 params.enableInt = TRUE;
197 Hwi_create(intInfo->intVectorId, &ti_sysbios_family_c64p_EventCombiner_dispatch,
198 ¶ms, NULL);
199 Hwi_enableInterrupt(intInfo->intVectorId);
200 }
201 else {
202 EventCombiner_dispatchPlug(eventId,
203 (Hwi_FuncPtr)InterruptDsp_intShmStub, eventId, TRUE);
204 }
206 /* Enable the mailbox interrupt to the DSP */
207 InterruptDsp_intEnable(remoteProcId, intInfo);
209 /* Restore global interrupts */
210 Hwi_restore(key);
211 }
213 /*!
214 * ======== InterruptDsp_intUnregister ========
215 */
216 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
217 IInterrupt_IntInfo *intInfo)
218 {
219 Hwi_Handle hwiHandle;
220 Int index;
221 UInt eventId;
222 InterruptDsp_FxnTable *table;
224 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
225 (remoteProcId == MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
227 index = PROCID(remoteProcId);
229 /* Disable the mailbox interrupt source */
230 InterruptDsp_intDisable(remoteProcId, intInfo);
232 /* Make sure the interrupt only gets plugged once */
233 eventId = InterruptDsp_dspInterruptTable[index];
235 InterruptDsp_module->numPlugged--;
237 EventCombiner_disableEvent(eventId);
239 if (InterruptDsp_module->numPlugged == 0) {
240 /* Delete the Hwi */
241 hwiHandle = Hwi_getHandle(intInfo->intVectorId);
242 Hwi_delete(&hwiHandle);
243 }
245 table = &(InterruptDsp_module->fxnTable[index]);
246 table->func = NULL;
247 table->arg = NULL;
248 }
250 /*!
251 * ======== InterruptDsp_intSend ========
252 * Send interrupt to the remote processor
253 */
254 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
255 UArg arg)
256 {
257 UInt key;
258 UInt16 index;
260 index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
262 /*
263 * Before writing to a mailbox, check whehter it already contains a message
264 * If so, then don't write to the mailbox since we want one and only one
265 * message per interrupt. Disable interrupts between reading
266 * the MSGSTATUS_X register and writing to the mailbox to protect from
267 * another thread doing an intSend at the same time
268 *
269 * Note regarding possible race condition between local 'intSend' and
270 * remote 'intClear':
271 * It is possible that we we read the MAILBOX_MSGSTATUS_X register during
272 * the remote side's intClear. Therefore, we might choose _not_ to send
273 * write to the mailbox even though the mailbox is about to be cleared a
274 * few cycles later. In this case, the interrupt will be lost.
275 * This is OK, however. intClear should always be called by the Notify
276 * driver _before_ shared memory is read, so the event will be picked up
277 * anyway by the previous interrupt that caused intClear to be called.
278 */
279 key = Hwi_disable();
280 if (REG32(MAILBOX_STATUS(index)) == 0) {
281 REG32(MAILBOX_MESSAGE(index)) = arg;
282 }
283 Hwi_restore(key);
284 }
286 /*!
287 * ======== InterruptDsp_intPost ========
288 */
289 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
290 UArg arg)
291 {
292 UInt key;
293 UInt16 index;
295 index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
297 key = Hwi_disable();
298 if (REG32(MAILBOX_STATUS(index)) == 0) {
299 REG32(MAILBOX_MESSAGE(index)) = arg;
300 }
301 Hwi_restore(key);
302 }
304 /*!
305 * ======== InterruptDsp_intClear ========
306 * Clear interrupt
307 */
308 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
309 {
310 UInt arg;
311 UInt16 index;
313 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
315 arg = REG32(MAILBOX_MESSAGE(index));
316 REG32(MAILBOX_IRQSTATUS_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
318 /* Write to EOI (End Of Interrupt) register */
319 REG32(MAILBOX_EOI_REG(index)) = 0x1;
321 return (arg);
322 }
324 /*
325 *************************************************************************
326 * Internals functions
327 *************************************************************************
328 */
330 /*!
331 * ======== InterruptDsp_intShmStub ========
332 */
333 Void InterruptDsp_intShmStub(UArg arg)
334 {
335 UInt16 index;
336 UInt16 selfIdx;
337 UInt16 loopIdx;
338 InterruptDsp_FxnTable *table;
340 selfIdx = MultiProc_self();
342 /*
343 * Loop through each Sub-mailbox to determine which one generated
344 * interrupt.
345 */
346 for (loopIdx = 0; loopIdx < MultiProc_getNumProcsInCluster(); loopIdx++) {
348 if (loopIdx == selfIdx) {
349 continue;
350 }
352 index = MBX_TABLE_IDX(loopIdx, selfIdx);
354 if ((REG32(MAILBOX_STATUS(index)) != 0) &&
355 (REG32(MAILBOX_IRQENABLE_SET_DSP(index)) &
356 MAILBOX_REG_VAL(SUBMBX_IDX(index)))) {
357 table = &(InterruptDsp_module->fxnTable[PROCID(loopIdx)]);
358 (table->func)(table->arg);
359 }
360 }
361 }