4079163280c24bde330bd9f2ca8bc9913d06b321
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / am65xx / NotifyDriverMbx.c
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  *  ======== NotifyDriverMbx.c ========
35  */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Startup.h>
40 #if defined(xdc_target__isaCompatible_v7R)
42 #include <ti/sysbios/family/arm/v7r/keystone3/Hwi.h>
44 #elif defined(xdc_target__isaCompatible_v8A)
46 #include <ti/sysbios/family/arm/gicv3/Hwi.h>
48 #else
49 #error Invalid target
50 #endif
52 #include <ti/sdo/ipc/_Notify.h>
53 #include <ti/sdo/ipc/family/am65xx/NotifySetup.h>
54 #include <ti/sdo/utils/_MultiProc.h>
56 #include "package/internal/NotifyDriverMbx.xdc.h"
58 /* Bit mask operations */
59 #define SET_BIT(num,pos)            ((num) |= (1u << (pos)))
60 #define CLEAR_BIT(num,pos)          ((num) &= ~(1u << (pos)))
61 #define TEST_BIT(num,pos)           ((num) & (1u << (pos)))
63 /* register access methods */
64 #define REG16(A)        (*(volatile UInt16 *)(A))
65 #define REG32(A)        (*(volatile UInt32 *)(A))
67 #define MAILBOX_FIFOLENGTH 4
68 #define PROCID(idx) (NotifyDriverMbx_procIdTable[(idx)])
70 #define MBX_BASEADDR_IDX(idx) \
71         ((NotifyDriverMbx_mailboxTable[(idx)] >> 16) & 0xFFFF)
73 #define MAILBOX_ADDR(idx) \
74         (NotifyDriverMbx_mailboxBaseAddr[MBX_BASEADDR_IDX(idx)])
76 #define MBX_TABLE_IDX(src, dst) \
77         ((PROCID(src) * NotifyDriverMbx_NUM_CORES) + PROCID(dst))
79 #define SUBMBX_IDX(idx) (NotifyDriverMbx_mailboxTable[(idx)] & 0xFF)
81 #define MBX_USER_IDX(idx) ((NotifyDriverMbx_mailboxTable[(idx)] >> 8) & 0xFF)
83 #define MAILBOX_REG_VAL(m) (0x1 << (2 * m))
85 #define MAILBOX_MESSAGE(idx) \
86         (MAILBOX_ADDR(idx) + 0x40 + (0x4 * SUBMBX_IDX(idx)))
88 #define MAILBOX_STATUS(idx) \
89         (MAILBOX_ADDR(idx) + 0xC0 + (0x4 * SUBMBX_IDX(idx)))
91 #define MAILBOX_IRQSTATUS_CLR(idx) \
92         (MAILBOX_ADDR(idx) + 0x104 + (0x10 * MBX_USER_IDX(idx)))
94 #define MAILBOX_IRQENABLE_SET(idx) \
95         (MAILBOX_ADDR(idx) + 0x108 + (0x10 * MBX_USER_IDX(idx)))
97 #define MAILBOX_IRQENABLE_CLR(idx) \
98         (MAILBOX_ADDR(idx) + 0x10C + (0x10 * MBX_USER_IDX(idx)))
100 #define MAILBOX_EOI_REG(idx) (MAILBOX_ADDR(idx) + 0x140)
102 #define EVENT_GROUP_SIZE 32
104 /* empty the mailbox for the given index, clear its interrupt */
105 #define MAILBOX_INIT(idx)                                                   \
106     while (REG32(MAILBOX_STATUS(idx)) != 0) {                               \
107         REG32(MAILBOX_MESSAGE(idx));                                        \
108     }                                                                       \
109     REG32(MAILBOX_IRQSTATUS_CLR(idx)) = MAILBOX_REG_VAL(SUBMBX_IDX(idx));   \
110     REG32(MAILBOX_EOI_REG(idx)) = MBX_USER_IDX(idx);
112 /*
113  *************************************************************************
114  *                       Module functions
115  *************************************************************************
116  */
118 /*
119  *  ======== NotifyDriverMbx_Module_startup ========
120  */
121 Int NotifyDriverMbx_Module_startup(Int phase)
123 #if defined(xdc_target__isaCompatible_v7R)
125     /* nothing to do on this processor */
126     return (Startup_DONE);
128 #elif defined(xdc_target__isaCompatible_v8A)
130     return (Startup_DONE);
132 #else
133 #error Invalid target
134 #endif
137 /*
138  **************************************************************
139  *                       Instance functions
140  **************************************************************
141  */
143 /*
144  *  ======== NotifyDriverMbx_Instance_init ========
145  */
146 Void NotifyDriverMbx_Instance_init(NotifyDriverMbx_Object *obj,
147         const NotifyDriverMbx_Params *params)
149     UInt        key;
150     UInt16      selfVirtId;
151     UInt16      index;
153     obj->evtRegMask = 0;
154     obj->notifyHandle = NULL;
155     obj->remoteProcId = params->remoteProcId;
156     obj->remoteVirtId = PROCID(params->remoteProcId);
157     obj->cpuIntrNum = params->intVectorId;
159     /* disable global interrupts */
160     key = Hwi_disable();
162     /* clear inbound mailbox of all old messages */
163     selfVirtId = PROCID(MultiProc_self());
164     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
165     MAILBOX_INIT(index);
167     /* must use processor virtual ID to store driver handle in table */
168     NotifyDriverMbx_module->drvHandles[obj->remoteVirtId] = obj;
170     /* plug the cpu interrupt */
171     NotifySetup_plugHwi(params->remoteProcId, params->intVectorId,
172             NotifyDriverMbx_isr);
174     /* enable the mailbox interrupt from the remote core */
175     NotifyDriverMbx_enable(obj);
177     /* restore global interrupts */
178     Hwi_restore(key);
181 /*
182  *  ======== NotifyDriverMbx_Instance_finalize ========
183  */
184 Void NotifyDriverMbx_Instance_finalize(NotifyDriverMbx_Object *obj)
187     /* disable the mailbox interrupt source */
188     NotifyDriverMbx_disable(obj);
190     /* unplug isr and unprogram the event dispatcher */
191     NotifySetup_unplugHwi(obj->remoteProcId, obj->cpuIntrNum);
193     /* must use processor virtual ID to remove driver handle from table */
194     NotifyDriverMbx_module->drvHandles[obj->remoteVirtId] = NULL;
197 /*
198  *  ======== NotifyDriverMbx_registerEvent ========
199  */
200 Void NotifyDriverMbx_registerEvent(NotifyDriverMbx_Object *obj,
201                                    UInt32 eventId)
203     UInt hwiKey;
205     /*
206      *  Disable interrupt line to ensure that isr doesn't
207      *  preempt registerEvent and encounter corrupt state
208      */
209     hwiKey = Hwi_disable();
211     /* Set the 'registered' bit */
212     SET_BIT(obj->evtRegMask, eventId);
214     /* Restore the interrupt line */
215     Hwi_restore(hwiKey);
218 /*
219  *  ======== NotifyDriverMbx_unregisterEvent ========
220  */
221 Void NotifyDriverMbx_unregisterEvent(NotifyDriverMbx_Object *obj,
222                                      UInt32 eventId)
224     UInt hwiKey;
226     /*
227      *  Disable interrupt line to ensure that isr doesn't
228      *  preempt registerEvent and encounter corrupt state
229      */
230     hwiKey = Hwi_disable();
232     /* Clear the registered bit */
233     CLEAR_BIT(obj->evtRegMask, eventId);
235     /* Restore the interrupt line */
236     Hwi_restore(hwiKey);
239 /*
240  *  ======== NotifyDriverMbx_sendEvent ========
241  */
242 /*
243  *  PUT_NOTIFICATION will spin waiting for enough room in the mailbox FIFO
244  *  to store the number of messages needed for the notification ('numMsgs').
245  *  If spinning is necesssary (i.e. if waitClear is TRUE and there isn't enough
246  *  room in the FIFO) then PUT_NOTIFICATION will allow pre-emption while
247  *  spinning.
248  *
249  *  PUT_NOTIFICATION needs to prevent another local thread from writing to the
250  *  same mailbox after the current thread has
251  *  1) determined that there is enough room to write the notification and
252  *  2) written the first of two messages to the mailbox.
253  *  This is needed to respectively prevent
254  *  1) both threads from incorrectly assuming there is enough space in the FIFO
255  *     for their own notifications
256  *  2) the interrupting thread from writing a notification between two
257  *     two messages that need to be successivly written by the preempted thread.
258  *  Therefore, the check for enough FIFO room and one/both mailbox write(s)
259  *  should all occur atomically (i.e. with interrupts disabled)
260  */
261 #define PUT_NOTIFICATION(idx)                                               \
262         key = Hwi_disable();                                                \
263         while(MAILBOX_FIFOLENGTH - REG32(MAILBOX_STATUS(idx)) < numMsgs) {  \
264             Hwi_restore(key);                                               \
265             if (!waitClear) {                                               \
266                 return (Notify_E_FAIL);                                     \
267             }                                                               \
268             key = Hwi_disable();                                            \
269         };                                                                  \
270         REG32(MAILBOX_MESSAGE(idx)) = eventId + smallPayload;               \
271         if (smallPayload == 0xFFFFFFE0) {                                   \
272             REG32(MAILBOX_MESSAGE(idx)) = payload;                          \
273         }                                                                   \
274         Hwi_restore(key);
276 Int NotifyDriverMbx_sendEvent(NotifyDriverMbx_Object *obj, UInt32 eventId,
277         UInt32 payload, Bool waitClear)
279     UInt16 selfVirtId = PROCID(MultiProc_self());
280     UInt16 index;
281     UInt key;
282     UInt numMsgs;
283     UInt32 smallPayload;
285     /* Decide if the payload is small enough to fit in the first mbx msg */
286     if (payload < 0x7FFFFFF) {
287         smallPayload = (payload << 5);
288         numMsgs = 1;
289     }
290     else {
291         smallPayload = 0xFFFFFFE0;
292         numMsgs = 2;
293     }
295     index = (selfVirtId * NotifyDriverMbx_NUM_CORES) + obj->remoteVirtId;
296     PUT_NOTIFICATION(index);
298     return (Notify_S_SUCCESS);
301 /*
302  *  ======== NotifyDriverMbx_disable ========
303  */
304 Void NotifyDriverMbx_disable(NotifyDriverMbx_Object *obj)
306     UInt16 selfVirtId = PROCID(MultiProc_self());
307     UInt16 index;
309     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
310     REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
313 /*
314  *  ======== NotifyDriverMbx_enable ========
315  */
316 Void NotifyDriverMbx_enable(NotifyDriverMbx_Object *obj)
318     UInt16 selfVirtId = PROCID(MultiProc_self());
319     UInt16 index;
321     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
322     REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
325 /*
326  *  ======== NotifyDriverMbx_disableEvent ========
327  */
328 Void NotifyDriverMbx_disableEvent(NotifyDriverMbx_Object *obj, UInt32 eventId)
330     /* NotifyDriverMbx_disableEvent not supported by this driver */
331     Assert_isTrue(FALSE, NotifyDriverMbx_A_notSupported);
334 /*
335  *  ======== NotifyDriverMbx_enableEvent ========
336  */
337 Void NotifyDriverMbx_enableEvent(NotifyDriverMbx_Object *obj, UInt32 eventId)
339     /* NotifyDriverMbx_enableEvent not supported by this driver */
340     Assert_isTrue(FALSE, NotifyDriverMbx_A_notSupported);
343 /*
344  *************************************************************************
345  *                       Internal functions
346  *************************************************************************
347  */
349 /*
350  *  ======== NotifyDriverMbx_isr ========
351  */
353 /*  Read a message from the mailbox. The low 5 bits of the message
354  *  contains the eventId. The high 27 bits of the message contains
355  *  either:
356  *      1) The payload if the payload is less than 0x7FFFFFF
357  *      2) 0x7FFFFFF otherwise
358  *  If the high 27 bits of the first message is 0x7FFFFFF, then the
359  *  payload is in the next mailbox message.
360  *
361  *  idx = mailbox table index
362  */
363 #define MESSAGE_DELIVERY(idx)                                               \
364     msg = REG32(MAILBOX_MESSAGE(idx));                                      \
365     eventId = (UInt16)(msg & 0x1F);                                         \
366     payload = msg >> 5;                                                     \
367     if (payload == 0x7FFFFFF) {                                             \
368         while(REG32(MAILBOX_STATUS(idx)) == 0);                             \
369         payload = REG32(MAILBOX_MESSAGE(idx));                              \
370     }                                                                       \
371     REG32(MAILBOX_IRQSTATUS_CLR(idx)) = MAILBOX_REG_VAL(SUBMBX_IDX(idx));   \
372     obj = NotifyDriverMbx_module->drvHandles[srcVirtId];                    \
373     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_internal);               \
374     if (TEST_BIT(obj->evtRegMask, eventId)) {                               \
375         ti_sdo_ipc_Notify_exec(obj->notifyHandle, eventId, payload);        \
376     }                                                                       \
377     REG32(MAILBOX_EOI_REG(idx)) = MBX_USER_IDX(idx);
379 Void NotifyDriverMbx_isr(UInt16 idx)
381     NotifyDriverMbx_Object *obj;
382     UInt32 msg, payload;
383     UInt16 eventId;
384     UInt16 srcVirtId;
386     srcVirtId = idx / NotifyDriverMbx_NUM_CORES;
387     MESSAGE_DELIVERY(idx)
390 /*
391  *  ======== NotifyDriverMbx_setNotifyHandle ========
392  */
393 Void NotifyDriverMbx_setNotifyHandle(NotifyDriverMbx_Object *obj,
394         Ptr notifyHandle)
396     /* internally used, so no assert needed */
397     obj->notifyHandle = (ti_sdo_ipc_Notify_Handle)notifyHandle;