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 */
33 /*
34 * ======== NotifySetup.c ========
35 */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Error.h>
39 #include <xdc/runtime/Startup.h>
41 #include <ti/sdo/ipc/_Notify.h>
42 #include <ti/sdo/ipc/family/am65xx/NotifyDriverMbx.h>
43 #include <ti/sdo/ipc/notifyDrivers/NotifyDriverShm.h>
44 #include <ti/sdo/utils/_MultiProc.h>
46 #if defined(xdc_target__isaCompatible_v7R)
48 #include <ti/sysbios/BIOS.h>
49 #include <ti/sysbios/family/arm/v7r/keystone3/Hwi.h>
50 #include <ti/sysbios/family/arm/v7r/keystone3/Core.h>
52 #elif defined(xdc_target__isaCompatible_v8A)
53 #include <ti/sysbios/family/arm/gicv3/Hwi.h>
54 #else
55 #error Invalid target
56 #endif
58 #include "package/internal/NotifySetup.xdc.h"
61 #define EVENT_GROUP_SIZE 32
63 /* register access methods */
64 #define REG16(A) (*(volatile UInt16 *)(A))
65 #define REG32(A) (*(volatile UInt32 *)(A))
67 /* ipc helper macros */
68 #define MAILBOX_REG_VAL(m) (0x1 << (2 * (m)))
70 #define VIRTID(procId) (NotifySetup_procIdTable[(procId)])
72 #define MBX_BASEADDR_IDX(idx) ((NotifySetup_mailboxTable[(idx)] >> 16) & 0xFFFF)
74 #define MBX_USER_IDX(idx) ((NotifySetup_mailboxTable[(idx)] >> 8) & 0xFF)
76 #define SUBMBX_IDX(idx) (NotifySetup_mailboxTable[(idx)] & 0xFF)
78 #define MAILBOX_ADDR(idx) \
79 (NotifySetup_mailboxBaseAddr[MBX_BASEADDR_IDX(idx)])
81 #define MAILBOX_STATUS(idx) \
82 (MAILBOX_ADDR((idx)) + 0xC0 + (0x4 * SUBMBX_IDX((idx))))
84 #define MAILBOX_IRQENABLE_SET(idx) \
85 (MAILBOX_ADDR((idx)) + 0x108 + (0x10 * MBX_USER_IDX((idx))))
87 #define MBOX_IRQ_ENABLE(idx) \
88 ((REG32(MAILBOX_IRQENABLE_SET((idx))) & \
89 MAILBOX_REG_VAL(SUBMBX_IDX((idx)))) != 0)
91 #define MBOX_MSG_COUNT(idx) (REG32(MAILBOX_STATUS((idx))))
93 #define M2M_LVL_INT_RTR_BASE 0x00A10000
94 #define M2M_LV_INT_ICR0_OFFSET 0x4
95 #define NAVSS_INT_RTR_BASE 0x310E0000
96 #define NAVSS_INT_ICR0_OFFSET 0x4
98 /* Corresponds to VIM: 160 */
99 #define M2M_LVL_INT_RTR_OUTPUT_R5F0_0 0
100 /* Corresponds to VIM: 161 */
101 #define M2M_LVL_INT_RTR_OUTPUT_R5F0_1 1
102 /* Corresponds to VIM: 162 */
103 #define M2M_LVL_INT_RTR_OUTPUT_R5F1_0 2
104 /* Corresponds to VIM: 163 */
105 #define M2M_LVL_INT_RTR_OUTPUT_R5F1_1 3
107 #define NAVSS_INT_RTR_INPUT_MAILBOX0_USER0 436
108 #define NAVSS_INT_RTR_INPUT_MAILBOX0_USER1 437
110 #define NAVSS_INT_RTR_INPUT_MAILBOX1_USER0 432
111 #define NAVSS_INT_RTR_INPUT_MAILBOX1_USER1 433
113 #define NAVSS_INT_RTR_INPUT_MAILBOX2_USER0 428
114 #define NAVSS_INT_RTR_INPUT_MAILBOX2_USER1 429
116 /* Corresponds to GIC: 496 */
117 #define NAVSS_INT_RTR_OUTPUT_A53_0 112
118 /* Corresponds to GIC: 497 */
119 #define NAVSS_INT_RTR_OUTPUT_A53_1 113
121 #define NAVSS_INT_RTR_OUTPUT_R5F0_0 120
122 #define NAVSS_INT_RTR_OUTPUT_R5F1_0 121
123 #define NAVSS_INT_RTR_OUTPUT_R5F0_1 122
124 #define NAVSS_INT_RTR_OUTPUT_R5F1_1 123
126 /* The following INPUT is connected to NAVSS OUTPUT 120 */
127 #define M2M_LVL_INT_RTR_INPUT_A53_PEND_120 184
128 /* The following INPUT is connected to NAVSS OUTPUT 121 */
129 #define M2M_LVL_INT_RTR_INPUT_A53_PEND_121 185
131 /* The following INPUT is connected to NAVSS OUTPUT 122 */
132 #define M2M_LVL_INT_RTR_INPUT_A53_PEND_122 186
133 /* The following INPUT is connected to NAVSS OUTPUT 123 */
134 #define M2M_LVL_INT_RTR_INPUT_A53_PEND_123 187
136 static inline void connect_m2m_lvl_int_rtr(UInt32 input_evt, UInt32 output_line)
137 {
138 #ifdef INTERRUPT_ROUTING_THROUGH_DMSC
139 /* TODO: Need to add code to configure routing through DMSC */
140 #else
141 /* TODO: Eventually the interrupt routing below cannot be done
142 * directly. Need to go through DMSC. Currently this is done
143 * directly to help Pre-silicon testing
144 */
145 *((UInt32 *)(M2M_LVL_INT_RTR_BASE + M2M_LV_INT_ICR0_OFFSET) + output_line) = input_evt;
146 #endif
147 }
149 static inline void connect_navss_int_rtr(UInt32 input_evt, UInt32 output_line)
150 {
151 #ifdef INTERRUPT_ROUTING_THROUGH_DMSC
152 /* TODO: Need to add code to configure routing through DMSC */
153 #else
154 /* TODO: Eventually the interrupt routing below cannot be done
155 * directly. Need to go through DMSC. Currently this is done
156 * directly to help Pre-silicon testing
157 */
158 *((UInt32 *)(NAVSS_INT_RTR_BASE + NAVSS_INT_ICR0_OFFSET) + output_line) = input_evt;
159 #endif
160 }
162 /*
163 *************************************************************************
164 * Module functions
165 *************************************************************************
166 */
168 /*
169 * ======== NotifySetup_Module_startup ========
170 */
171 Int NotifySetup_Module_startup(Int phase)
172 {
173 #if defined(xdc_target__isaCompatible_v7R)
174 /* connect mailbox interrupts at startup */
175 if ((Core_getId() == 0)) {
176 /* R5F-0 */
177 /* Navss mailbox 0 User 1 */
178 /* Configure NAVSS interrupt router */
179 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX0_USER1,
180 NAVSS_INT_RTR_OUTPUT_R5F0_0);
181 /* Configure MCU level interrupt router */
182 connect_m2m_lvl_int_rtr(M2M_LVL_INT_RTR_INPUT_A53_PEND_120,
183 M2M_LVL_INT_RTR_OUTPUT_R5F0_0);
185 /* plug mbx2 only if R5F-1 exists */
186 if ((MultiProc_getId("R5F-1") != MultiProc_INVALIDID)) {
187 /* Navss mailbox 2 User 0 */
188 /* Configure NAVSS interrupt router */
189 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX2_USER0,
190 NAVSS_INT_RTR_OUTPUT_R5F0_1);
191 /* Configure MCU level interrupt router */
192 connect_m2m_lvl_int_rtr(M2M_LVL_INT_RTR_INPUT_A53_PEND_121,
193 M2M_LVL_INT_RTR_OUTPUT_R5F0_1);
194 }
195 }
196 else { /* R5F-1 */
197 /* Navss mailbox 1 User 1 */
198 /* Configure NAVSS interrupt router */
199 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX1_USER1,
200 NAVSS_INT_RTR_OUTPUT_R5F1_0);
201 /* Configure MCU level interrupt router */
202 connect_m2m_lvl_int_rtr(M2M_LVL_INT_RTR_INPUT_A53_PEND_122,
203 M2M_LVL_INT_RTR_OUTPUT_R5F1_1);
205 /* plug mbx2 only if R5F-0 exists */
206 if ((MultiProc_getId("R5F-0") != MultiProc_INVALIDID)) {
207 /* Navss mailbox 2 User 1 */
208 /* Configure NAVSS interrupt router */
209 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX2_USER1,
210 NAVSS_INT_RTR_OUTPUT_R5F1_1);
211 /* Configure MCU level interrupt router */
212 connect_m2m_lvl_int_rtr(M2M_LVL_INT_RTR_INPUT_A53_PEND_123,
213 M2M_LVL_INT_RTR_OUTPUT_R5F1_1);
214 }
215 }
216 return (Startup_DONE);
218 #elif defined(xdc_target__isaCompatible_v8A)
219 /* Navss mailbox 0 User 0 */
220 /* Configure NAVSS interrupt router */
221 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX0_USER0,
222 NAVSS_INT_RTR_OUTPUT_A53_0);
223 /* Navss mailbox 1 User 0 */
224 /* Configure NAVSS interrupt router */
225 connect_navss_int_rtr(NAVSS_INT_RTR_INPUT_MAILBOX1_USER0,
226 NAVSS_INT_RTR_OUTPUT_A53_1);
227 return (Startup_DONE);
229 #else
230 #error Invalid target
231 #endif
232 }
234 /*
235 * ======== NotifySetup_interruptTable ========
236 */
237 UInt16 NotifySetup_interruptTable(Int srcVirtId)
238 {
239 return (NotifySetup_module->interruptTable[srcVirtId]);
240 }
242 /*
243 * ======== NotifySetup_attach ========
244 * Create driver instance specified at config time.
245 *
246 * This functions is generated by the NotifySetup.xdt template.
247 */
249 /*
250 * ======== NotifySetup_sharedMemReq ========
251 * Compute how much shared memory is required by the driver.
252 *
253 * This functions is generated by the NotifySetup.xdt template.
254 */
256 /*
257 * ======== NotifySetup_numIntLines ========
258 * Return number of available interrupt lines to the current processor.
259 */
260 UInt16 NotifySetup_numIntLines(UInt16 remoteProcId)
261 {
262 return (1);
263 }
265 /*
266 * ======== NotifySetup_driverType ========
267 * Find driver type for given connection.
268 *
269 * Search the connection array for the given remote processor. If
270 * found, return the requested notify driver type.
271 */
272 NotifySetup_Driver NotifySetup_driverType(UInt16 remoteProcId)
273 {
274 Int i;
275 NotifySetup_Driver driver = NotifySetup_Driver_SHAREDMEMORY;
277 /* look for remote processor in connection array */
278 for (i = 0; i < NotifySetup_module->connAry.length; i++) {
279 if (remoteProcId == NotifySetup_module->connAry.elem[i].procId) {
280 driver = NotifySetup_module->connAry.elem[i].driver;
281 break;
282 }
283 }
285 return (driver);
286 }
288 /*
289 * ======== NotifySetup_plugHwi ========
290 */
291 Void NotifySetup_plugHwi(UInt16 remoteProcId, Int cpuIntrNum,
292 NotifySetup_DriverIsr isr)
293 {
294 Error_Block eb;
295 UInt key;
296 Hwi_Params hwiParams;
297 UInt16 srcVirtId;
298 #if defined(xdc_target__isaCompatible_v7R) \
299 || defined(xdc_target__isaCompatible_v8A)
300 UInt16 idx;
301 UInt mbxIdx;
302 #endif
304 Error_init(&eb);
306 /* disable interrupts */
307 key = Hwi_disable();
309 /* map remote processor id to virtual id */
310 srcVirtId = VIRTID(remoteProcId);
312 /* save driver ISR in dispatch table */
313 NotifySetup_module->isrDispatchTable[srcVirtId] = isr;
315 #if defined(xdc_target__isaCompatible_v7R) \
316 || defined(xdc_target__isaCompatible_v8A)
318 /* compute table index for given source and destination */
319 idx = (srcVirtId * NotifySetup_NUM_CORES) + VIRTID(MultiProc_self());
321 /* compute mailbox index */
322 mbxIdx = MBX_BASEADDR_IDX(idx);
324 /* make sure the interrupt is plugged only once */
325 NotifySetup_module->numPlugged[mbxIdx]++;
327 if (NotifySetup_module->numPlugged[mbxIdx] == 1) {
329 Hwi_Params_init(&hwiParams);
330 hwiParams.maskSetting = Hwi_MaskingOption_LOWER;
331 hwiParams.arg = cpuIntrNum;
333 Hwi_create(cpuIntrNum, NotifySetup_dispatchIsr, &hwiParams, &eb);
334 /* TODO: add error handling */
336 Hwi_enableInterrupt(cpuIntrNum);
337 }
339 #else
340 #error Invalid target
341 #endif
343 /* restore interrupts */
344 Hwi_restore(key);
345 }
347 /*
348 * ======== NotifySetup_unplugHwi ========
349 */
350 Void NotifySetup_unplugHwi(UInt16 remoteProcId, Int cpuIntrNum)
351 {
352 UInt key;
353 Hwi_Handle hwi;
354 UInt16 srcVirtId;
355 #if defined(xdc_target__isaCompatible_v7R) \
356 || defined(xdc_target__isaCompatible_v8A)
357 UInt16 idx;
358 UInt mbxIdx;
359 #endif
361 /* disable global interrupts (TODO: should be a gated module) */
362 key = Hwi_disable();
364 /* map processor id to virtual id */
365 srcVirtId = VIRTID(remoteProcId);
367 /* remove driver isr from dispatch table */
368 NotifySetup_module->isrDispatchTable[srcVirtId] = NULL;
370 #if defined(xdc_target__isaCompatible_v7R) \
371 || defined(xdc_target__isaCompatible_v8A)
373 /* decrement plug count */
374 idx = (srcVirtId * NotifySetup_NUM_CORES) + VIRTID(MultiProc_self());
375 mbxIdx = MBX_BASEADDR_IDX(idx);
376 NotifySetup_module->numPlugged[mbxIdx]--;
378 /* unplug interrupt if last user */
379 if (NotifySetup_module->numPlugged[0] == 0) {
380 hwi = Hwi_getHandle(cpuIntrNum);
381 Hwi_delete(&hwi);
382 }
384 #else
385 #error Invalid target
386 #endif
388 /* restore global interrupts */
389 Hwi_restore(key);
390 }
392 /*
393 * ======== NotifySetup_Shm_attach ========
394 */
395 Int NotifySetup_Shm_attach(UInt16 remoteProcId, Ptr sharedAddr)
396 {
397 NotifyDriverShm_Params notifyShmParams;
398 NotifyDriverShm_Handle shmDrvHandle;
399 ti_sdo_ipc_Notify_Handle notifyHandle;
400 Int status = Notify_S_SUCCESS;
401 Error_Block eb;
403 Error_init(&eb);
405 NotifyDriverShm_Params_init(¬ifyShmParams);
406 notifyShmParams.sharedAddr = sharedAddr;
407 notifyShmParams.remoteProcId = remoteProcId;
409 /* create the notify driver instance */
410 shmDrvHandle = NotifyDriverShm_create(¬ifyShmParams, &eb);
412 if (shmDrvHandle == NULL) {
413 return (Notify_E_FAIL);
414 }
416 /* create the front-end notify instance */
417 notifyHandle = ti_sdo_ipc_Notify_create(
418 NotifyDriverShm_Handle_upCast(shmDrvHandle), remoteProcId, 0,
419 NULL, &eb);
421 if (notifyHandle == NULL) {
422 NotifyDriverShm_delete(&shmDrvHandle);
423 status = Notify_E_FAIL;
424 }
426 return (status);
427 }
429 /*!
430 * ======== NotifySetup_Shm_sharedMemReq ========
431 */
432 SizeT NotifySetup_Shm_sharedMemReq(UInt16 remoteProcId, Ptr sharedAddr)
433 {
434 SizeT memReq;
435 NotifyDriverShm_Params notifyShmParams;
437 NotifyDriverShm_Params_init(¬ifyShmParams);
438 notifyShmParams.sharedAddr = sharedAddr;
440 memReq = NotifyDriverShm_sharedMemReq(¬ifyShmParams);
442 return (memReq);
443 }
445 /*
446 * ======== NotifySetup_Mbx_attach ========
447 */
448 Int NotifySetup_Mbx_attach(UInt16 remoteProcId, Ptr sharedAddr)
449 {
450 Int status = Notify_S_SUCCESS;
451 NotifyDriverMbx_Params params;
452 NotifyDriverMbx_Handle driver;
453 ti_sdo_ipc_Notify_Handle notify;
454 UInt16 virtId;
455 Error_Block eb;
457 Error_init(&eb);
459 NotifyDriverMbx_Params_init(¶ms);
460 params.remoteProcId = remoteProcId;
462 /* set the intVectorId if on the R5F */
463 if ((MultiProc_self() == NotifySetup_r5f_0ProcId) ||
464 (MultiProc_self() == NotifySetup_r5f_1ProcId)) {
466 virtId = VIRTID(remoteProcId);
467 params.intVectorId = NotifySetup_module->interruptTable[virtId];
468 }
470 /* set the intVectorId if on the HOST */
471 if (MultiProc_self() == NotifySetup_hostProcId) {
472 virtId = VIRTID(remoteProcId);
473 params.intVectorId = NotifySetup_module->interruptTable[virtId];
474 }
476 /* create the notify driver instance */
477 driver = NotifyDriverMbx_create(¶ms, &eb);
479 if (driver == NULL) {
480 return (Notify_E_FAIL);
481 }
483 /* create the front-end notify instance */
484 notify = ti_sdo_ipc_Notify_create(NotifyDriverMbx_Handle_upCast(driver),
485 remoteProcId, 0, NULL, &eb);
487 if (notify == NULL) {
488 NotifyDriverMbx_delete(&driver);
489 status = Notify_E_FAIL;
490 }
492 return (status);
493 }
495 /*!
496 * ======== NotifySetup_Mbx_sharedMemReq ========
497 */
498 SizeT NotifySetup_Mbx_sharedMemReq(UInt16 remoteProcId, Ptr sharedAddr)
499 {
500 SizeT memReq = 0;
502 return (memReq);
503 }
505 /*
506 *************************************************************************
507 * Internal functions
508 *************************************************************************
509 */
511 /*
512 * ======== NotifySetup_dispatchIsr ========
513 * Dispatch the current interrupt to the appropriate notify driver
514 *
515 * The given interrupt may be shared by multiple notify drivers. This
516 * ISR inspects the mailbox which raised the interrupt and looks for
517 * all FIFOs which have data and raise the given interrupt. For each
518 * one, the interrupt is dispatched to the registered driver for that
519 * FIFO.
520 *
521 * @param(arg) The eventId which raised the interrupt.
522 */
523 Void NotifySetup_dispatchIsr(UArg arg)
524 {
525 Int numProcessed;
526 UInt16 idx;
527 UInt16 srcVirtId;
528 UInt16 dstVirtId = VIRTID(MultiProc_self());
529 NotifySetup_DriverIsr driver;
531 do {
532 numProcessed = 0;
534 for (srcVirtId = 0; srcVirtId < NotifySetup_NUM_CORES; srcVirtId++) {
536 /* skip null drivers, processor not in system or self */
537 driver = NotifySetup_module->isrDispatchTable[srcVirtId];
539 if (driver == NULL) {
540 continue;
541 }
543 /* check if processor would raise the given hardware eventId */
544 if (arg == NotifySetup_module->interruptTable[srcVirtId]) {
546 /* compute table index for given source and destination */
547 idx = (srcVirtId * NotifySetup_NUM_CORES) + dstVirtId;
549 /* check if submailbox has a message and irq is enabled */
550 if ((MBOX_MSG_COUNT(idx) != 0) && MBOX_IRQ_ENABLE(idx)) {
552 /* invoke driver isr to deliver the event */
553 (*driver)(idx);
555 /* event has been delivered */
556 numProcessed++;
557 }
558 }
559 }
560 } while (numProcessed != 0);
561 }