]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - packages/ti/sdo/ipc/family/arctic/InterruptDsp.c
Initial commit
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / arctic / InterruptDsp.c
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  */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Error.h>
41 #include <ti/sysbios/family/c64p/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/InterruptDsp.xdc.h"
49 /* Register access method. */
50 #define REG16(A)   (*(volatile UInt16 *) (A))
51 #define REG32(A)   (*(volatile UInt32 *) (A))
53 /* Assigned mailboxes */
54 #define DSP_TO_ARP32      0
55 #define ARP32_TO_DSP      1
57 #define MAILBOX_REG_VAL(M)   (0x1 << (2 * M))
59 #define MAILBOX_MESSAGE(M)   (InterruptDsp_mailboxBaseAddr + 0x40 + (0x4 * M))
60 #define MAILBOX_STATUS(M)    (InterruptDsp_mailboxBaseAddr + 0xC0 + (0x4 * M))
62 #define MBX_INTR_TO_ARP32 0
63 #define MBX_INTR_TO_DSP 1
65 #define MAILBOX_IRQSTATUS_CLR(INTR_NUM)  (InterruptDsp_mailboxBaseAddr + 0x104 + ((INTR_NUM) * 0x10))
67 #define MAILBOX_IRQENABLE_SET(INTR_NUM)  (InterruptDsp_mailboxBaseAddr + 0x108 + ((INTR_NUM) * 0x10))
69 #define MAILBOX_IRQENABLE_CLR(INTR_NUM)  (InterruptDsp_mailboxBaseAddr + 0x10C + ((INTR_NUM) * 0x10))
71 #define MAILBOX_EOI_REG             (InterruptDsp_mailboxBaseAddr + 0x140)
73 /*
74  *************************************************************************
75  *                      Module functions
76  *************************************************************************
77  */
79 /*!
80  *  ======== InterruptDsp_intEnable ========
81  *  Enable remote processor interrupt
82  */
83 Void InterruptDsp_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
84 {
85     REG32(MAILBOX_IRQENABLE_SET(MBX_INTR_TO_DSP)) = MAILBOX_REG_VAL(ARP32_TO_DSP);
86 }
88 /*!
89  *  ======== InterruptDsp_intDisable ========
90  *  Disables remote processor interrupt
91  */
92 Void InterruptDsp_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
93 {
94     REG32(MAILBOX_IRQENABLE_CLR(MBX_INTR_TO_DSP)) = MAILBOX_REG_VAL(ARP32_TO_DSP);
95 }
97 /*!
98  *  ======== InterruptDsp_intRegister ========
99  */
100 Void InterruptDsp_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
101                               Fxn func, UArg arg)
103     UInt        key;
104     Hwi_Params  hwiAttrs;
105     Error_Block eb;
106     InterruptDsp_FxnTable *table;
108     Assert_isTrue(intInfo->intVectorId <= 15, ti_sdo_ipc_Ipc_A_internal);
110     /* init error block */
111     Error_init(&eb);
113     /* Disable global interrupts */
114     key = Hwi_disable();
116     table = &(InterruptDsp_module->fxnTable);
117     table->func = func;
118     table->arg  = arg;
120     InterruptDsp_intClear(remoteProcId, intInfo);
122     /* Make sure the interrupt only gets plugged once */
123     InterruptDsp_module->numPlugged++;
124     if (InterruptDsp_module->numPlugged == 1) {
125         /* Register interrupt to remote processor */
126         Hwi_Params_init(&hwiAttrs);
127         hwiAttrs.arg = arg;
128         hwiAttrs.eventId = 90;
130         Hwi_create(intInfo->intVectorId,
131                    (Hwi_FuncPtr)InterruptDsp_intShmStub,
132                    &hwiAttrs,
133                    &eb);
135         /* enable the interrupt vector */
136         Hwi_enableInterrupt(intInfo->intVectorId);
137     }
139     /* Enable the mailbox interrupt to the DSP */
140     InterruptDsp_intEnable(remoteProcId, intInfo);
142     /* Restore global interrupts */
143     Hwi_restore(key);
146 /*!
147  *  ======== InterruptDsp_intUnregister ========
148  */
149 Void InterruptDsp_intUnregister(UInt16 remoteProcId,
150                                 IInterrupt_IntInfo *intInfo)
152     Hwi_Handle  hwiHandle;
153     InterruptDsp_FxnTable *table;
155     /* Disable the mailbox interrupt source */
156     InterruptDsp_intDisable(remoteProcId, intInfo);
158     InterruptDsp_module->numPlugged--;
159     if (InterruptDsp_module->numPlugged == 0) {
160         /* Delete the Hwi */
161         hwiHandle = Hwi_getHandle(intInfo->intVectorId);
162         Hwi_delete(&hwiHandle);
163     }
165     /* Clear the FxnTable entry for the remote processor */
166     table = &(InterruptDsp_module->fxnTable);
167     table->func = NULL;
168     table->arg  = 0;
171 /*!
172  *  ======== InterruptDsp_intSend ========
173  *  Send interrupt to the remote processor
174  */
175 Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
176                           UArg arg)
178     UInt key;
180     /*
181      *  Before writing to a mailbox, check whehter it already contains a message
182      *  If so, then don't write to the mailbox since we want one and only one
183      *  message per interrupt.  Disable interrupts between reading
184      *  the MSGSTATUS_X register and writing to the mailbox to protect from
185      *  another thread doing an intSend at the same time
186      *
187      *  Note regarding possible race condition between local 'intSend' and
188      *  remote 'intClear':
189      *  It is possible that we we read the MAILBOX_MSGSTATUS_X register during
190      *  the remote side's intClear.  Therefore, we might choose _not_ to send
191      *  write to the mailbox even though the mailbox is about to be cleared a
192      *  few cycles later. In this case, the interrupt will be lost.
193      *  This is OK, however. intClear should always be called by the Notify
194      *  driver _before_ shared memory is read, so the event will be picked up
195      *  anyway by the previous interrupt that caused intClear to be called.
196      */
197     key = Hwi_disable();
199     if (REG32(MAILBOX_STATUS(DSP_TO_ARP32)) == 0) {
200         /* write the mailbox message to arp32 */
201         REG32(MAILBOX_MESSAGE(DSP_TO_ARP32)) = arg;
202     }
204     /* restore interrupts */
205     Hwi_restore(key);
208 /*!
209  *  ======== InterruptDsp_intPost ========
210  */
211 Void InterruptDsp_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
212                           UArg arg)
214     UInt key;
216     /* disable interrupts */
217     key = Hwi_disable();
219     if (REG32(MAILBOX_STATUS(ARP32_TO_DSP)) == 0) {
220         /* write the mailbox message to dsp */
221         REG32(MAILBOX_MESSAGE(ARP32_TO_DSP)) = arg;
222     }
224     /* restore interrupts */
225     Hwi_restore(key);
228 /*!
229  *  ======== InterruptDsp_intClear ========
230  *  Clear interrupt
231  */
232 UInt InterruptDsp_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
234     UInt arg;
236     arg = REG32(MAILBOX_MESSAGE(ARP32_TO_DSP));
238     /* clear the dsp mailbox */
239     REG32(MAILBOX_IRQSTATUS_CLR(MBX_INTR_TO_DSP)) = MAILBOX_REG_VAL(ARP32_TO_DSP);
241     /* Write to EOI (End Of Interrupt) register */
242     REG32(MAILBOX_EOI_REG) = 0x1;
244     return (arg);
247 /*
248  *************************************************************************
249  *                      Internals functions
250  *************************************************************************
251  */
253 /*!
254  *  ======== InterruptDsp_intShmStub ========
255  */
256 Void InterruptDsp_intShmStub(UArg arg)
258     InterruptDsp_FxnTable *table;
260     if (((REG32(MAILBOX_IRQENABLE_SET(MBX_INTR_TO_DSP)) &
261         MAILBOX_REG_VAL(ARP32_TO_DSP)) &&
262         REG32(MAILBOX_STATUS(ARP32_TO_DSP))) != 0) {
263         /* call function with arg */
264         table = &(InterruptDsp_module->fxnTable);
265         (table->func)(table->arg);
266     }