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 * ======== InterruptHost.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/arm/a8/intcps/Hwi.h>
43 #include <ti/sdo/utils/_MultiProc.h>
44 #include <ti/sdo/ipc/_Ipc.h>
46 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
48 #include "package/internal/InterruptHost.xdc.h"
50 /* Register access method. */
51 #define REG16(A) (*(volatile UInt16 *) (A))
52 #define REG32(A) (*(volatile UInt32 *) (A))
54 /* Assigned mailboxes */
55 #define DSP_TO_HOST 0
56 #define DSP_TO_VIDEO 1
57 #define DSP_TO_VPSS 2
58 #define HOST_TO_DSP 3
59 #define HOST_TO_VIDEO 4
60 #define HOST_TO_VPSS 5
61 #define VIDEO_TO_HOST 6
62 #define VIDEO_TO_DSP 7
63 #define VPSS_TO_HOST 8
64 #define VPSS_TO_DSP 9
66 #define MAILBOX_MESSAGE(M) (InterruptHost_mailboxBaseAddr + 0x040 + (0x4 * M))
67 #define MAILBOX_STATUS(M) (InterruptHost_mailboxBaseAddr + 0x0C0 + (0x4 * M))
69 #define MAILBOX_REG_VAL(M) (0x1 << (2 * M))
71 #define MAILBOX_IRQSTATUS_CLR_HOST (InterruptHost_mailboxBaseAddr + 0x104)
72 #define MAILBOX_IRQENABLE_SET_HOST (InterruptHost_mailboxBaseAddr + 0x108)
73 #define MAILBOX_IRQENABLE_CLR_HOST (InterruptHost_mailboxBaseAddr + 0x10C)
75 #define HOSTINT 77
76 #define M3VIDEOINT 53
77 #define M3DSSINT 54
78 #define DSPINT 56
80 /*
81 *************************************************************************
82 * Module functions
83 *************************************************************************
84 */
86 /*!
87 * ======== InterruptHost_intEnable ========
88 * Enable remote processor interrupt
89 */
90 Void InterruptHost_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
91 {
92 if (remoteProcId == InterruptHost_dspProcId) {
93 REG32(MAILBOX_IRQENABLE_SET_HOST) = MAILBOX_REG_VAL(DSP_TO_HOST);
94 }
95 else if (remoteProcId == InterruptHost_videoProcId) {
96 REG32(MAILBOX_IRQENABLE_SET_HOST) = MAILBOX_REG_VAL(VIDEO_TO_HOST);
97 }
98 else if (remoteProcId == InterruptHost_vpssProcId) {
99 REG32(MAILBOX_IRQENABLE_SET_HOST) = MAILBOX_REG_VAL(VPSS_TO_HOST);
100 }
101 else {
102 Assert_isTrue(FALSE, ti_sdo_ipc_Ipc_A_internal);
103 }
104 }
106 /*!
107 * ======== InterruptHost_intDisable ========
108 * Disables remote processor interrupt
109 */
110 Void InterruptHost_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
111 {
112 if (remoteProcId == InterruptHost_dspProcId) {
113 REG32(MAILBOX_IRQENABLE_CLR_HOST) = MAILBOX_REG_VAL(DSP_TO_HOST);
114 }
115 else if (remoteProcId == InterruptHost_videoProcId) {
116 REG32(MAILBOX_IRQENABLE_CLR_HOST) = MAILBOX_REG_VAL(VIDEO_TO_HOST);
117 }
118 else if (remoteProcId == InterruptHost_vpssProcId) {
119 REG32(MAILBOX_IRQENABLE_CLR_HOST) = MAILBOX_REG_VAL(VPSS_TO_HOST);
120 }
121 else {
122 Assert_isTrue(FALSE, ti_sdo_ipc_Ipc_A_internal);
123 }
124 }
126 /*!
127 * ======== InterruptHost_intRegister ========
128 */
129 Void InterruptHost_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
130 Fxn func, UArg arg)
131 {
132 UInt key;
133 Int index;
134 InterruptHost_FxnTable *table;
136 if (remoteProcId == InterruptHost_dspProcId) {
137 index = 0;
138 }
139 else if (remoteProcId == InterruptHost_videoProcId) {
140 index = 1;
141 }
142 else if (remoteProcId == InterruptHost_vpssProcId) {
143 index = 2;
144 }
145 else {
146 Assert_isTrue(FALSE, ti_sdo_ipc_Ipc_A_internal);
147 return; /* keep Coverity happy */
148 }
150 /* Disable global interrupts */
151 key = Hwi_disable();
153 table = &(InterruptHost_module->fxnTable[index]);
154 table->func = func;
155 table->arg = arg;
157 InterruptHost_intClear(remoteProcId, intInfo);
159 /* Make sure the interrupt only gets plugged once */
160 InterruptHost_module->numPlugged++;
161 if (InterruptHost_module->numPlugged == 1) {
162 Hwi_create(HOSTINT,
163 (Hwi_FuncPtr)InterruptHost_intShmStub,
164 NULL,
165 NULL);
166 Hwi_enableInterrupt(HOSTINT);
167 }
169 /* Enable the mailbox interrupt to the HOST core */
170 InterruptHost_intEnable(remoteProcId, intInfo);
172 /* Restore global interrupts */
173 Hwi_restore(key);
174 }
176 /*!
177 * ======== InterruptHost_intUnregister ========
178 */
179 Void InterruptHost_intUnregister(UInt16 remoteProcId,
180 IInterrupt_IntInfo *intInfo)
181 {
182 Hwi_Handle hwiHandle;
183 Int index;
184 InterruptHost_FxnTable *table;
186 if (remoteProcId == InterruptHost_hostProcId) {
187 index = 0;
188 }
189 else if (remoteProcId == InterruptHost_videoProcId) {
190 index = 1;
191 }
192 else if (remoteProcId == InterruptHost_vpssProcId) {
193 index = 2;
194 }
195 else {
196 Assert_isTrue(FALSE, ti_sdo_ipc_Ipc_A_internal);
197 return; /* keep Coverity happy */
198 }
200 /* Disable the mailbox interrupt source */
201 InterruptHost_intDisable(remoteProcId, intInfo);
203 InterruptHost_module->numPlugged--;
204 if (InterruptHost_module->numPlugged == 0) {
205 /* Delete the Hwi */
206 hwiHandle = Hwi_getHandle(HOSTINT);
207 Hwi_delete(&hwiHandle);
208 }
210 table = &(InterruptHost_module->fxnTable[index]);
211 table->func = NULL;
212 table->arg = 0;
213 }
215 /*!
216 * ======== InterruptHost_intSend ========
217 * Send interrupt to the remote processor
218 */
219 Void InterruptHost_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
220 UArg arg)
221 {
222 UInt key;
224 /*
225 * Before writing to a mailbox, check whehter it already contains a message
226 * If so, then don't write to the mailbox since we want one and only one
227 * message per interrupt. Disable interrupts between reading
228 * the MSGSTATUS_X register and writing to the mailbox to protect from
229 * another thread doing an intSend at the same time
230 *
231 * Note regarding possible race condition between local 'intSend' and
232 * remote 'intClear':
233 * It is possible that we we read the MAILBOX_MSGSTATUS_X register during
234 * the remote side's intClear. Therefore, we might choose _not_ to send
235 * write to the mailbox even though the mailbox is about to be cleared a
236 * few cycles later. In this case, the interrupt will be lost.
237 * This is OK, however. intClear should always be called by the Notify
238 * driver _before_ shared memory is read, so the event will be picked up
239 * anyway by the previous interrupt that caused intClear to be called.
240 */
241 if (remoteProcId == InterruptHost_dspProcId) {
242 key = Hwi_disable();
243 if (REG32(MAILBOX_STATUS(HOST_TO_DSP)) == 0) {
244 REG32(MAILBOX_MESSAGE(HOST_TO_DSP)) = arg;
245 }
246 Hwi_restore(key);
247 }
248 else if (remoteProcId == InterruptHost_videoProcId) {
249 key = Hwi_disable();
250 if (REG32(MAILBOX_STATUS(HOST_TO_VIDEO)) == 0) {
251 REG32(MAILBOX_MESSAGE(HOST_TO_VIDEO)) = arg;
252 }
253 Hwi_restore(key);
254 }
255 else { /* VPSS-M3 */
256 key = Hwi_disable();
257 if (REG32(MAILBOX_STATUS(HOST_TO_VPSS)) == 0) {
258 REG32(MAILBOX_MESSAGE(HOST_TO_VPSS)) = arg;
259 }
260 Hwi_restore(key);
261 }
262 }
264 /*!
265 * ======== InterruptHost_intPost ========
266 */
267 Void InterruptHost_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
268 UArg arg)
269 {
270 UInt key;
272 if (srcProcId == InterruptHost_vpssProcId) {
273 key = Hwi_disable();
274 if (REG32(MAILBOX_STATUS(VPSS_TO_HOST)) == 0) {
275 REG32(MAILBOX_MESSAGE(VPSS_TO_HOST)) = arg;
276 }
277 Hwi_restore(key);
278 }
279 else if (srcProcId == InterruptHost_videoProcId) {
280 key = Hwi_disable();
281 if (REG32(MAILBOX_STATUS(VIDEO_TO_HOST)) == 0) {
282 REG32(MAILBOX_MESSAGE(VIDEO_TO_HOST)) = arg;
283 }
284 Hwi_restore(key);
285 }
286 else { /* dspProcId */
287 key = Hwi_disable();
288 if (REG32(MAILBOX_STATUS(DSP_TO_HOST)) == 0) {
289 REG32(MAILBOX_MESSAGE(DSP_TO_HOST)) = arg;
290 }
291 Hwi_restore(key);
292 }
293 }
295 /*!
296 * ======== InterruptHost_intClear ========
297 * Clear interrupt
298 */
299 UInt InterruptHost_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
300 {
301 UInt arg;
303 if (remoteProcId == InterruptHost_dspProcId) {
304 arg = REG32(MAILBOX_MESSAGE(DSP_TO_HOST));
305 REG32(MAILBOX_IRQSTATUS_CLR_HOST) = MAILBOX_REG_VAL(DSP_TO_HOST);
306 }
307 else if (remoteProcId == InterruptHost_videoProcId) {
308 arg = REG32(MAILBOX_MESSAGE(VIDEO_TO_HOST));
309 REG32(MAILBOX_IRQSTATUS_CLR_HOST) = MAILBOX_REG_VAL(VIDEO_TO_HOST);
310 }
311 else { /* VPSS-M3 */
312 arg = REG32(MAILBOX_MESSAGE(VPSS_TO_HOST));
313 REG32(MAILBOX_IRQSTATUS_CLR_HOST) = MAILBOX_REG_VAL(VPSS_TO_HOST);
314 }
316 // /* Write to EOI (End Of Interrupt) register */
317 // REG32(MAILBOX_EOI_REG) = 0x1;
318 // Hwi_intc.ISR_CLEAR2 = (1 << (HOSTINT - 64));
320 return (arg);
321 }
323 /*
324 *************************************************************************
325 * Internals functions
326 *************************************************************************
327 */
329 /*!
330 * ======== InterruptHost_intShmStub ========
331 */
332 Void InterruptHost_intShmStub(UArg arg)
333 {
334 InterruptHost_FxnTable *table;
336 /* Process messages from the DSP */
337 if ((REG32(MAILBOX_IRQENABLE_SET_HOST) & MAILBOX_REG_VAL(DSP_TO_HOST))
338 && REG32(MAILBOX_STATUS(DSP_TO_HOST)) != 0) {
339 table = &(InterruptHost_module->fxnTable[0]);
340 (table->func)(table->arg);
341 }
343 /* Process messages from VIDEO */
344 if ((REG32(MAILBOX_IRQENABLE_SET_HOST) & MAILBOX_REG_VAL(VIDEO_TO_HOST))
345 && REG32(MAILBOX_STATUS(VIDEO_TO_HOST)) != 0) {
346 table = &(InterruptHost_module->fxnTable[1]);
347 (table->func)(table->arg);
348 }
350 /* Process messages from VPSS */
351 if ((REG32(MAILBOX_IRQENABLE_SET_HOST) & MAILBOX_REG_VAL(VPSS_TO_HOST))
352 && REG32(MAILBOX_STATUS(VPSS_TO_HOST)) != 0) {
353 table = &(InterruptHost_module->fxnTable[2]);
354 (table->func)(table->arg);
355 }
356 }