Shared memory cache management
[ipc/ipcdev.git] / packages / ti / pm / IpcPowerDsp_omap54xx.c
1 /*
2  * Copyright (c) 2012-2015, 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  *  @file       IpcPowerDsp_omap54xx.c
34  *
35  *  @brief      A simple Power Managment which responses to the host commands.
36  *
37  *  TODO:
38  *     - Add suspend/resume notifications
39  *  ============================================================================
40  */
42 #include <xdc/std.h>
43 #include <xdc/runtime/System.h>
44 #include <xdc/runtime/Error.h>
45 #include <xdc/runtime/Assert.h>
46 #include <xdc/runtime/Memory.h>
47 #include <xdc/runtime/Main.h>
48 #include <xdc/runtime/Log.h>
49 #include <xdc/runtime/Diags.h>
51 #include <ti/sysbios/BIOS.h>
52 #include <ti/sysbios/knl/Semaphore.h>
53 #include <ti/sysbios/knl/Task.h>
54 #include <ti/sysbios/hal/Hwi.h>
55 #include <ti/sysbios/knl/Swi.h>
56 #include <ti/sysbios/knl/Clock.h>
57 #include <ti/sysbios/timers/dmtimer/Timer.h>
58 #include <ti/sysbios/family/c64p/tesla/Power.h>
59 #include <ti/sysbios/family/c64p/tesla/Wugen.h>
60 #include <ti/sysbios/family/c64p/tesla/package/internal/Power.xdc.h>
62 #include <ti/ipc/MultiProc.h>
64 #include <ti/pm/IpcPower.h>
65 #include "_IpcPower.h"
67 #define REG32(A)   (*(volatile UInt32 *) (A))
69 static UInt32 IpcPower_hibLock;
71 #define PDCCMD_REG      0x01810000
72 #define SLEEP_MODE      0x15555
73 #define GPT5_IRQ        51
74 #define GPT6_IRQ        52
75 #define MBX_DSP_IRQ     55
77 static Swi_Handle suspendResumeSwi;
78 static Semaphore_Handle IpcPower_semSuspend = NULL;
79 static Semaphore_Handle IpcPower_semExit = NULL;
80 static Task_Handle IpcPower_tskSuspend = NULL;
82 /* List for storing all registered callback functions */
83 static IpcPower_CallbackElem *IpcPower_callbackList = NULL;
85 /* Module ref count: */
86 static Int curInit = 0;
88 /* PM transition debug counters */
89 UInt32 IpcPower_idleCount = 0;
90 UInt32 IpcPower_suspendCount = 0;
91 UInt32 IpcPower_resumeCount = 0;
93 /* Clock function pointer to handle custom clock functions */
94 Void *IpcPower_clockFxn = NULL;
96 /* Handle to store BIOS Tick Timer */
97 static Timer_Handle tickTimerHandle = NULL;
99 /*
100  *  ======== IpcPower_callUserFxns ========
101  */
102 static Void IpcPower_callUserFxns(IpcPower_Event event)
104     IpcPower_CallbackElem *node = IpcPower_callbackList;
106     /* Call the registered functions matching the event */
107     while (node != NULL) {
108         if (node->event == event) {
109             (*(node->callback))(event, node->data);
110         }
111         node = node->next;
112     }
115 /*
116  *  ======== IpcPower_suspendSwi ========
117  */
118 static Void IpcPower_suspendSwi(UArg arg0, UArg arg1)
120     /* Disable wakeup events */
121     Wugen_disableEvent(GPT5_IRQ);
122     Wugen_disableEvent(GPT6_IRQ);
123     Wugen_disableEvent(MBX_DSP_IRQ);
125     /* Invoke the BIOS suspend routine */
126     Power_suspend(Power_Suspend_HIBERNATE);
128     /* Re-enable wakeup events */
129     Wugen_enableEvent(GPT5_IRQ);
130     Wugen_enableEvent(GPT6_IRQ);
131     Wugen_enableEvent(MBX_DSP_IRQ);
134 /*
135  * =============================================================================
136  *  IpcPower Functions:
137  * =============================================================================
138  */
140 /*
141  *  ======== IpcPower_suspendTaskFxn ========
142  */
143 Void IpcPower_suspendTaskFxn(UArg arg0, UArg arg1)
145     while (curInit) {
146         /* Wait for suspend notification from host-side */
147         Semaphore_pend(IpcPower_semSuspend, BIOS_WAIT_FOREVER);
149         if (curInit) {
150             /* Call pre-suspend preparation function */
151             IpcPower_preSuspend();
153             Swi_post(suspendResumeSwi);
155             /* Call post-resume preparation function */
156             IpcPower_postResume();
157         }
158     }
160     /* Signal the task end */
161     Semaphore_post(IpcPower_semExit);
164 /*
165  *  ======== IpcPower_init ========
166  */
167 Void IpcPower_init()
169     Swi_Params swiParams;
170     Task_Params taskParams;
171     Int i;
172     UArg arg;
173     UInt func;
174     Timer_Handle tHandle = NULL;
176     if (curInit++) {
177         return;
178     }
180     IpcPower_hibLock = 0;
182     for (i = 0; i < Timer_Object_count(); i++) {
183         tHandle = Timer_Object_get(NULL, i);
184         func = (UInt) Timer_getFunc(tHandle, &arg);
185         if (func && ((func == (UInt) ti_sysbios_knl_Clock_doTick__I) ||
186                      (func == (UInt) Clock_tick) ||
187                      (func == (UInt) IpcPower_clockFxn))) {
188             tickTimerHandle = tHandle;
189             break;
190         }
191     }
192     if (tickTimerHandle == NULL) {
193         System_abort("IpcPower_init: Cannot find tickTimer Handle. Custom"
194                         " clock timer functions currently not supported.\n");
195     }
197     IpcPower_semSuspend = Semaphore_create(0, NULL, NULL);
198     IpcPower_semExit = Semaphore_create(0, NULL, NULL);
200     Task_Params_init(&taskParams);
201     taskParams.priority = Task_numPriorities - 1; /* Highest priority */
202     taskParams.instance->name = "ti.pm.IpcPower_tskSuspend";
203     IpcPower_tskSuspend = Task_create(IpcPower_suspendTaskFxn, &taskParams,
204                                                                         NULL);
206     Swi_Params_init(&swiParams);
207     swiParams.priority = Swi_numPriorities - 1; /* Max Priority Swi */
208     suspendResumeSwi = Swi_create(IpcPower_suspendSwi, &swiParams, NULL);
211 /*
212  *  ======== IpcPower_exit ========
213  */
214 Void IpcPower_exit()
216     --curInit;
218     if (curInit == 0) {
219         /* Unblock PM suspend task */
220         Semaphore_post(IpcPower_semSuspend);
222         /* Wait for task completion */
223         Semaphore_pend(IpcPower_semExit, BIOS_WAIT_FOREVER);
225         /* Delete the suspend task and semaphore */
226         Task_delete(&IpcPower_tskSuspend);
227         Semaphore_delete(&IpcPower_semSuspend);
228         Semaphore_delete(&IpcPower_semExit);
229     }
232 /*
233  *  ======== IpcPower_suspend ========
234  */
235 Void IpcPower_suspend()
237     Assert_isTrue((curInit > 0) , NULL);
239     Semaphore_post(IpcPower_semSuspend);
242 /*
243  *  ======== IpcPower_idle ========
244  */
245 Void IpcPower_idle()
247     IpcPower_idleCount++;
249     REG32(PDCCMD_REG) = SLEEP_MODE;
250     REG32(PDCCMD_REG);
252     /* Enable wakeup events */
253     Wugen_enableEvent(GPT5_IRQ);
254     Wugen_enableEvent(GPT6_IRQ);
255     Wugen_enableEvent(MBX_DSP_IRQ);
257     asm(" idle");
260 /*
261  *  ======== IpcPower_hibernateLock ========
262  */
263 UInt IpcPower_hibernateLock()
265     IArg hwiKey, swiKey;
267     hwiKey = Hwi_disable();
268     swiKey = Swi_disable();
270     IpcPower_hibLock++;
272     Swi_restore(swiKey);
273     Hwi_restore(hwiKey);
275     return (IpcPower_hibLock);
278 /*
279  *  ======== IpcPower_hibernateUnlock ========
280  */
281 UInt IpcPower_hibernateUnlock()
283     IArg hwiKey, swiKey;
285     hwiKey = Hwi_disable();
286     swiKey = Swi_disable();
288     if (IpcPower_hibLock > 0) {
289         IpcPower_hibLock--;
290     }
292     Swi_restore(swiKey);
293     Hwi_restore(hwiKey);
295     return (IpcPower_hibLock);
299 /*
300  *  ======== IpcPower_canHibernate ========
301  */
302 Bool IpcPower_canHibernate()
304     if (IpcPower_hibLock) {
305         return (FALSE);
306     }
308     return (TRUE);
311 /*
312  *  ======== IpcPower_registerCallback ========
313  */
314 #define FXNN "IpcPower_registerCallback"
315 Int IpcPower_registerCallback(Int event, IpcPower_CallbackFuncPtr cbck,
316                               Ptr data)
318     IArg hwiKey;
319     IpcPower_CallbackElem **list, *node;
320     BIOS_ThreadType context = BIOS_getThreadType();
322     if ((context != BIOS_ThreadType_Task) &&
323         (context != BIOS_ThreadType_Main)) {
324         Log_print0(Diags_ERROR, FXNN":Invalid context\n");
325         return (IpcPower_E_FAIL);
326     }
328     list = &IpcPower_callbackList;
330     /* Allocate and update new element */
331     node = Memory_alloc(NULL, sizeof(IpcPower_CallbackElem), 0, NULL);
332     if (node == NULL) {
333         Log_print0(Diags_ERROR, FXNN":out of memory\n");
334         return (IpcPower_E_MEMORY);
335     }
337     node->next     = NULL;
338     node->event    = (IpcPower_Event) event;
339     node->callback = cbck;
340     node->data     = data;
342     hwiKey = Hwi_disable();  /* begin: critical section */
343     while (*list != NULL) {
344         list = &(*list)->next;
345     }
346     *list = node;
347     Hwi_restore(hwiKey);  /* end: critical section */
349     return (IpcPower_S_SUCCESS);
351 #undef FXNN
353 /*
354  *  ======== IpcPower_unregisterCallback ========
355  */
356 #define FXNN "IpcPower_unregisterCallback"
357 Int IpcPower_unregisterCallback(Int event, IpcPower_CallbackFuncPtr cbck)
359     IArg hwiKey;
360     IpcPower_CallbackElem **list, *node;
361     Int status = IpcPower_E_FAIL;
362     BIOS_ThreadType context = BIOS_getThreadType();
364     if ((context != BIOS_ThreadType_Task) &&
365         (context != BIOS_ThreadType_Main)) {
366         Log_print0(Diags_ERROR, FXNN":Invalid context\n");
367         return (status);
368     }
370     list = &IpcPower_callbackList;
371     node  = NULL;
373     hwiKey = Hwi_disable();  /* begin: critical section */
374     while (*list != NULL) {
375         if ( ((*list)->callback == cbck) &&
376              ((*list)->event == event) ) {
377             node   = *list;
378             *list  = (*list)->next;
379             status = IpcPower_S_SUCCESS;
380             break;
381         }
382         list = &(*list)->next;
383     }
384     Hwi_restore(hwiKey);  /* end: critical section */
386     if (status == IpcPower_S_SUCCESS) {
387         if (node != NULL) {
388             Memory_free(NULL, node, sizeof(IpcPower_CallbackElem));
389         }
390         else {
391             Log_print0(Diags_ERROR, FXNN":Invalid pointer\n");
392         }
393     }
395     return (status);
397 #undef FXNN
399 /*
400  *  ======== IpcPower_preSuspend ========
401  */
402 Void IpcPower_preSuspend(Void)
404     IpcPower_suspendCount++;
406     /* Call all user registered suspend callback functions */
407     IpcPower_callUserFxns(IpcPower_Event_SUSPEND);
410 /*
411  *  ======== IpcPower_postResume ========
412  */
413 Void IpcPower_postResume(Void)
415     /* Restore timer registers */
416     Timer_restoreRegisters(tickTimerHandle, NULL);
417     Timer_start(tickTimerHandle);
419     /* Call all user registered resume callback functions */
420     IpcPower_callUserFxns(IpcPower_Event_RESUME);
422     IpcPower_resumeCount++;