PM: Remove redundant critical section protections
[gstreamer-omap:sysbios-rpmsg.git] / src / ti / pm / IpcPower.c
1 /*
2  * Copyright (c) 2011-2012, 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       IpcPower.c
34  *
35  *  @brief      A simple Power Managment which responses to the host commands.
36  *
37  *  TODO:
38  *     - Add suspend/resume notifications
39  *  ============================================================================
40  */
41
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/Registry.h>
49 #include <xdc/runtime/Log.h>
50 #include <xdc/runtime/Diags.h>
51
52 #include <ti/sysbios/hal/Hwi.h>
53 #include <ti/sysbios/knl/Swi.h>
54 #include <ti/sysbios/family/arm/ducati/Core.h>
55 #include <ti/sysbios/family/arm/ducati/omap4430/Power.h>
56
57 #include <ti/ipc/MultiProc.h>
58 #include <ti/pm/IpcPower.h>
59 #include "_IpcPower.h"
60
61 #define MASTERCORE                      1
62 #define NO_MASTERCORE                   0
63 #define CPU_COPY                       -1
64 #define REG32(A)   (*(volatile UInt32 *) (A))
65
66 #pragma DATA_SECTION(IpcPower_hibLocks, ".ipcpower_data")
67 UInt32 IpcPower_hibLocks[2]; /* One lock for each of the IPU cores */
68
69 static Power_SuspendArgs PowerSuspArgs;
70 static Swi_Handle suspendResumeSwi;
71 static UInt16 sysm3ProcId;
72 static UInt16 appm3ProcId;
73 static Int32 refWakeLockCnt;
74
75 /* Module ref count: */
76 static Int curInit = 0;
77
78 typedef enum IpcPower_SleepMode {
79     IpcPower_SLEEP_MODE_DEEPSLEEP,
80     IpcPower_SLEEP_MODE_WAKELOCK,
81     IpcPower_SLEEP_MODE_WAKEUNLOCK
82 } IpcPower_SleepMode;
83
84 static inline Void IpcPower_sleepMode(IpcPower_SleepMode opt)
85 {
86     IArg hwiKey;
87
88     /* Set/Restore the DeepSleep bit if no timer already in use */
89     hwiKey = Hwi_disable();
90     switch (opt) {
91         case IpcPower_SLEEP_MODE_WAKEUNLOCK:
92             if (refWakeLockCnt) {
93                 refWakeLockCnt--;
94             }
95         case IpcPower_SLEEP_MODE_DEEPSLEEP:
96             if (!refWakeLockCnt) {
97                 REG32(M3_SCR_REG) |= 1 << DEEPSLEEP_BIT;
98             }
99             break;
100         case IpcPower_SLEEP_MODE_WAKELOCK:
101             refWakeLockCnt++;
102             REG32(M3_SCR_REG) &= ~(1 << DEEPSLEEP_BIT);
103             break;
104     }
105     Hwi_restore(hwiKey);
106 }
107
108 static inline Void IpcPower_setWugen()
109 {
110     REG32(WUGEN_MEVT1) |= WUGEN_INT_MASK;
111 }
112
113 /*
114  *  ======== IpcPower_suspendSwi ========
115  */
116 #define FXNN "IpcPower_suspendSwi"
117 static Void IpcPower_suspendSwi(UArg arg0, UArg arg1)
118 {
119     if (MultiProc_self() == sysm3ProcId) {
120         Log_print0(Diags_INFO, FXNN":Core0 Hibernation Swi");
121         PowerSuspArgs.pmMasterCore = MASTERCORE;
122     } else if (MultiProc_self() == appm3ProcId) {
123         Log_print0(Diags_INFO, FXNN":Core1 Hibernation Swi");
124         PowerSuspArgs.pmMasterCore = NO_MASTERCORE;
125     }
126     if (refWakeLockCnt) {
127         System_printf("Warning: Wake locks in use\n");
128     }
129     Power_suspend(&PowerSuspArgs);
130     IpcPower_sleepMode(IpcPower_SLEEP_MODE_DEEPSLEEP);
131     IpcPower_setWugen();
132     Log_print0(Diags_INFO, FXNN":Resume");
133 }
134 #undef FXNN
135
136 /* =============================================================================
137  *  IpcPower Functions:
138  * =============================================================================
139  */
140
141 /*
142  *  ======== IpcPower_init ========
143  */
144 Void IpcPower_init()
145 {
146     Swi_Params swiParams;
147     UInt coreIdx = Core_getId();
148
149     if (curInit++) {
150         return;
151     }
152
153     IpcPower_hibLocks[coreIdx] = 0;
154
155     sysm3ProcId = MultiProc_getId("CORE0");
156     appm3ProcId = MultiProc_getId("CORE1");
157     refWakeLockCnt = 0;
158
159     Swi_Params_init(&swiParams);
160     swiParams.priority = Swi_numPriorities - 1; /* Max Priority Swi */
161     suspendResumeSwi = Swi_create(IpcPower_suspendSwi, &swiParams, NULL);
162
163     /*Power settings for saving/restoring context */
164     PowerSuspArgs.rendezvousResume = TRUE;
165     PowerSuspArgs.dmaChannel = CPU_COPY;
166     PowerSuspArgs.intMask31_0 = 0x0;
167     PowerSuspArgs.intMask63_32 = 0x0;
168     PowerSuspArgs.intMask79_64 = 0x0;
169     IpcPower_sleepMode(IpcPower_SLEEP_MODE_DEEPSLEEP);
170     IpcPower_setWugen();
171 }
172
173 /*
174  *  ======== IpcPower_exit ========
175  */
176 Void IpcPower_exit()
177 {
178     --curInit;
179 }
180
181 /*
182  *  ======== IpcPower_suspend ========
183  */
184 Void IpcPower_suspend()
185 {
186     Assert_isTrue((curInit > 0) , NULL);
187
188     Swi_post(suspendResumeSwi);
189 }
190
191 /*
192  *  ======== IpcPower_idle ========
193  */
194 Void IpcPower_idle()
195 {
196     asm(" wfi");
197 }
198
199 /*
200  *  ======== IpcPower_wakeLock ========
201  */
202 Void IpcPower_wakeLock()
203 {
204     IpcPower_sleepMode(IpcPower_SLEEP_MODE_WAKELOCK);
205 }
206
207 /*
208  *  ======== IpcPower_wakeUnlock ========
209  */
210 Void IpcPower_wakeUnlock()
211 {
212     IpcPower_sleepMode(IpcPower_SLEEP_MODE_WAKEUNLOCK);
213 }
214
215 /*
216  *  ======== IpcPower_hibernateLock ========
217  */
218 UInt IpcPower_hibernateLock()
219 {
220     IArg hwiKey;
221     UInt coreIdx = Core_getId();
222
223     hwiKey = Hwi_disable();
224
225     IpcPower_hibLocks[coreIdx] += 1;
226
227     Hwi_restore(hwiKey);
228
229     return (IpcPower_hibLocks[coreIdx]);
230 }
231
232 /*
233  *  ======== IpcPower_hibernateUnlock ========
234  */
235 UInt IpcPower_hibernateUnlock()
236 {
237     IArg hwiKey;
238     UInt coreIdx = Core_getId();
239
240     hwiKey = Hwi_disable();
241
242     if (IpcPower_hibLocks[coreIdx] > 0) {
243         IpcPower_hibLocks[coreIdx] -= 1;
244     }
245
246     Hwi_restore(hwiKey);
247
248     return (IpcPower_hibLocks[coreIdx]);
249 }
250
251 /*
252  *  ======== IpcPower_canHibernate ========
253  */
254 Bool IpcPower_canHibernate()
255 {
256     if (IpcPower_hibLocks[0] || IpcPower_hibLocks[1]) {
257         return (FALSE);
258     }
259
260     return (TRUE);
261 }