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 */
33 /*
34 * ======== InterruptDsp.c ========
35 * Mailbox based interrupt manager
36 */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Startup.h>
41 #include <ti/sysbios/family/c64p/EventCombiner.h>
42 #include <ti/sysbios/family/c64p/Hwi.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_intEnable ========
93 * Enable remote processor interrupt
94 */
95 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
96 {
97 UInt16 index;
99 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
100 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
102 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
104 REG32(MAILBOX_IRQENABLE_SET_DSP(index))=MAILBOX_REG_VAL(SUBMBX_IDX(index));
105 }
107 /*
108 * ======== InterruptDsp_intDisable ========
109 * Disables remote processor interrupt
110 */
111 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
112 {
113 UInt16 index;
115 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
116 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
118 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
120 REG32(MAILBOX_IRQENABLE_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
121 }
123 /*
124 * ======== InterruptDsp_intRegister ========
125 */
126 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
127 Fxn func, UArg arg)
128 {
129 UInt key;
130 Int index;
131 InterruptDsp_FxnTable *table;
133 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
134 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
136 index = PROCID(remoteProcId);
138 /* Disable global interrupts */
139 key = Hwi_disable();
141 table = &(InterruptDsp_module->fxnTable[index]);
142 table->func = func;
143 table->arg = arg;
145 InterruptDsp_intClear(remoteProcId, intInfo);
147 /* plug the cpu interrupt */
148 NotifySetup_plugHwi(remoteProcId, intInfo->intVectorId,
149 InterruptDsp_intShmStub);
151 /* Enable the mailbox interrupt to the DSP */
152 InterruptDsp_intEnable(remoteProcId, intInfo);
154 /* Restore global interrupts */
155 Hwi_restore(key);
156 }
158 /*
159 * ======== InterruptDsp_intUnregister ========
160 */
161 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
162 IInterrupt_IntInfo *intInfo)
163 {
164 Int index;
165 InterruptDsp_FxnTable *table;
167 Assert_isTrue(((remoteProcId < MultiProc_getNumProcsInCluster()) &&
168 (remoteProcId != MultiProc_self())), ti_sdo_ipc_Ipc_A_internal);
170 index = PROCID(remoteProcId);
172 /* disable the mailbox interrupt source */
173 InterruptDsp_intDisable(remoteProcId, intInfo);
175 /* unplug isr and unprogram the event dispatcher */
176 NotifySetup_unplugHwi(remoteProcId, intInfo->intVectorId);
178 table = &(InterruptDsp_module->fxnTable[index]);
179 table->func = NULL;
180 table->arg = 0;
181 }
183 /*
184 * ======== InterruptDsp_intSend ========
185 * Send interrupt to the remote processor
186 */
187 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
188 UArg arg)
189 {
190 UInt key;
191 UInt16 index;
193 index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
195 /*
196 * Before writing to a mailbox, check whether it already contains a
197 * message. If so, wait for the message to be read since we want one
198 * and only one message per interrupt. Disable interrupts between reading
199 * the MSGSTATUS_X register and writing to the mailbox to protect from
200 * another thread doing an intSend at the same time.
201 */
202 key = Hwi_disable();
203 while (REG32(MAILBOX_STATUS(index)) != 0) {
204 Hwi_restore(key);
205 key = Hwi_disable();
206 }
207 REG32(MAILBOX_MESSAGE(index)) = arg;
208 Hwi_restore(key);
209 }
211 /*
212 * ======== InterruptDsp_intPost ========
213 */
214 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
215 UArg arg)
216 {
217 UInt key;
218 UInt16 index;
220 index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
222 key = Hwi_disable();
223 if (REG32(MAILBOX_STATUS(index)) == 0) {
224 REG32(MAILBOX_MESSAGE(index)) = arg;
225 }
226 Hwi_restore(key);
227 }
229 /*
230 * ======== InterruptDsp_intClear ========
231 * Clear interrupt
232 */
233 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
234 {
235 UInt arg;
236 UInt16 index;
238 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
240 arg = REG32(MAILBOX_MESSAGE(index));
241 REG32(MAILBOX_IRQSTATUS_CLR_DSP(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
243 /* Write to EOI (End Of Interrupt) register */
244 REG32(MAILBOX_EOI_REG(index)) = 0x1;
246 return (arg);
247 }
249 /*
250 *************************************************************************
251 * Internals functions
252 *************************************************************************
253 */
255 /*
256 * ======== InterruptDsp_intShmStub ========
257 */
258 Void InterruptDsp_intShmStub(UInt16 idx)
259 {
260 UInt16 srcVirtId;
261 InterruptDsp_FxnTable *table;
263 srcVirtId = idx / InterruptDsp_NUM_CORES;
264 table = &(InterruptDsp_module->fxnTable[srcVirtId]);
265 (table->func)(table->arg);
266 }