53b5c502df3d2522e19eada86715bd3f98c248b3
1 /*
2 * Copyright (c) 2012-2014, 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 */
34 /*
35 * ======== Watchdog.c ========
36 *
37 */
39 #include <xdc/runtime/Assert.h>
40 #include <xdc/runtime/System.h>
41 #include <xdc/runtime/Error.h>
42 #include <xdc/runtime/System.h>
43 #include <xdc/runtime/Startup.h>
44 #include <xdc/runtime/Memory.h>
45 #include <xdc/runtime/Types.h>
47 #include <ti/sysbios/BIOS.h>
48 #include <ti/sysbios/knl/Swi.h>
49 #include <ti/sysbios/knl/Task.h>
50 #include <ti/sysbios/interfaces/ITimer.h>
51 #include <ti/sysbios/timers/dmtimer/Timer.h>
53 #ifdef DSP
54 #include <ti/sysbios/family/c64p/Hwi.h>
55 #ifdef OMAP5
56 #include <ti/sysbios/family/c64p/tesla/Wugen.h>
57 #endif
58 #endif
60 #ifdef IPU
61 #include <ti/sysbios/family/arm/m3/Hwi.h>
62 #endif
64 #ifdef SMP
65 #include <ti/sysbios/hal/Core.h>
66 #endif
68 #include <ti/pm/IpcPower.h>
70 #include "package/internal/Watchdog.xdc.h"
72 /* Macro to write to GP timer registers */
73 #define REG32(A) (*(volatile UInt32 *) (A))
75 /* Bit mask for writing into GP timer TGRR reg for posted write mode */
76 #define WATCHDOG_TIMER_TWPS_W_PEND_TGRR 0x8
78 /* Bit mask for writing into GP timer TLDR reg for posted write mode */
79 #define WATCHDOG_TIMER_TWPS_W_PEND_TLDR 0x4
81 /* Bit mask for writing into GP timer TCRR reg for posted write mode */
82 #define WATCHDOG_TIMER_TWPS_W_PEND_TCRR 0x2
84 /* Bit mask for writing into GP timer TCLR reg for posted write mode */
85 #define WATCHDOG_TIMER_TWPS_W_PEND_TCLR 0x1
87 /* GP Timers Clock Control register bit mask */
88 #define WATCHDOG_WDT_CLKCTRL_IDLEST_MASK (3 << 16)
90 #if defined(IPU) && defined(OMAP5)
91 /* OMAP IDCode Register to find the version id, 0x4A002204 */
92 #define IDCODE_REGISTER (0xAA002204)
94 /*
95 * ======== adjustGptClkCtrlAddr ========
96 * Adjust the GPTimer PRCM Clock Register Addresses on OMAP5 ES2.x
97 */
98 static Void adjustGptClkCtrlAddr()
99 {
100 Int i;
101 Bool adjust = FALSE;
102 UInt32 idCode = REG32(IDCODE_REGISTER);
103 UInt32 ramp = (idCode >> 12) & 0xFFFF;
104 UInt32 version = (idCode >> 28) & 0xF;
106 /* Change the addresses only for OMAP5 ES2.x */
107 if (ramp == 0xB942 || ramp == 0xB998) {
108 if (version == 1) {
109 adjust = TRUE;
110 }
111 }
113 /*
114 * OMAP5 ES 2.x has PER GPT PRCM addresses moved up by 0x400
115 * w.r.t OMAP4 and OMAP5 ES 1.0
116 */
117 if (adjust == TRUE) {
118 for (i = 0; i < Watchdog_module->wdtCores; i++) {
119 Watchdog_module->device[i].clkCtrl =
120 (Ptr)((UInt32)Watchdog_module->device[i].clkCtrl - 0x400);
121 }
122 }
123 }
124 #endif
126 /*
127 * ======== initTimer ========
128 */
129 static Void initTimer(Watchdog_TimerRegs *timer, Bool boot)
130 {
131 Timer_Handle tHandle;
132 Types_FreqHz tFreq;
134 /* Get timer frequency */
135 tHandle = Timer_Object_get(NULL, 0);
136 Timer_getFreq(tHandle, &tFreq);
138 timer->tisr = ~0;
139 timer->tier = 2;
140 timer->twer = 2;
141 timer->tldr = (0 - (tFreq.lo * Watchdog_TIME_SEC));
143 /* Booting can take more time, so set CRR to WDT_BOOT_TIME */
144 if (boot) {
145 timer->tcrr = (0 - (tFreq.lo * Watchdog_BOOT_TIME_SEC));
146 }
147 else {
148 timer->tcrr = (0 - (tFreq.lo * Watchdog_TIME_SEC));
149 }
151 timer->tsicr |= 4; /* enable posted write mode */
152 }
154 /*
155 * ======== Watchdog_init ========
156 */
157 Void Watchdog_init( Void (*timerFxn)(Void) )
158 {
159 Hwi_Params hwiParams;
160 UInt key;
161 Timer_Handle tHandle;
162 Types_FreqHz tFreq;
163 Watchdog_TimerRegs *timer;
164 Int i;
165 static Bool first = TRUE;
167 tHandle = Timer_Object_get(NULL, 0);
168 Timer_getFreq(tHandle, &tFreq); /* get timer frequency */
170 #if defined(IPU) && defined(OMAP5)
171 if (first) {
172 adjustGptClkCtrlAddr();
173 }
174 #endif
175 for (i = 0; i < Watchdog_module->wdtCores; i++) { /* loop for SMP cores */
176 timer = (Watchdog_TimerRegs *) Watchdog_module->device[i].baseAddr;
178 /* Check if timer is enabled by host-side */
179 if ((REG32(Watchdog_module->device[i].clkCtrl) &
180 WATCHDOG_WDT_CLKCTRL_IDLEST_MASK) ==
181 WATCHDOG_WDT_CLKCTRL_IDLEST_MASK) {
182 System_printf("Watchdog disabled: TimerBase = 0x%x ClkCtrl = 0x%x\n",
183 timer, Watchdog_module->device[i].clkCtrl);
184 continue; /* for next core */
185 }
187 if (Watchdog_module->status[i] != Watchdog_Mode_ENABLED) {
188 /* Configure the timer */
189 initTimer(timer, TRUE);
191 /* Enable interrupt in BIOS */
192 Hwi_Params_init(&hwiParams);
193 hwiParams.priority = 1;
194 hwiParams.eventId = Watchdog_module->device[i].eventId;
195 hwiParams.maskSetting = Hwi_MaskingOption_LOWER;
196 hwiParams.arg = 1; /* Exception_handler(abortFlag) */
197 key = Hwi_disable();
198 Hwi_create(Watchdog_module->device[i].intNum, (Hwi_FuncPtr) timerFxn,
199 &hwiParams, NULL);
200 Hwi_enableInterrupt(Watchdog_module->device[i].intNum);
201 #if defined(DSP) && defined(OMAP5)
202 Wugen_enableEvent(Watchdog_module->device[i].eventId);
203 #endif
204 Hwi_restore(key);
206 /* Enable timer */
207 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TCLR);
208 timer->tclr |= 1;
209 Watchdog_module->status[i] = Watchdog_Mode_ENABLED;
211 #ifdef SMP
212 System_printf("Watchdog enabled: TimerBase = 0x%x SMP-Core = %d "
213 "Freq = %d\n", timer, i, tFreq.lo);
214 #else
215 System_printf("Watchdog enabled: TimerBase = 0x%x Freq = %d\n",
216 timer, tFreq.lo);
217 #endif
218 }
219 }
221 #if defined(OMAP5) || defined(IPU)
222 if (first) {
223 /* Register callback function */
224 if (!IpcPower_registerCallback(IpcPower_Event_RESUME, Watchdog_restore,
225 NULL)) {
226 System_printf("Watchdog_restore registered as a resume callback\n");
227 }
228 }
229 #endif
231 if (first) {
232 first = FALSE;
233 }
235 return;
236 }
238 /*
239 * ======== Watchdog_idleBegin ========
240 */
241 Void Watchdog_idleBegin(Void)
242 {
243 Int core = 0;
245 #ifdef SMP
246 core = Core_getId();
248 if (core != 0) {
249 Watchdog_stop(core);
250 }
251 else
252 #endif
253 {
254 Watchdog_kick(core);
255 }
256 }
258 /*
259 * ======== Watchdog_swiPrehook ========
260 */
261 Void Watchdog_swiPrehook(Swi_Handle swi)
262 {
263 Int core = 0;
265 #ifdef SMP
266 core = Core_getId();
268 if (core != 0) {
269 Watchdog_start(core);
270 }
271 else
272 #endif
273 {
274 Watchdog_kick(core);
275 }
276 }
278 /*
279 * ======== Watchdog_taskSwitch ========
280 * Refresh/restart watchdog timer whenever task switch scheduling happens
281 */
282 Void Watchdog_taskSwitch(Task_Handle p, Task_Handle n)
283 {
284 Int core = 0;
286 #ifdef SMP
287 core = Core_getId();
289 if (core != 0) {
290 Watchdog_start(core);
291 }
292 else
293 #endif
294 {
295 Watchdog_kick(core);
296 }
297 }
299 /*
300 * ======== Watchdog_isException ========
301 */
302 Bool Watchdog_isException(UInt excNum)
303 {
304 Int i;
305 Bool found = FALSE;
307 for (i = 0; i < Watchdog_module->wdtCores; i++) {
308 if (excNum == Watchdog_module->device[i].intNum) {
309 found = TRUE;
310 break;
311 }
312 }
314 return found;
315 }
317 /*
318 * ======== Watchdog_stop ========
319 */
320 Void Watchdog_stop(Int core)
321 {
322 Watchdog_TimerRegs *timer = Watchdog_module->device[core].baseAddr;
324 if ((Watchdog_module->status[core] == Watchdog_Mode_ENABLED) && timer) {
325 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TCLR);
326 timer->tclr &= ~1;
327 }
328 }
330 /*
331 * ======== Watchdog_start ========
332 */
333 Void Watchdog_start(Int core)
334 {
335 Watchdog_TimerRegs *timer = Watchdog_module->device[core].baseAddr;
337 if ((Watchdog_module->status[core] == Watchdog_Mode_ENABLED) && timer) {
338 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TCLR);
339 timer->tclr |= 1;
341 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TGRR);
342 timer->ttgr = 0;
343 }
344 }
346 /*
347 * ======== Watchdog_kick ========
348 * Refresh/restart the watchdog timer
349 */
350 Void Watchdog_kick(Int core)
351 {
352 Watchdog_TimerRegs *timer = Watchdog_module->device[core].baseAddr;
354 if ((Watchdog_module->status[core] == Watchdog_Mode_ENABLED) && timer) {
355 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TGRR);
356 timer->ttgr = 0;
357 }
358 }
360 /*
361 * ======== Watchdog_restore ========
362 * Refresh/restart the watchdog timer
363 */
364 Void Watchdog_restore(Int event, Ptr data)
365 {
366 Int i;
367 Watchdog_TimerRegs *timer;
369 for (i = 0; i < Watchdog_module->wdtCores; i++) { /* loop for SMP cores */
370 timer = (Watchdog_TimerRegs *) Watchdog_module->device[i].baseAddr;
372 if (Watchdog_module->status[i] == Watchdog_Mode_ENABLED) {
373 /* Configure the timer */
374 initTimer(timer, FALSE);
376 /* Enable timer */
377 while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TCLR);
378 timer->tclr |= 1;
379 }
380 }
381 }