SDOCM00106584 Notify mailbox driver support on DRA7xx (IPU, HOST) - Part 1
[ipc/ipcdev.git] / packages / ti / sdo / ipc / family / vayu / NotifyDriverMbx.c
1 /*
2  * Copyright (c) 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  */
33 /*
34  *  ======== NotifyDriverMbx.c ========
35  */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Startup.h>
40 #include <ti/sysbios/BIOS.h>
41 #include <ti/sysbios/family/c64p/EventCombiner.h>
42 #include <ti/sysbios/family/c64p/Hwi.h>
43 #include <ti/sysbios/family/shared/vayu/IntXbar.h>
45 #include <ti/sdo/ipc/_Ipc.h>
46 #include <ti/sdo/ipc/_Notify.h>
47 #include <ti/sdo/ipc/family/vayu/NotifySetup.h>
48 #include <ti/sdo/ipc/interfaces/INotifyDriver.h>
49 #include <ti/sdo/utils/_MultiProc.h>
51 #include "package/internal/NotifyDriverMbx.xdc.h"
53 /* Bit mask operations */
54 #define SET_BIT(num,pos)            ((num) |= (1u << (pos)))
55 #define CLEAR_BIT(num,pos)          ((num) &= ~(1u << (pos)))
56 #define TEST_BIT(num,pos)           ((num) & (1u << (pos)))
58 /* register access methods */
59 #define REG16(A)        (*(volatile UInt16 *)(A))
60 #define REG32(A)        (*(volatile UInt32 *)(A))
62 #define MAILBOX_FIFOLENGTH 4
63 #define PROCID(idx) (NotifyDriverMbx_procIdTable[idx])
65 #define MBX_BASEADDR_IDX(idx) \
66         ((NotifyDriverMbx_mailboxTable[idx] >> 16) & 0xFFFF)
68 #define MAILBOX_ADDR(idx) \
69         (NotifyDriverMbx_mailboxBaseAddr[MBX_BASEADDR_IDX(idx)])
71 #define MBX_TABLE_IDX(src, dst) \
72         ((PROCID(src) * NotifyDriverMbx_NUM_CORES) + PROCID(dst))
74 #define SUBMBX_IDX(idx) (NotifyDriverMbx_mailboxTable[idx] & 0xFF)
76 #define MBX_USER_IDX(idx) ((NotifyDriverMbx_mailboxTable[idx] >> 8) & 0xFF)
78 #define MAILBOX_REG_VAL(m) (0x1 << (2 * m))
80 #define MAILBOX_MESSAGE(idx) \
81         (MAILBOX_ADDR(idx) + 0x40 + (0x4 * SUBMBX_IDX(idx)))
83 #define MAILBOX_STATUS(idx) \
84         (MAILBOX_ADDR(idx) + 0xC0 + (0x4 * SUBMBX_IDX(idx)))
86 #define MAILBOX_IRQSTATUS_CLR(idx) \
87         (MAILBOX_ADDR(idx) + 0x104 + (0x10 * MBX_USER_IDX(idx)))
89 #define MAILBOX_IRQENABLE_SET(idx) \
90         (MAILBOX_ADDR(idx) + 0x108 + (0x10 * MBX_USER_IDX(idx)))
92 #define MAILBOX_IRQENABLE_CLR(idx) \
93         (MAILBOX_ADDR(idx) + 0x10C + (0x10 * MBX_USER_IDX(idx)))
95 #define MAILBOX_EOI_REG(idx) (MAILBOX_ADDR(idx) + 0x140)
97 #define EVENT_GROUP_SIZE 32
99 /* empty the mailbox for the given index, clear its interrupt */
100 #define MAILBOX_INIT(idx)                                                   \
101     while (REG32(MAILBOX_STATUS(idx)) != 0) {                               \
102         REG32(MAILBOX_MESSAGE(idx));                                        \
103     }                                                                       \
104     REG32(MAILBOX_IRQSTATUS_CLR(idx)) = MAILBOX_REG_VAL(SUBMBX_IDX(idx));
106 /*
107  *************************************************************************
108  *                       Module functions
109  *************************************************************************
110  */
112 /*
113  *  ======== NotifyDriverMbx_Module_startup ========
114  */
115 Int NotifyDriverMbx_Module_startup(Int phase)
117 #if defined(xdc_target__isaCompatible_64P)
119     /* nothing to do on this processor */
120     return (Startup_DONE);
122 #elif defined(xdc_target__isaCompatible_arp32)
124     /* nothing to do on this processor */
125     return (Startup_DONE);
127 #elif defined(xdc_target__isaCompatible_v7M)
129     /* nothing to do on this processor */
130     return (Startup_DONE);
132 #elif defined(xdc_target__isaCompatible_v7A)
134     /* TODO */
135     return (Startup_DONE);
137 #else
138 #error Invalid target
139 #endif
142 /*
143  **************************************************************
144  *                       Instance functions
145  **************************************************************
146  */
148 /*
149  *  ======== NotifyDriverMbx_Instance_init ========
150  */
151 Void NotifyDriverMbx_Instance_init(NotifyDriverMbx_Object *obj,
152         const NotifyDriverMbx_Params *params)
154     UInt        key;
155     UInt16      selfVirtId;
156     UInt16      index;
158     Assert_isTrue((params->remoteProcId != MultiProc_INVALIDID) &&
159             (params->remoteProcId != MultiProc_self()),
160             ti_sdo_ipc_Ipc_A_invParam);
162     /* TODO: this check is weak */
163     if (params->remoteProcId >= MultiProc_getNumProcessors() ||
164         params->remoteProcId == MultiProc_INVALIDID) {
165         return;    /* keep Coverity happy */
166     }
168     obj->evtRegMask = 0;
169     obj->notifyHandle = NULL;
170     obj->remoteProcId = params->remoteProcId;
171     obj->remoteVirtId = PROCID(params->remoteProcId);
172     obj->cpuIntrNum = params->intVectorId;
174     /* disable global interrupts */
175     key = Hwi_disable();
177     /* clear mailbox of any old messages */
178     selfVirtId = PROCID(MultiProc_self());
179     index = (selfVirtId * NotifyDriverMbx_NUM_CORES) + obj->remoteVirtId;
180     MAILBOX_INIT(index);
182     /* must use processor virtual ID to store driver handle in table */
183     NotifyDriverMbx_module->drvHandles[obj->remoteVirtId] = obj;
185     /* plug the cpu interrupt */
186     NotifySetup_plugHwi(params->remoteProcId, params->intVectorId,
187             NotifyDriverMbx_isr);
189     /* enable the mailbox interrupt from the remote core */
190     NotifyDriverMbx_enable(obj);
192     /* restore global interrupts */
193     Hwi_restore(key);
196 /*
197  *  ======== NotifyDriverMbx_Instance_finalize ========
198  */
199 Void NotifyDriverMbx_Instance_finalize(NotifyDriverMbx_Object *obj)
202     /* disable the mailbox interrupt source */
203     NotifyDriverMbx_disable(obj);
205     /* unplug isr and unprogram the event dispatcher */
206     NotifySetup_unplugHwi(obj->remoteProcId, obj->cpuIntrNum);
208     /* must use processor virtual ID to remove driver handle from table */
209     NotifyDriverMbx_module->drvHandles[obj->remoteVirtId] = NULL;
212 /*
213  *  ======== NotifyDriverMbx_registerEvent ========
214  */
215 Void NotifyDriverMbx_registerEvent(NotifyDriverMbx_Object *obj,
216                                    UInt32 eventId)
218     UInt hwiKey;
220     /*
221      *  Disable interrupt line to ensure that isr doesn't
222      *  preempt registerEvent and encounter corrupt state
223      */
224     hwiKey = Hwi_disable();
226     /* Set the 'registered' bit */
227     SET_BIT(obj->evtRegMask, eventId);
229     /* Restore the interrupt line */
230     Hwi_restore(hwiKey);
233 /*
234  *  ======== NotifyDriverMbx_unregisterEvent ========
235  */
236 Void NotifyDriverMbx_unregisterEvent(NotifyDriverMbx_Object *obj,
237                                      UInt32 eventId)
239     UInt hwiKey;
241     /*
242      *  Disable interrupt line to ensure that isr doesn't
243      *  preempt registerEvent and encounter corrupt state
244      */
245     hwiKey = Hwi_disable();
247     /* Clear the registered bit */
248     CLEAR_BIT(obj->evtRegMask, eventId);
250     /* Restore the interrupt line */
251     Hwi_restore(hwiKey);
254 /*
255  *  ======== NotifyDriverMbx_sendEvent ========
256  */
257 /*
258  *  PUT_NOTIFICATION will spin waiting for enough room in the mailbox FIFO
259  *  to store the number of messages needed for the notification ('numMsgs').
260  *  If spinning is necesssary (i.e. if waitClear is TRUE and there isn't enough
261  *  room in the FIFO) then PUT_NOTIFICATION will allow pre-emption while
262  *  spinning.
263  *
264  *  PUT_NOTIFICATION needs to prevent another local thread from writing to the
265  *  same mailbox after the current thread has
266  *  1) determined that there is enough room to write the notification and
267  *  2) written the first of two messages to the mailbox.
268  *  This is needed to respectively prevent
269  *  1) both threads from incorrectly assuming there is enough space in the FIFO
270  *     for their own notifications
271  *  2) the interrupting thread from writing a notification between two
272  *     two messages that need to be successivly written by the preempted thread.
273  *  Therefore, the check for enough FIFO room and one/both mailbox write(s)
274  *  should all occur atomically (i.e. with interrupts disabled)
275  */
276 #define PUT_NOTIFICATION(idx)                                               \
277         key = Hwi_disable();                                                \
278         while(MAILBOX_FIFOLENGTH - REG32(MAILBOX_STATUS(idx)) < numMsgs) {  \
279             Hwi_restore(key);                                               \
280             if (!waitClear) {                                               \
281                 return (Notify_E_FAIL);                                     \
282             }                                                               \
283             key = Hwi_disable();                                            \
284         };                                                                  \
285         REG32(MAILBOX_MESSAGE(idx)) = eventId + smallPayload;               \
286         if (smallPayload == 0xFFFFFFE0) {                                   \
287             REG32(MAILBOX_MESSAGE(idx)) = payload;                          \
288         }                                                                   \
289         Hwi_restore(key);
291 Int NotifyDriverMbx_sendEvent(NotifyDriverMbx_Object *obj, UInt32 eventId,
292         UInt32 payload, Bool waitClear)
294     UInt16 selfVirtId = PROCID(MultiProc_self());
295     UInt16 index;
296     UInt key;
297     UInt numMsgs;
298     UInt32 smallPayload;
300     /* Decide if the payload is small enough to fit in the first mbx msg */
301     if (payload < 0x7FFFFFF) {
302         smallPayload = (payload << 5);
303         numMsgs = 1;
304     }
305     else {
306         smallPayload = 0xFFFFFFE0;
307         numMsgs = 2;
308     }
310 #if defined(xdc_target__isaCompatible_64P) || \
311     defined(xdc_target__isaCompatible_arp32) || \
312     defined(xdc_target__isaCompatible_v7M)
314     index = (selfVirtId * NotifyDriverMbx_NUM_CORES) + obj->remoteVirtId;
315     PUT_NOTIFICATION(index);
317 #elif defined(xdc_target__isaCompatible_v7A)
319     /* TODO */
320     index = (selfVirtId * NotifyDriverMbx_NUM_CORES) + obj->remoteVirtId;
321     PUT_NOTIFICATION(index);
323 #else
324 #error Invalid target
325 #endif
327     return (Notify_S_SUCCESS);
330 /*
331  *  ======== NotifyDriverMbx_disable ========
332  */
333 Void NotifyDriverMbx_disable(NotifyDriverMbx_Object *obj)
335     UInt16 selfVirtId = PROCID(MultiProc_self());
336     UInt16 index;
338 #if defined(xdc_target__isaCompatible_64P) || \
339     defined(xdc_target__isaCompatible_arp32) || \
340     defined(xdc_target__isaCompatible_v7M)
342     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
343     REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
345 #elif defined(xdc_target__isaCompatible_v7A)
347     /* TODO */
348     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
349     REG32(MAILBOX_IRQENABLE_CLR(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
351 #else
352 #error Invalid target
353 #endif
356 /*
357  *  ======== NotifyDriverMbx_enable ========
358  */
359 Void NotifyDriverMbx_enable(NotifyDriverMbx_Object *obj)
361     UInt16 selfVirtId = PROCID(MultiProc_self());
362     UInt16 index;
364 #if defined(xdc_target__isaCompatible_64P) || \
365     defined(xdc_target__isaCompatible_arp32) || \
366     defined(xdc_target__isaCompatible_v7M)
368     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
369     REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
371 #elif defined(xdc_target__isaCompatible_v7A)
373     /* TODO */
374     index = (obj->remoteVirtId * NotifyDriverMbx_NUM_CORES) + selfVirtId;
375     REG32(MAILBOX_IRQENABLE_SET(index)) = MAILBOX_REG_VAL(SUBMBX_IDX(index));
377 #else
378 #error Invalid target
379 #endif
382 /*
383  *  ======== NotifyDriverMbx_disableEvent ========
384  */
385 Void NotifyDriverMbx_disableEvent(NotifyDriverMbx_Object *obj, UInt32 eventId)
387     /* NotifyDriverMbx_disableEvent not supported by this driver */
388     Assert_isTrue(FALSE, NotifyDriverMbx_A_notSupported);
391 /*
392  *  ======== NotifyDriverMbx_enableEvent ========
393  */
394 Void NotifyDriverMbx_enableEvent(NotifyDriverMbx_Object *obj, UInt32 eventId)
396     /* NotifyDriverMbx_enableEvent not supported by this driver */
397     Assert_isTrue(FALSE, NotifyDriverMbx_A_notSupported);
400 /*
401  *************************************************************************
402  *                       Internal functions
403  *************************************************************************
404  */
406 /*
407  *  ======== NotifyDriverMbx_isr ========
408  */
410 /*  Read a message from the mailbox. The low 5 bits of the message
411  *  contains the eventId. The high 27 bits of the message contains
412  *  either:
413  *      1) The payload if the payload is less than 0x7FFFFFF
414  *      2) 0x7FFFFFF otherwise
415  *  If the high 27 bits of the first message is 0x7FFFFFF, then the
416  *  payload is in the next mailbox message.
417  *
418  *  idx = mailbox table index
419  */
420 #define MESSAGE_DELIVERY(idx)                                               \
421     msg = REG32(MAILBOX_MESSAGE(idx));                                      \
422     eventId = (UInt16)(msg & 0x1F);                                         \
423     payload = msg >> 5;                                                     \
424     if (payload == 0x7FFFFFF) {                                             \
425         while(REG32(MAILBOX_STATUS(idx)) == 0);                             \
426         payload = REG32(MAILBOX_MESSAGE(idx));                              \
427     }                                                                       \
428     REG32(MAILBOX_IRQSTATUS_CLR(idx)) = MAILBOX_REG_VAL(SUBMBX_IDX(idx));   \
429     obj = NotifyDriverMbx_module->drvHandles[srcVirtId];                    \
430     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_internal);               \
431     if (TEST_BIT(obj->evtRegMask, eventId)) {                               \
432         ti_sdo_ipc_Notify_exec(obj->notifyHandle, eventId, payload);        \
433     }                                                                       \
434     REG32(MAILBOX_EOI_REG(idx)) = 0x1;
436 Void NotifyDriverMbx_isr(UInt16 idx)
438     NotifyDriverMbx_Object *obj;
439     UInt32 msg, payload;
440     UInt16 eventId;
442 #if defined(xdc_target__isaCompatible_64P) || \
443     defined(xdc_target__isaCompatible_arp32) || \
444     defined(xdc_target__isaCompatible_v7M)
446     UInt16 srcVirtId;
448     srcVirtId = idx / NotifyDriverMbx_NUM_CORES;
449     MESSAGE_DELIVERY(idx)
451 #elif defined(xdc_target__isaCompatible_v7A)
453     /* TODO */
454     UInt16 srcVirtId;
456     srcVirtId = idx / NotifyDriverMbx_NUM_CORES;
457     MESSAGE_DELIVERY(idx)
459 #else
460 #error Invalid target
461 #endif
464 /*
465  *  ======== NotifyDriverMbx_setNotifyHandle ========
466  */
467 Void NotifyDriverMbx_setNotifyHandle(NotifyDriverMbx_Object *obj,
468         Ptr notifyHandle)
470     /* internally used, so no assert needed */
471     obj->notifyHandle = (ti_sdo_ipc_Notify_Handle)notifyHandle;