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 * ======== InterruptArp32.c ========
34 * ARP32 mailbox based interrupt manager
35 */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Error.h>
41 #include <ti/sysbios/family/arp32/Hwi.h>
43 #include <ti/sdo/utils/_MultiProc.h>
44 #include <ti/sdo/ipc/_Ipc.h>
45 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
47 #include "package/internal/InterruptArp32.xdc.h"
49 /* Register access method. */
50 #define REG16(A) (*(volatile UInt16 *) (A))
51 #define REG32(A) (*(volatile UInt32 *) (A))
53 #define PROCID(IDX) (InterruptArp32_procIdTable[IDX])
54 #define MBX_TABLE_IDX(SRC, DST) ((PROCID(SRC) * InterruptArp32_NUM_CORES) + \
55 PROCID(DST))
56 #define SUBMBX_IDX(IDX) (InterruptArp32_mailboxTable[IDX] & 0xFF)
57 #define MBX_USER_IDX(IDX) ((InterruptArp32_mailboxTable[IDX] >> 8) \
58 & 0xFF)
59 #define MBX_BASEADDR_IDX(IDX) ((InterruptArp32_mailboxTable[IDX] >> 16) \
60 & 0xFFFF)
62 #define MAILBOX_REG_VAL(M) (0x1 << (2 * M))
64 #define MAILBOX_MESSAGE(IDX) (InterruptArp32_mailboxBaseAddr[ \
65 MBX_BASEADDR_IDX(IDX)] + 0x040 \
66 + (0x4 * SUBMBX_IDX(IDX)))
67 #define MAILBOX_STATUS(IDX) (InterruptArp32_mailboxBaseAddr[ \
68 MBX_BASEADDR_IDX(IDX)] + 0x0C0 \
69 + (0x4 * SUBMBX_IDX(IDX)))
71 #define MAILBOX_IRQSTATUS_CLR(IDX) (InterruptArp32_mailboxBaseAddr[ \
72 MBX_BASEADDR_IDX(IDX)] + 0x104 \
73 + (MBX_USER_IDX(IDX) * 0x10))
74 #define MAILBOX_IRQENABLE_SET(IDX) (InterruptArp32_mailboxBaseAddr[ \
75 MBX_BASEADDR_IDX(IDX)] + 0x108 \
76 + (MBX_USER_IDX(IDX) * 0x10))
77 #define MAILBOX_IRQENABLE_CLR(IDX) (InterruptArp32_mailboxBaseAddr[ \
78 MBX_BASEADDR_IDX(IDX)] + 0x10C \
79 + (MBX_USER_IDX(IDX) * 0x10))
81 #define MAILBOX_EOI_REG(IDX) (InterruptArp32_mailboxBaseAddr[ \
82 MBX_BASEADDR_IDX(IDX)] + 0x140)
84 /* This needs to match the virtual id from the TableInit.xs */
85 #define DSP1_ID 4
86 #define DSP2_ID 5
87 #define IPU1_ID 6
88 #define IPU2_ID 7
89 #define HOST_ID 8
91 /*
92 *************************************************************************
93 * Module functions
94 *************************************************************************
95 */
97 /*!
98 * ======== InterruptArp32_intEnable ========
99 * Enable remote processor interrupt
100 */
101 Void InterruptArp32_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
102 {
103 UInt16 index;
105 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
107 REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
108 }
110 /*!
111 * ======== InterruptArp32_intDisable ========
112 * Disables remote processor interrupt
113 */
114 Void InterruptArp32_intDisable(UInt16 remoteProcId,
115 IInterrupt_IntInfo *intInfo)
116 {
117 UInt16 index;
119 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
121 REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
122 }
124 /*!
125 * ======== InterruptArp32_intRegister ========
126 */
127 Void InterruptArp32_intRegister(UInt16 remoteProcId,
128 IInterrupt_IntInfo *intInfo,
129 Fxn func, UArg arg)
130 {
131 UInt key;
132 UInt16 index;
133 UInt mbxIdx;
134 Hwi_Params hwiAttrs;
135 Error_Block eb;
136 InterruptArp32_FxnTable *table;
138 Assert_isTrue(remoteProcId < ti_sdo_utils_MultiProc_numProcessors,
139 ti_sdo_ipc_Ipc_A_internal);
141 /* Assert that our MultiProc id is set correctly */
142 Assert_isTrue((InterruptArp32_eve1ProcId == MultiProc_self()) ||
143 (InterruptArp32_eve2ProcId == MultiProc_self()) ||
144 (InterruptArp32_eve3ProcId == MultiProc_self()) ||
145 (InterruptArp32_eve4ProcId == MultiProc_self()),
146 ti_sdo_ipc_Ipc_A_internal);
148 /* init error block */
149 Error_init(&eb);
151 index = PROCID(remoteProcId);
153 /* Disable global interrupts */
154 key = Hwi_disable();
156 table = &(InterruptArp32_module->fxnTable[index]);
157 table->func = func;
158 table->arg = arg;
160 InterruptArp32_intClear(remoteProcId, intInfo);
162 if ((index == DSP1_ID) || (index == IPU1_ID) || (index == HOST_ID)) {
163 mbxIdx = 0;
164 }
165 else if ((index == DSP2_ID) || (index == IPU2_ID)) {
166 mbxIdx = 1;
167 }
168 else if (index < InterruptArp32_NUM_EVES) {
169 mbxIdx = 2;
170 }
172 /* Make sure the interrupt only gets plugged once */
173 InterruptArp32_module->numPlugged[mbxIdx]++;
174 if (InterruptArp32_module->numPlugged[mbxIdx] == 1) {
175 /* Register interrupt to remote processor */
176 Hwi_Params_init(&hwiAttrs);
177 hwiAttrs.arg = arg;
178 hwiAttrs.vectorNum = intInfo->intVectorId;
180 Hwi_create(InterruptArp32_eveInterruptTable[index],
181 (Hwi_FuncPtr)InterruptArp32_intShmStub,
182 &hwiAttrs,
183 &eb);
184 Hwi_enableInterrupt(InterruptArp32_eveInterruptTable[index]);
185 }
187 /* enable the mailbox and Hwi */
188 InterruptArp32_intEnable(remoteProcId, intInfo);
190 /* Restore global interrupts */
191 Hwi_restore(key);
192 }
194 /*!
195 * ======== InterruptArp32_intUnregister ========
196 */
197 Void InterruptArp32_intUnregister(UInt16 remoteProcId,
198 IInterrupt_IntInfo *intInfo)
199 {
200 UInt16 index;
201 UInt mbxIdx;
202 Hwi_Handle hwiHandle;
203 InterruptArp32_FxnTable *table;
205 index = PROCID(remoteProcId);
207 if ((remoteProcId == DSP1_ID) || (remoteProcId == IPU1_ID) || (remoteProcId == HOST_ID)) {
208 mbxIdx = 0;
209 }
210 else if ((remoteProcId == DSP2_ID) || (remoteProcId == IPU2_ID)) {
211 mbxIdx = 1;
212 }
213 else if (remoteProcId < InterruptArp32_NUM_EVES) {
214 mbxIdx = 2;
215 }
217 /* Disable the mailbox interrupt source */
218 InterruptArp32_intDisable(remoteProcId, intInfo);
220 InterruptArp32_module->numPlugged[mbxIdx]--;
221 if (InterruptArp32_module->numPlugged[mbxIdx] == 0) {
222 /* Delete the Hwi */
223 hwiHandle = Hwi_getHandle(InterruptArp32_eveInterruptTable[index]);
224 Hwi_delete(&hwiHandle);
225 }
227 /* Clear the FxnTable entry for the remote processor */
228 table = &(InterruptArp32_module->fxnTable[index]);
229 table->func = NULL;
230 table->arg = 0;
231 }
234 /*!
235 * ======== InterruptArp32_intSend ========
236 * Send interrupt to the remote processor
237 */
238 Void InterruptArp32_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
239 UArg arg)
240 {
241 UInt key;
242 UInt16 index;
244 index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
246 /* disable interrupts */
247 key = Hwi_disable();
249 if (REG32(MAILBOX_STATUS(index)) == 0) {
250 /* write the mailbox message to remote proc */
251 REG32(MAILBOX_MESSAGE(index)) = arg;
252 }
254 /* restore interrupts */
255 Hwi_restore(key);
256 }
259 /*!
260 * ======== InterruptArp32_intPost ========
261 * Simulate an interrupt from a remote processor
262 */
263 Void InterruptArp32_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
264 UArg arg)
265 {
266 UInt key;
267 UInt16 index;
269 index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
271 /* disable interrupts */
272 key = Hwi_disable();
274 if (REG32(MAILBOX_STATUS(index)) == 0) {
275 /* write the mailbox message to arp32 */
276 REG32(MAILBOX_MESSAGE(index)) = arg;
277 }
279 /* restore interrupts */
280 Hwi_restore(key);
281 }
284 /*!
285 * ======== InterruptArp32_intClear ========
286 * Clear interrupt
287 */
288 UInt InterruptArp32_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
289 {
290 UInt arg;
291 UInt16 index;
293 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
295 arg = REG32(MAILBOX_MESSAGE(index));
296 /* clear the dsp mailbox */
297 REG32(MAILBOX_IRQSTATUS_CLR(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
299 /* Write to EOI (End Of Interrupt) register */
300 REG32(MAILBOX_EOI_REG(index)) = 0x1;
302 return (arg);
303 }
305 /*
306 *************************************************************************
307 * Internals functions
308 *************************************************************************
309 */
311 /*!
312 * ======== InterruptArp32_intShmStub ========
313 */
314 Void InterruptArp32_intShmStub(UArg arg)
315 {
316 UInt16 index;
317 UInt16 selfIdx;
318 UInt16 loopIdx;
319 InterruptArp32_FxnTable *table;
321 selfIdx = MultiProc_self();
323 for (loopIdx = 0; loopIdx < MultiProc_getNumProcsInCluster(); loopIdx++) {
325 if (loopIdx == selfIdx) {
326 continue;
327 }
329 index = MBX_TABLE_IDX(loopIdx, selfIdx);
331 if ((REG32(MAILBOX_STATUS(index)) != 0) &&
332 (REG32(MAILBOX_IRQENABLE_SET(index)) &
333 MAILBOX_REG_VAL(SUBMBX_IDX(index)))) {
334 /* call function with arg */
335 table = &(InterruptArp32_module->fxnTable[PROCID(loopIdx)]);
336 (table->func)(table->arg);
337 }
338 }
339 }