1 /*
2 * Copyright (c) 2017-2018 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 * ======== InterruptR5f.c ========
34 * AM65XX R5F based interupt manager
35 */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
40 #include <ti/sysbios/BIOS.h>
41 #include <ti/sysbios/family/arm/v7r/keystone3/Core.h>
42 #include <ti/sysbios/family/arm/v7r/keystone3/Hwi.h>
44 #include <ti/sdo/ipc/family/am65xx/NotifySetup.h>
46 #include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
47 #include <ti/sdo/utils/_MultiProc.h>
49 #include "package/internal/InterruptR5f.xdc.h"
51 /* Register access method. */
52 #define REG16(A) (*(volatile UInt16 *) ((uintptr_t)A))
53 #define REG32(A) (*(volatile UInt32 *) ((uintptr_t)A))
55 #define PROCID(IDX) (InterruptR5f_procIdTable[(IDX)])
56 #define MBX_TABLE_IDX(SRC, DST) ((PROCID(SRC) * InterruptR5f_NUM_CORES) + \
57 PROCID(DST))
58 #define SUBMBX_IDX(IDX) (InterruptR5f_mailboxTable[(IDX)] & 0xFF)
59 #define MBX_USER_IDX(IDX) ((InterruptR5f_mailboxTable[(IDX)] >> 8) \
60 & 0xFF)
61 #define MBX_BASEADDR_IDX(IDX) ((InterruptR5f_mailboxTable[(IDX)] >> 16) \
62 & 0xFFFF)
64 #define MAILBOX_REG_VAL(M) (0x1 << (2 * M))
66 #define MAILBOX_MESSAGE(IDX) (InterruptR5f_mailboxBaseAddr[ \
67 MBX_BASEADDR_IDX(IDX)] + 0x40 + \
68 (0x4 * SUBMBX_IDX(IDX)))
69 #define MAILBOX_STATUS(IDX) (InterruptR5f_mailboxBaseAddr[ \
70 MBX_BASEADDR_IDX(IDX)] + 0xC0 + \
71 (0x4 * SUBMBX_IDX(IDX)))
73 #define MAILBOX_IRQSTATUS_CLR(IDX) (InterruptR5f_mailboxBaseAddr[ \
74 MBX_BASEADDR_IDX(IDX)] + (0x10 * \
75 MBX_USER_IDX(IDX)) + 0x104)
76 #define MAILBOX_IRQENABLE_SET(IDX) (InterruptR5f_mailboxBaseAddr[ \
77 MBX_BASEADDR_IDX(IDX)] + (0x10 * \
78 MBX_USER_IDX(IDX)) + 0x108)
79 #define MAILBOX_IRQENABLE_CLR(IDX) (InterruptR5f_mailboxBaseAddr[ \
80 MBX_BASEADDR_IDX(IDX)] + (0x10 * \
81 MBX_USER_IDX(IDX)) + 0x10C)
82 #define MAILBOX_EOI_REG(IDX) (InterruptR5f_mailboxBaseAddr[ \
83 MBX_BASEADDR_IDX(IDX)] + 0x140)
85 #define WUGENIPU 19
87 /*
88 *************************************************************************
89 * Module functions
90 *************************************************************************
91 */
93 /*
94 * ======== InterruptR5f_intEnable ========
95 * Enable remote processor interrupt
96 */
97 Void InterruptR5f_intEnable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
98 {
99 UInt16 index;
100 Bool useMailbox = TRUE;
101 UInt subMbxIdx;
103 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
105 if ((remoteProcId == InterruptR5f_r5f_0ProcId) ||
106 (remoteProcId == InterruptR5f_r5f_1ProcId)) {
107 Hwi_enableInterrupt(WUGENIPU);
108 useMailbox = FALSE;
109 }
111 /* If the remote processor communicates via mailboxes, we should enable
112 * the Mailbox IRQ instead of enabling the Hwi because multiple mailboxes
113 * share the same Hwi
114 */
115 if (useMailbox) {
116 subMbxIdx = SUBMBX_IDX(index);
117 REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(subMbxIdx);
118 }
119 }
121 /*
122 * ======== InterruptR5f_intDisable ========
123 * Disables remote processor interrupt
124 */
125 Void InterruptR5f_intDisable(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
126 {
127 UInt16 index;
128 Bool useMailbox = TRUE;
129 UInt subMbxIdx;
131 if ((remoteProcId == InterruptR5f_r5f_0ProcId) ||
132 (remoteProcId == InterruptR5f_r5f_1ProcId)) {
133 Hwi_disableInterrupt(WUGENIPU);
134 useMailbox = FALSE;
135 }
137 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
139 /* If the remote processor communicates via mailboxes, we should disable
140 * the Mailbox IRQ instead of disabling the Hwi because multiple mailboxes
141 * share the same Hwi
142 */
143 if (useMailbox) {
144 subMbxIdx = SUBMBX_IDX(index);
145 REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(subMbxIdx);
146 }
147 }
149 /*
150 * ======== InterruptR5f_intRegister ========
151 */
152 Void InterruptR5f_intRegister(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
153 Fxn func, UArg arg)
154 {
155 Hwi_Params hwiAttrs;
156 UInt key;
157 Int index;
158 InterruptR5f_FxnTable *table;
160 Assert_isTrue(remoteProcId < ti_sdo_utils_MultiProc_numProcessors,
161 ti_sdo_utils_MultiProc_A_invalidMultiProcId);
163 /* index is the virtual id (invariant) */
164 index = PROCID(remoteProcId);
166 intInfo->localIntId = NotifySetup_interruptTable(index);
168 /* Disable global interrupts */
169 key = Hwi_disable();
171 /* store callback function by virtual id */
172 table = &(InterruptR5f_module->fxnTable[index]);
173 table->func = func;
174 table->arg = arg;
176 InterruptR5f_intClear(remoteProcId, intInfo);
178 Hwi_Params_init(&hwiAttrs);
179 hwiAttrs.maskSetting = Hwi_MaskingOption_LOWER;
181 /* plug the cpu interrupt with notify setup dispatch isr */
182 NotifySetup_plugHwi(remoteProcId, intInfo->localIntId,
183 InterruptR5f_intShmMbxStub);
185 InterruptR5f_intEnable(remoteProcId, intInfo);
187 /* Restore global interrupts */
188 Hwi_restore(key);
189 }
191 /*
192 * ======== InterruptR5f_intUnregister ========
193 */
194 Void InterruptR5f_intUnregister(UInt16 remoteProcId,
195 IInterrupt_IntInfo *intInfo)
196 {
197 Int index;
198 Hwi_Handle hwiHandle;
199 InterruptR5f_FxnTable *table;
201 /* Disable the mailbox interrupt source */
202 InterruptR5f_intDisable(remoteProcId, intInfo);
204 if ((remoteProcId == InterruptR5f_r5f_0ProcId) ||
205 (remoteProcId == InterruptR5f_r5f_1ProcId)) {
206 hwiHandle = Hwi_getHandle(WUGENIPU);
207 Hwi_delete(&hwiHandle);
208 }
209 else {
210 NotifySetup_unplugHwi(remoteProcId, intInfo->localIntId);
211 }
213 /* index is the virtual id (invariant) */
214 index = PROCID(remoteProcId);
216 /* Clear the FxnTable entry for the remote processor */
217 table = &(InterruptR5f_module->fxnTable[index]);
218 table->func = NULL;
219 table->arg = 0;
220 }
223 /*
224 * ======== InterruptR5f_intSend ========
225 * Send interrupt to the remote processor
226 */
227 Void InterruptR5f_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
228 UArg arg)
229 {
230 UInt key;
231 UInt16 index;
233 index = MBX_TABLE_IDX(MultiProc_self(), remoteProcId);
234 key = Hwi_disable();
235 while (REG32(MAILBOX_STATUS(index)) != 0) {
236 Hwi_restore(key);
237 key = Hwi_disable();
238 }
239 REG32(MAILBOX_MESSAGE(index)) = arg;
240 Hwi_restore(key);
242 }
245 /*
246 * ======== InterruptR5f_intPost ========
247 * Simulate an interrupt from a remote processor
248 */
249 Void InterruptR5f_intPost(UInt16 srcProcId, IInterrupt_IntInfo *intInfo,
250 UArg arg)
251 {
252 UInt key;
253 UInt16 index;
255 index = MBX_TABLE_IDX(srcProcId, MultiProc_self());
256 key = Hwi_disable();
257 if (REG32(MAILBOX_STATUS(index)) == 0) {
258 REG32(MAILBOX_MESSAGE(index)) = arg;
259 }
260 Hwi_restore(key);
262 }
264 /*
265 * ======== InterruptR5f_intClear ========
266 * Clear interrupt
267 */
268 UInt InterruptR5f_intClear(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo)
269 {
270 UInt arg;
271 UInt16 index;
273 index = MBX_TABLE_IDX(remoteProcId, MultiProc_self());
274 arg = REG32(MAILBOX_MESSAGE(index));
275 REG32(MAILBOX_IRQSTATUS_CLR(index)) =
276 MAILBOX_REG_VAL(SUBMBX_IDX(index));
278 return (arg);
279 }
281 /*
282 *************************************************************************
283 * Internals functions
284 *************************************************************************
285 */
287 /*
288 * ======== InterruptR5f_intShmMbxStub ========
289 */
290 Void InterruptR5f_intShmMbxStub(UInt16 idx)
291 {
292 UInt16 srcVirtId;
293 InterruptR5f_FxnTable *table;
295 srcVirtId = idx / InterruptR5f_NUM_CORES;
296 table = &(InterruptR5f_module->fxnTable[srcVirtId]);
297 (table->func)(table->arg);
298 }