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 * ======== IpcMgr.c ========
34 */
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/sysbios/hal/Hwi.h>
42 #include <ti/sdo/ipc/family/f28m35x/NotifyDriverCirc.h>
43 #include <ti/sdo/ipc/family/f28m35x/NameServerBlock.h>
44 #include <ti/sdo/ipc/family/f28m35x/TransportCirc.h>
45 #include <ti/sdo/ipc/_MessageQ.h>
46 #include <ti/sdo/ipc/_Notify.h>
47 #include <ti/sdo/utils/_MultiProc.h>
49 #include "package/internal/IpcMgr.xdc.h"
51 /* For the M3 */
52 #define CTOMIPCACK (0x400FB700)
53 #define CTOMIPCSTS (CTOMIPCACK + 0x4)
54 #define MTOCIPCSET (CTOMIPCACK + 0x8)
55 #define MTOCIPCCLR (CTOMIPCACK + 0xC)
56 #define MTOCIPCFLG (CTOMIPCACK + 0x10)
58 /* For the C28 */
59 #define CTOMIPCSET (0x00004E00)
60 #define CTOMIPCCLR (CTOMIPCSET + 0x2)
61 #define CTOMIPCFLG (CTOMIPCSET + 0x4)
62 #define MTOCIPCACK (CTOMIPCSET + 0x6)
63 #define MTOCIPCSTS (CTOMIPCSET + 0x8)
65 #define M3_IPCFLAG 10
66 #define C28_IPCFLAG 11
68 /*
69 * ======== IpcMgr_Module_startup ========
70 * In this function the M3 processors is used to enable shared memory.
71 * In addition, the owner of each block of memory is initialized and
72 * the write access set based on the static configuration parameters.
73 * IPC flags are used by the M3 and C28 respectively for synchronization.
74 *
75 * The M3 starts by creating its driver instances and then sets the
76 * C28's IPC flag to let the C28 proceed. Then the M3 waits for its
77 * IPC flag to be set before proceeding. Once its IPC flag is set
78 * by the C28, the M3 clears its IPC flag and continues.
79 *
80 * The C28 starts by waiting for its IPC flag to be set by the M3.
81 * Once its IPC flag is set by the M3, the C28 clears its IPC flag and
82 * proceeds to create its driver instances. The C28 then sets the M3's
83 * IPC flag to let the M3 proceed.
84 *
85 * The shared memory usage looks like the following:
86 *
87 * |--------------------|
88 * | Notify Driver |
89 * | |
90 * |--------------------|
91 * | NameServer |
92 * | Remote Driver |
93 * |--------------------|
94 * | MessageQ Transport |
95 * | |
96 * |--------------------|
97 */
98 Int IpcMgr_Module_startup(Int phase)
99 {
100 Int status;
101 SizeT memReq;
102 Ptr writeAddr = (UInt32 *)IpcMgr_writeAddr;
103 Ptr readAddr = (UInt32 *)IpcMgr_readAddr;
104 UInt16 remoteProcId;
105 NotifyDriverCirc_Params notifyDrvParams;
106 TransportCirc_Params transportParams;
107 #ifdef xdc_target__isaCompatible_v7M
108 UInt32 i;
109 volatile UInt32 *memcnf = (volatile UInt32 *)IpcMgr_MEMCNF;
110 volatile UInt32 *msmsel = (volatile UInt32 *)IpcMgr_MSxMSEL;
111 volatile UInt32 *mssrcr = (volatile UInt32 *)IpcMgr_MSxSRCR;
112 volatile UInt32 *set = (volatile UInt32 *)MTOCIPCSET;
113 volatile UInt32 *stat = (volatile UInt32 *)CTOMIPCSTS;
114 volatile UInt32 *ack = (volatile UInt32 *)CTOMIPCACK;
115 #else
116 volatile UInt32 *set = (volatile UInt32 *)CTOMIPCSET;
117 volatile UInt32 *stat = (volatile UInt32 *)MTOCIPCSTS;
118 volatile UInt32 *ack = (volatile UInt32 *)MTOCIPCACK;
119 #endif
121 /*
122 * This code assumes that the device's C28 and M3 MultiProc Ids
123 * are next to each other (e.g. n and n + 1) and that the first
124 * one is even (e.g. n is even).
125 */
126 if (MultiProc_self() & 1) {
127 /* I'm odd */
128 remoteProcId = MultiProc_self() - 1;
129 }
130 else {
131 /* I'm even */
132 remoteProcId = MultiProc_self() + 1;
133 }
135 /* wait for Hwi module to initialize first because of NotifyDriverCirc */
136 if (!Hwi_Module_startupDone()) {
137 return Startup_NOTDONE;
138 }
140 #ifdef xdc_target__isaCompatible_v7M
141 /*
142 * The M3 writes the shared memory enable and owner select
143 * registers before either processor starts using shared memory.
144 */
146 /* write the shared memory configuration register */
147 *memcnf = IpcMgr_sharedMemoryEnable;
149 /* write the owner select register */
150 *msmsel = IpcMgr_sharedMemoryOwnerMask;
152 /* init the owner write access registers */
153 for (i = 0; i < 2; i++) {
154 mssrcr[i] = (IpcMgr_sharedMemoryAccess[(i * 4)]) |
155 (IpcMgr_sharedMemoryAccess[(i * 4) + 1] << 8) |
156 (IpcMgr_sharedMemoryAccess[(i * 4) + 2] << 16) |
157 (IpcMgr_sharedMemoryAccess[(i * 4) + 3] << 24);
158 }
160 #else
162 /* wait for M3 to set C28's IPC flag */
163 while (!(*stat & (1 << C28_IPCFLAG))) {
164 }
166 /* clear own IPC flag */
167 *ack = 1 << C28_IPCFLAG;
169 #endif
171 /* determine the amount of memory required for NotifyDriverCirc */
172 NotifyDriverCirc_Params_init(¬ifyDrvParams);
173 notifyDrvParams.writeAddr = writeAddr;
174 memReq = NotifyDriverCirc_sharedMemReq(¬ifyDrvParams);
176 /* call NotifyCircSetup attach to remote processor */
177 status = IpcMgr_notifyCircAttach(remoteProcId,
178 writeAddr, readAddr);
180 Assert_isTrue(status >= 0, IpcMgr_A_internal);
182 /* update the read/write address */
183 writeAddr = (Ptr)((UInt32)writeAddr + memReq);
184 readAddr = (Ptr)((UInt32)readAddr + memReq);
186 /* determine the amount of memory required for NameServerBlock */
187 memReq = NameServerBlock_sharedMemReq(NULL);
189 /* call NameServerBlock attach to remote processor */
190 status = IpcMgr_nameServerAttach(remoteProcId, writeAddr, readAddr);
192 Assert_isTrue(status >= 0, IpcMgr_A_internal);
194 /* update the read/write address */
195 writeAddr = (Ptr)((UInt32)writeAddr + memReq);
196 readAddr = (Ptr)((UInt32)readAddr + memReq);
198 /* determine the amount of memory required for TransportCirc */
199 TransportCirc_Params_init(&transportParams);
200 transportParams.writeAddr = writeAddr;
201 memReq = TransportCirc_sharedMemReq(&transportParams);
203 /* call TransportCircSetup attach to remote processor */
204 status = IpcMgr_transportCircAttach(remoteProcId,
205 writeAddr, readAddr);
207 Assert_isTrue(status >= 0, IpcMgr_A_internal);
209 #ifdef xdc_target__isaCompatible_v7M
211 /* set C28 IPC flag to tell C28 to proceed */
212 *set = 1 << C28_IPCFLAG;
214 /* wait for C28 to set M3's IPC flag */
215 while (!(*stat & (1 << M3_IPCFLAG))) {
216 }
218 /* clear own IPC flag */
219 *ack = 1 << M3_IPCFLAG;
221 #else
223 /* set M3's IPC flag to tell M3 to proceed */
224 *set = 1 << M3_IPCFLAG;
226 #endif
228 return (Startup_DONE);
229 }
231 /*
232 * ======== IpcMgr_init ========
233 * Init CTOMMSGRAM and MTOCMSGRAM
234 */
235 Void IpcMgr_init()
236 {
237 #ifdef xdc_target__isaCompatible_v7M
238 volatile UInt32 *mwrallow = (volatile UInt32 *)IpcMgr_MWRALLOW;
239 volatile UInt32 *mtocrTestInit = (volatile UInt32 *)IpcMgr_MTOCRTESTINIT;
240 volatile UInt32 *mtocrInitDone = (volatile UInt32 *)IpcMgr_MTOCRINITDONE;
242 /* allow writes to protected registers. */
243 *mwrallow = 0xA5A5A5A5;
245 /* init MtoCMsgRam */
246 *mtocrTestInit |= 0x1;
248 /* make sure init is done */
249 while ((*mtocrInitDone & 0x1) != 0x1) {
250 }
252 /* Disable writes to protected registers. */
253 *mwrallow = 0;
255 #else
257 volatile UInt32 *c28rTestInit = (volatile UInt32 *)IpcMgr_C28RTESTINIT;
258 volatile UInt32 *c28rInitDone = (volatile UInt32 *)IpcMgr_C28RINITDONE;
260 asm(" EALLOW");
262 /* init CtoMMsgRam */
263 *c28rTestInit |= (0x1 << 4);
265 /* make sure init is done */
266 while ((*c28rInitDone & (0x1 << 4)) != (0x1 << 4)) {
267 }
269 asm(" EDIS");
271 #endif
272 }
275 /*
276 * ======== IpcMgr_notifyCircAttach ========
277 * Initialize interrupt
278 */
279 Int IpcMgr_notifyCircAttach(UInt16 remoteProcId, Ptr writeAddr, Ptr readAddr)
280 {
281 NotifyDriverCirc_Params notifyDrvParams;
282 NotifyDriverCirc_Handle notifyDrvHandle;
283 ti_sdo_ipc_Notify_Handle notifyHandle;
284 Error_Block eb;
285 Int status = Notify_S_SUCCESS;
287 /* Initialize the error block */
288 Error_init(&eb);
290 /* Setup the notify driver to the remote processor */
291 NotifyDriverCirc_Params_init(¬ifyDrvParams);
293 /* set the read/write address of the param */
294 notifyDrvParams.readAddr = readAddr;
295 notifyDrvParams.writeAddr = writeAddr;
297 /* create the notify driver instance */
298 notifyDrvHandle = NotifyDriverCirc_create(¬ifyDrvParams, &eb);
299 if (notifyDrvHandle == NULL) {
300 return (Notify_E_FAIL);
301 }
303 /* create the notify instance */
304 notifyHandle = ti_sdo_ipc_Notify_create(
305 NotifyDriverCirc_Handle_upCast(notifyDrvHandle),
306 remoteProcId, 0, NULL, &eb);
308 if (notifyHandle == NULL) {
309 NotifyDriverCirc_delete(¬ifyDrvHandle);
310 status = Notify_E_FAIL;
311 }
313 return (status);
314 }
316 /*
317 * ======== IpcMgr_nameServerAttach ========
318 */
319 Int IpcMgr_nameServerAttach(UInt16 remoteProcId, Ptr writeAddr, Ptr readAddr)
320 {
321 NameServerBlock_Params nsbParams;
322 NameServerBlock_Handle handle;
323 Int status = NameServerBlock_E_FAIL;
324 Error_Block eb;
326 Error_init(&eb);
328 /* Init the param */
329 NameServerBlock_Params_init(&nsbParams);
331 /* set the read/write addresses */
332 nsbParams.readAddr = readAddr;
333 nsbParams.writeAddr = writeAddr;
335 /* create only if notify driver has been created to remote proc */
336 if (Notify_intLineRegistered(remoteProcId, 0)) {
337 handle = NameServerBlock_create(remoteProcId,
338 &nsbParams,
339 &eb);
340 if (handle != NULL) {
341 status = NameServerBlock_S_SUCCESS;
342 }
343 }
345 return (status);
346 }
348 /*
349 * ======== IpcMgr_transportCircAttach ========
350 */
351 Int IpcMgr_transportCircAttach(UInt16 remoteProcId, Ptr writeAddr,
352 Ptr readAddr)
353 {
354 TransportCirc_Handle handle;
355 TransportCirc_Params params;
356 Int status = MessageQ_E_FAIL;
357 Error_Block eb;
359 Error_init(&eb);
361 /* init the transport parameters */
362 TransportCirc_Params_init(¶ms);
363 params.readAddr = readAddr;
364 params.writeAddr = writeAddr;
366 /* make sure notify driver has been created */
367 if (Notify_intLineRegistered(remoteProcId, 0)) {
368 handle = TransportCirc_create(remoteProcId, ¶ms, &eb);
370 if (handle != NULL) {
371 status = MessageQ_S_SUCCESS;
372 }
373 }
375 return (status);
376 }