SDOCM00106584 Notify mailbox driver support on DRA7xx (IPU, HOST) - Part 1
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / vayu / InterruptIpu.c
1 /*
2  * Copyright (c) 2013-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  */
32 /*
33  *  ======== InterruptIpu.c ========
34  *  Vayu IPU based interupt manager
35  */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Startup.h>
41 #include <ti/sysbios/BIOS.h>
42 #include <ti/sysbios/family/shared/vayu/IntXbar.h>
43 #include <ti/sysbios/family/arm/m3/Hwi.h>
44 #include <ti/sysbios/family/arm/ducati/Core.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/InterruptIpu.xdc.h"
52 /* Register access method. */
53 #define REG16(A)   (*(volatile UInt16 *) (A))
54 #define REG32(A)   (*(volatile UInt32 *) (A))
56 /*
57  *  Ducati control register that maintains inter-core interrupt bits.
58  *
59  *  Using separate CORE0 and CORE1 values to do 16-bit reads/writes
60  *  because we do not want to overwrite the other cores value.
61  */
62 #define INTERRUPT_CORE0         (InterruptIpu_ducatiCtrlBaseAddr)
63 #define INTERRUPT_CORE1         (InterruptIpu_ducatiCtrlBaseAddr + 2)
65 #define PROCID(IDX)               (InterruptIpu_procIdTable[(IDX)])
66 #define MBX_TABLE_IDX(SRC, DST)   ((PROCID(SRC) * InterruptIpu_NUM_CORES) + \
67                                     PROCID(DST))
68 #define SUBMBX_IDX(IDX)           (InterruptIpu_mailboxTable[(IDX)] & 0xFF)
69 #define MBX_USER_IDX(IDX)         ((InterruptIpu_mailboxTable[(IDX)] >> 8) \
70                                     & 0xFF)
71 #define MBX_BASEADDR_IDX(IDX)    ((InterruptIpu_mailboxTable[(IDX)] >> 16) \
72                                     & 0xFFFF)
74 #define MAILBOX_REG_VAL(M)        (0x1 << (2 * M))
76 #define MAILBOX_MESSAGE(IDX)      (InterruptIpu_mailboxBaseAddr[  \
77                                     MBX_BASEADDR_IDX(IDX)] + 0x40 +   \
78                                     (0x4 * SUBMBX_IDX(IDX)))
79 #define MAILBOX_STATUS(IDX)       (InterruptIpu_mailboxBaseAddr[  \
80                                     MBX_BASEADDR_IDX(IDX)] + 0xC0 +   \
81                                     (0x4 * SUBMBX_IDX(IDX)))
83 #define MAILBOX_IRQSTATUS_CLR(IDX)   (InterruptIpu_mailboxBaseAddr[  \
84                                         MBX_BASEADDR_IDX(IDX)] + (0x10 * \
85                                         MBX_USER_IDX(IDX)) + 0x104)
86 #define MAILBOX_IRQENABLE_SET(IDX)   (InterruptIpu_mailboxBaseAddr[  \
87                                         MBX_BASEADDR_IDX(IDX)] + (0x10 * \
88                                         MBX_USER_IDX(IDX)) + 0x108)
89 #define MAILBOX_IRQENABLE_CLR(IDX)   (InterruptIpu_mailboxBaseAddr[  \
90                                         MBX_BASEADDR_IDX(IDX)] + (0x10 * \
91                                         MBX_USER_IDX(IDX)) + 0x10C)
92 #define MAILBOX_EOI_REG(IDX)         (InterruptIpu_mailboxBaseAddr[  \
93                                         MBX_BASEADDR_IDX(IDX)] + 0x140)
95 #define WUGENIPU        19
97 /*
98  *************************************************************************
99  *                      Module functions
100  *************************************************************************
101  */
103 /*
104  *  ======== InterruptIpu_intEnable ========
105  *  Enable remote processor interrupt
106  */
107 Void InterruptIpu_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
109     UInt16 index;
110     Bool useMailbox = TRUE;
111     UInt8 subMbxIdx;
113     index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
115     if (Core_ipuId == 1) {
116         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
117             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
118             Hwi_enableInterrupt(WUGENIPU);
119             useMailbox = FALSE;
120         }
121     }
122     else {
123         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
124             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
125             Hwi_enableInterrupt(WUGENIPU);
126             useMailbox = FALSE;
127         }
128     }
130     /*  If the remote processor communicates via mailboxes, we should enable
131      *  the Mailbox IRQ instead of enabling the Hwi because multiple mailboxes
132      *  share the same Hwi
133      */
134     if (useMailbox) {
135         subMbxIdx = SUBMBX_IDX(index);
136         REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(subMbxIdx);
137     }
140 /*
141  *  ======== InterruptIpu_intDisable ========
142  *  Disables remote processor interrupt
143  */
144 Void InterruptIpu_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
146     UInt16 index;
147     Bool useMailbox = TRUE;
148     UInt8 subMbxIdx;
150     if (Core_ipuId == 1) {
151         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
152             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
153             Hwi_disableInterrupt(WUGENIPU);
154             useMailbox = FALSE;
155         }
156     }
157     else {
158         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
159             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
160             Hwi_disableInterrupt(WUGENIPU);
161             useMailbox = FALSE;
162         }
163     }
165     index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
167     /*  If the remote processor communicates via mailboxes, we should disable
168      *  the Mailbox IRQ instead of disabling the Hwi because multiple mailboxes
169      *  share the same Hwi
170      */
171     if (useMailbox) {
172         subMbxIdx = SUBMBX_IDX(index);
173         REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(subMbxIdx);
174     }
177 /*
178  *  ======== InterruptIpu_intRegister ========
179  */
180 Void InterruptIpu_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
181         Fxn func, UArg arg)
183     Hwi_Params  hwiAttrs;
184     UInt        key;
185     Int         index;
186     InterruptIpu_FxnTable *table;
188     Assert_isTrue(remoteProcId < ti_sdo_utils_MultiProc_numProcessors,
189             ti_sdo_utils_MultiProc_A_invalidMultiProcId);
191     /* index is the virtual id (invariant) */
192     index = PROCID(remoteProcId);
194     intInfo->localIntId = NotifySetup_interruptTable(index);
196     /* Disable global interrupts */
197     key = Hwi_disable();
199     /* store callback function by virtual id */
200     table = &(InterruptIpu_module->fxnTable[index]);
201     table->func = func;
202     table->arg  = arg;
204     InterruptIpu_intClear(remoteProcId, intInfo);
206     Hwi_Params_init(&hwiAttrs);
207     hwiAttrs.maskSetting = Hwi_MaskingOption_LOWER;
209     if (Core_ipuId == 1) {
210         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
211             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
213             /* plug the cpu interrupt with local isr */
214             Hwi_create(intInfo->localIntId,
215                    (Hwi_FuncPtr)InterruptIpu_intShmDucatiStub,
216                    &hwiAttrs, NULL);
217         }
218         else {
219             /* plug the cpu interrupt with notify setup dispatch isr */
220             NotifySetup_plugHwi(remoteProcId, intInfo->localIntId,
221                     InterruptIpu_intShmMbxStub);
222         }
223     }
224     else {
225         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
226             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
227             Hwi_create(intInfo->localIntId,
228                    (Hwi_FuncPtr)InterruptIpu_intShmDucatiStub,
229                    &hwiAttrs, NULL);
230         }
231         else {
232             NotifySetup_plugHwi(remoteProcId, intInfo->localIntId,
233                     InterruptIpu_intShmMbxStub);
234         }
235     }
237     InterruptIpu_intEnable(remoteProcId, intInfo);
239     /* Restore global interrupts */
240     Hwi_restore(key);
243 /*
244  *  ======== InterruptIpu_intUnregister ========
245  */
246 Void InterruptIpu_intUnregister(UInt16 remoteProcId,
247         IInterrupt_IntInfo *intInfo)
249     Int                        index;
250     InterruptIpu_FxnTable *table;
251     Hwi_Handle                 hwiHandle;
253     /* index is the virtual id (invariant) */
254     index = PROCID(remoteProcId);
256     /* Disable the mailbox interrupt source */
257     InterruptIpu_intDisable(remoteProcId, intInfo);
259     if (Core_ipuId == 1) {
260         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
261             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
262             hwiHandle = Hwi_getHandle(WUGENIPU);
263             Hwi_delete(&hwiHandle);
264         }
265         else {
266             NotifySetup_unplugHwi(remoteProcId, intInfo->localIntId);
267         }
268     }
269     else {
270         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
271             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
272             hwiHandle = Hwi_getHandle(WUGENIPU);
273             Hwi_delete(&hwiHandle);
274         }
275         else {
276             NotifySetup_unplugHwi(remoteProcId, intInfo->localIntId);
277         }
278     }
280     /* Clear the FxnTable entry for the remote processor */
281     table = &(InterruptIpu_module->fxnTable[index]);
282     table->func = NULL;
283     table->arg  = 0;
287 /*
288  *  ======== InterruptIpu_intSend ========
289  *  Send interrupt to the remote processor
290  */
291 Void InterruptIpu_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
292                              UArg arg)
294     UInt key;
295     UInt16 index;
297     if (Core_ipuId == 1) {
298         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
299             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
300             if (!(BIOS_smpEnabled) && (Core_getId() == 1)) {
301                 /* CORE1 to CORE0 */
302                 REG16(INTERRUPT_CORE0) |= 0x1;
303             }
304             else {
305                 /* CORE0 to CORE1 */
306                 REG16(INTERRUPT_CORE1) |= 0x1;
307             }
308         }
309         else {
310             index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
311             key = Hwi_disable();
312             while (REG32(MAILBOX_STATUS(index)) != 0) {
313                 Hwi_restore(key);
314                 key = Hwi_disable();
315             }
316             REG32(MAILBOX_MESSAGE(index)) = arg;
317             Hwi_restore(key);
318         }
319     }
320     else {
321         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
322             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
323             if (!(BIOS_smpEnabled) && (Core_getId() == 1)) {
324                 /* CORE1 to CORE0 */
325                 REG16(INTERRUPT_CORE0) |= 0x1;
326             }
327             else {
328                 /* CORE0 to CORE1 */
329                 REG16(INTERRUPT_CORE1) |= 0x1;
330             }
331         }
332         else {
333             index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
334             key = Hwi_disable();
335             while (REG32(MAILBOX_STATUS(index)) != 0) {
336                 Hwi_restore(key);
337                 key = Hwi_disable();
338             }
339             REG32(MAILBOX_MESSAGE(index)) = arg;
340             Hwi_restore(key);
341         }
342     }
346 /*
347  *  ======== InterruptIpu_intPost ========
348  *  Simulate an interrupt from a remote processor
349  */
350 Void InterruptIpu_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
351                              UArg arg)
353     UInt key;
354     UInt16 index;
356     if (Core_ipuId == 1) {
357         if ((srcProcId == InterruptIpu_ipu1_0ProcId) ||
358             (srcProcId == InterruptIpu_ipu1_1ProcId)) {
359             if (!(BIOS_smpEnabled) && (Core_getId() == 1)) {
360                 /* CORE0 to CORE1 */
361                 REG16(INTERRUPT_CORE1) |= 0x1;
362             }
363             else {
364                 /* CORE1 to CORE0 */
365                 REG16(INTERRUPT_CORE0) |= 0x1;
366             }
367         }
368         else {
369             index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
370             key = Hwi_disable();
371             if (REG32(MAILBOX_STATUS(index)) == 0) {
372                 REG32(MAILBOX_MESSAGE(index)) = arg;
373             }
374             Hwi_restore(key);
375         }
376     }
377     else {
378         if ((srcProcId == InterruptIpu_ipu2_0ProcId) ||
379             (srcProcId == InterruptIpu_ipu2_1ProcId)) {
380             if (!(BIOS_smpEnabled) && (Core_getId() == 1)) {
381                 /* CORE0 to CORE1 */
382                 REG16(INTERRUPT_CORE1) |= 0x1;
383             }
384             else {
385                 /* CORE1 to CORE0 */
386                 REG16(INTERRUPT_CORE0) |= 0x1;
387             }
388         }
389         else {
390             index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
391             key = Hwi_disable();
392             if (REG32(MAILBOX_STATUS(index)) == 0) {
393                 REG32(MAILBOX_MESSAGE(index)) = arg;
394             }
395             Hwi_restore(key);
396         }
397     }
400 /*
401  *  ======== InterruptIpu_intClear ========
402  *  Clear interrupt
403  */
404 UInt InterruptIpu_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
406     UInt arg;
407     UInt16 index;
409     if (Core_ipuId == 1) {
410         if ((remoteProcId == InterruptIpu_ipu1_0ProcId) ||
411             (remoteProcId == InterruptIpu_ipu1_1ProcId)) {
412             arg = REG32(InterruptIpu_ducatiCtrlBaseAddr);
414             /* Look at BIOS's ducati Core id */
415             if ((BIOS_smpEnabled) || (Core_getId() == 0)) {
416                 if ((REG16(INTERRUPT_CORE0) & 0x1) == 0x1) {
417                     /* CORE1 to CORE0 */
418                     REG16(INTERRUPT_CORE0) &= ~(0x1);
419                 }
420             }
421             else {
422                 if ((REG16(INTERRUPT_CORE1) & 0x1) == 0x1) {
423                     /* CORE0 to CORE1 */
424                     REG16(INTERRUPT_CORE1) &= ~(0x1);
425                 }
426             }
427         }
428         else {
429             index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
430             arg = REG32(MAILBOX_MESSAGE(index));
431             REG32(MAILBOX_IRQSTATUS_CLR(index)) =
432                 MAILBOX_REG_VAL(SUBMBX_IDX(index));
433         }
434     }
435     else {
436         if ((remoteProcId == InterruptIpu_ipu2_0ProcId) ||
437             (remoteProcId == InterruptIpu_ipu2_1ProcId)) {
438             arg = REG32(InterruptIpu_ducatiCtrlBaseAddr);
440             /* Look at BIOS's ducati Core id */
441             if ((BIOS_smpEnabled) || (Core_getId() == 0)) {
442                 if ((REG16(INTERRUPT_CORE0) & 0x1) == 0x1) {
443                     /* CORE1 to CORE0 */
444                     REG16(INTERRUPT_CORE0) &= ~(0x1);
445                 }
446             }
447             else {
448                 if ((REG16(INTERRUPT_CORE1) & 0x1) == 0x1) {
449                     /* CORE0 to CORE1 */
450                     REG16(INTERRUPT_CORE1) &= ~(0x1);
451                 }
452             }
453         }
454         else {
455             index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
456             arg = REG32(MAILBOX_MESSAGE(index));
457             REG32(MAILBOX_IRQSTATUS_CLR(index)) =
458                 MAILBOX_REG_VAL(SUBMBX_IDX(index));
459         }
460     }
462     return (arg);
465 /*
466  *************************************************************************
467  *                      Internals functions
468  *************************************************************************
469  */
471  /*
472  *  ======== InterruptIpu_intShmDucatiStub ========
473  */
474 Void InterruptIpu_intShmDucatiStub(UArg arg)
476     UInt16 index;
477     InterruptIpu_FxnTable *table;
479     if (Core_ipuId == 1) {
480         if ((BIOS_smpEnabled) || (Core_getId() == 0)) {
481             index = 9;
482         }
483         else {
484             index = 6;
485         }
486     }
487     else {
488         if ((BIOS_smpEnabled) || (Core_getId() == 0)) {
489             index = 10;
490         }
491         else {
492             index = 7;
493         }
494     }
496     table = &(InterruptIpu_module->fxnTable[index]);
497     (table->func)(table->arg);
501 /*
502  *  ======== InterruptIpu_intShmMbxStub ========
503  */
504 Void InterruptIpu_intShmMbxStub(UInt16 idx)
506     UInt16 srcVirtId;
507     InterruptIpu_FxnTable *table;
509     srcVirtId = idx / InterruptIpu_NUM_CORES;
510     table = &(InterruptIpu_module->fxnTable[srcVirtId]);
511     (table->func)(table->arg);