Stop watchdog timers when shutting down VAYU IPU
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / family / vayu / gptimers.c
1 /*
2  * Copyright (c) 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  */
33 /* Standard headers */
34 #include <ti/syslink/Std.h>
36 /* QNX specific header include */
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdbool.h>
41 #include <hw/inout.h>
42 #include <sys/mman.h>
44 #include <OsalIsr.h>
45 #include <ti/syslink/ProcMgr.h>
46 #include <ti/syslink/utils/Trace.h>
47 #include <MultiProc.h>
48 #include <_MultiProc.h>
49 #include <gptimers.h>
52 /* Start a software forced wake-up */
53 #define SW_WKUP                           0x2
55 /* Start a software forced wake-up */
56 #define HW_AUTO                           0x3
58 /* Explicitly enable a module */
59 #define MOD_ENABLE                        0x2
61 /* Disable a module */
62 #define MOD_DISABLE                       0xFFFFFFFC
64 /*
65  * Empirically determined delay that is necessary between when the clock domain
66  * is enabled and when the status bit is updated
67  */
68 #define DELAY                             100
70 /* Module idle status mask */
71 #define IDLEST_MASK                       0x30000
73 /* Module mode mask */
74 #define MODULEMODE_MASK                   0x3
76 /* Masks for timer registers */
77 #define GPT_TWPS_W_PEND_TCLR              0x1
78 #define GPT_TCLR_STOP_MASK                0xfffffffe
80 /* Registers for clock management of timers in IPU power domain */
81 #define CM_CORE_AON__IPU_SIZE             0x100
82 #define CM_CORE_AON__IPU_BASE             0x4A005500
83 #define CM_IPU_CLKSTCTRL_OFFSET           0x40
84 #define CM_IPU_TIMER5_CLKCTRL_OFFSET      0x58
85 #define CM_IPU_TIMER6_CLKCTRL_OFFSET      0x60
86 #define CM_IPU_TIMER7_CLKCTRL_OFFSET      0x68
87 #define CM_IPU_TIMER8_CLKCTRL_OFFSET      0x70
89 /* Timer base addresses and size */
90 #define GPTIMER4_BASE 0x48036000
91 #define GPTIMER9_BASE 0x4803E000
92 #define TIMER_REG_SIZE 0x1000
94 /*
95  * Interrupts for GPTimers used as watchdog
96  * They correspond to MPU_IRQ numbers + 32
97  */
98 #define VAYU_IRQ_GPT4 (40 + 32)
99 #define VAYU_IRQ_GPT9 (45 + 32)
101 typedef enum {
102     GPTIMER_4 = 0,
103     GPTIMER_9,
104     GPTIMER_MAX
105 } gpt_Nums;
107 /* GPTimer registers */
108 typedef struct gpt_Regs {
109     uint32_t tidr;
110     uint32_t space[3];
111     uint32_t tiocp_cfg;
112     uint32_t space1[3];
113     uint32_t eoi;
114     uint32_t irqstatus_raw;
115     uint32_t irqstatus;
116     uint32_t irqenable_set;
117     uint32_t irqenable_clr;
118     uint32_t irqwakeen;
119     uint32_t tclr;
120     uint32_t tcrr;
121     uint32_t tldr;
122     uint32_t ttgr;
123     uint32_t twps;
124     uint32_t tmar;
125     uint32_t tcar1;
126     uint32_t tsicr;
127     uint32_t tcar2;
128     uint32_t tpir;
129     uint32_t tnir;
130     uint32_t tcvr;
131     uint32_t tocr;
132     uint32_t towr;
133 } gpt_Regs;
135 /*
136  * Defines the state object, which contains all the module
137  * specific information.
138  */
139 struct gpt_module_object {
140     uintptr_t cmCoreAonBaseVa;
141     /* base address to CM_CORE_AON__IPU */
142     bool isSetup;
143     /* Indicates whether the module is setup. */
144     bool isAttached;
145     /* Indicates whether the module is attached. */
146     OsalIsr_Handle gpt4IsrObject;
147     /* ISR handle for gpt4 WDT */
148     OsalIsr_Handle gpt9IsrObject;
149     /* ISR handle for gpt9 WDT */
150     void *         gpt4BaseAddr;
151     /* Base address of GPTimer 4 registers */
152     void *         gpt9BaseAddr;
153     /* Base address of GPTimer 9 registers */
154     ProcMgr_Handle proc_handles[MultiProc_MAXPROCESSORS];
155     /* Array of processor handles */
156 };
158 static struct gpt_module_object gptState = {
159     .cmCoreAonBaseVa = NULL,
160     .isSetup = false
161 };
163 /* Enable a particular timer by setting its module mode */
164 static int enable(uintptr_t reg)
166     int max_tries = DELAY;
168     out32(reg, MOD_ENABLE);
169     do {
170         if (!(in32(reg) & IDLEST_MASK)) {
171             break;
172         }
173     } while (--max_tries);
175     if (max_tries == 0) {
176         return -EIO;
177     }
178     else {
179         return EOK;
180     }
183 /* Disable a particular timer by setting its module mode */
184 static int disable(uintptr_t reg)
186     uint32_t value = 0;
188     /*Check if Clock is Enabled*/
189     value = in32(reg);
190     if ((value & MODULEMODE_MASK) == MOD_ENABLE) {
191         /*Disable the Timer*/
192         value &= MOD_DISABLE;
193         out32(reg, value);
194     }
196     return EOK;
199 /* Enable GP timers (only the ones in PD_IPU for now) */
200 static int gpt_enable()
202     /* make sure abe clock domain is enabled as it is source for gpt5-8 */
203     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
204         SW_WKUP);
206     /* Set module mode for each timer */
207     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET)
208         != EOK) {
209         return -EIO;
210     }
212     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET)
213         != EOK) {
214         return -EIO;
215     }
217     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET)
218         != EOK) {
219         return -EIO;
220     }
222     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET)
223         != EOK) {
224         return -EIO;
225     }
227     return EOK;
230 /* Disable GP timers (only the ones in PD_IPU for now) */
231 static int gpt_disable()
233     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET);
234     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET);
235     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET);
236     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET);
238     /* put abe clock domain back to HW_AUTO mode */
239     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
240         HW_AUTO);
242     return EOK;
245 /* Setup module */
246 int gpt_setup()
248     int retval = EOK;
250     if (gptState.isSetup == false) {
251         gptState.isSetup = true;
253         gptState.cmCoreAonBaseVa = (uintptr_t)mmap_device_io(
254             CM_CORE_AON__IPU_SIZE, CM_CORE_AON__IPU_BASE);
255         if((uintptr_t)gptState.cmCoreAonBaseVa == MAP_DEVICE_FAILED) {
256             gptState.cmCoreAonBaseVa = NULL;
257             retval = -errno;
258             goto exit;
259         }
261         gpt_enable();
263         gptState.gpt4BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
264             GPTIMER4_BASE);
265         if ((uintptr_t)gptState.gpt4BaseAddr == MAP_DEVICE_FAILED) {
266             retval = -ENOMEM;
267             gptState.gpt4BaseAddr = NULL;
268             goto exit;
269         }
271         gptState.gpt9BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
272             GPTIMER9_BASE);
273         if ((uintptr_t)gptState.gpt9BaseAddr == MAP_DEVICE_FAILED) {
274             retval = -ENOMEM;
275             gptState.gpt9BaseAddr = NULL;
276             goto exit;
277         }
278     }
280 exit:
281     if (retval != EOK) {
282         gpt_destroy();
283     }
284     return retval;
287 /* Finalize module */
288 int gpt_destroy()
290     if (gptState.isSetup) {
291         if (gptState.gpt9BaseAddr) {
292             munmap((void *)gptState.gpt9BaseAddr, TIMER_REG_SIZE);
293             gptState.gpt9BaseAddr = NULL;
294         }
296         if (gptState.gpt4BaseAddr) {
297             munmap((void *)gptState.gpt4BaseAddr, TIMER_REG_SIZE);
298             gptState.gpt4BaseAddr = NULL;
299         }
301         gpt_disable();
303         if (gptState.cmCoreAonBaseVa) {
304             munmap((void *)gptState.cmCoreAonBaseVa, CM_CORE_AON__IPU_SIZE);
305             gptState.cmCoreAonBaseVa = NULL;
306         }
308         gptState.isSetup = false;
309     }
310     return EOK;
313 /* Watchdog interrupt handler */
314 static Bool gpt_interrupt(Ptr fxnArgs)
316     int num;
317     /* Using IPU2's id since that is the offically supported IPU */
318     uint16_t ipu2_id = MultiProc_getId("IPU2");
320     /* Trigger recovery by setting the ProcMgr state */
321     switch ((uint32_t)fxnArgs) {
322         case GPTIMER_4:
323             num = 4;
324             ProcMgr_setState(gptState.proc_handles[ipu2_id],
325                 ProcMgr_State_Watchdog);
326             break;
327         case GPTIMER_9:
328             num = 9;
329             ProcMgr_setState(gptState.proc_handles[ipu2_id],
330                 ProcMgr_State_Watchdog);
331             break;
332         default:
333             num = 0;
334             break;
335     }
337     GT_1trace(curTrace, GT_4CLASS,
338               "gpt_interrupt: GPTimer %d expired!", num);
340     return 0;
343 /* Interrupt clear function*/
344 static Bool gpt_clr_interrupt(Ptr fxnArgs)
346     uintptr_t reg;
347     uint32_t num = (uint32_t)fxnArgs;
348     gpt_Regs *GPTRegs = NULL;
350     if (num == GPTIMER_4) {
351         GPTRegs = gptState.gpt4BaseAddr;
352     }
353     else if (num == GPTIMER_9) {
354         GPTRegs = gptState.gpt9BaseAddr;
355     }
356     else {
357         return TRUE;
358     }
360     reg = in32((uintptr_t)&GPTRegs->irqstatus);
361     reg |= 0x2;
363     /*Clear Overflow event */
364     out32((uintptr_t)&GPTRegs->irqstatus, reg);
365     reg = in32((uintptr_t)&GPTRegs->irqstatus);
367     /*Always return TRUE for ISR*/
368     return TRUE;
371 /* Stop watchdog timer */
372 static void gpt_wdt_stop(int num)
374     uintptr_t reg;
375     gpt_Regs *GPTRegs = NULL;
377     if (num == GPTIMER_4) {
378         GPTRegs = gptState.gpt4BaseAddr;
379     }
380     else if (num == GPTIMER_9) {
381         GPTRegs = gptState.gpt9BaseAddr;
382     }
383     else {
384         return;
385     }
387     reg = in32((uintptr_t)&GPTRegs->tclr);
388     reg &= GPT_TCLR_STOP_MASK;
390     /* Clear Overflow event */
391     out32((uintptr_t)&GPTRegs->tclr, reg);
393     reg = in32((uintptr_t)&GPTRegs->twps);
394     while (reg & GPT_TWPS_W_PEND_TCLR) {
395         reg = in32((uintptr_t)&GPTRegs->twps);
396     }
398     /* Clear status bits */
399     reg = in32((uintptr_t)&GPTRegs->irqstatus);
400     if (reg) {
401         out32((uintptr_t)&GPTRegs->irqstatus, reg);
402     }
405 /* Wire the Watchdog interrupts to trigger recovery */
406 int gpt_wdt_attach(int proc_id)
408     int retval = EOK;
409     OsalIsr_Params isrParams;
411     if (proc_id > MultiProc_MAXPROCESSORS) {
412         return -EINVAL;
413     }
415     /* Only do the setup once since we only have two watchdog timers */
416     if (gptState.isAttached) {
417         return EOK;
418     }
420     if ((proc_id == MultiProc_getId("IPU1")) ||
421         (proc_id == MultiProc_getId("IPU2"))) {
422         gptState.isAttached = true;
423         isrParams.checkAndClearFxn = gpt_clr_interrupt;
424         isrParams.fxnArgs = (Ptr)GPTIMER_9;
425         isrParams.intId = VAYU_IRQ_GPT9;
426         isrParams.sharedInt = FALSE;
427         gptState.gpt9IsrObject =
428             OsalIsr_create(&gpt_interrupt,
429                            isrParams.fxnArgs, &isrParams);
430         if(gptState.gpt9IsrObject != NULL) {
431             if (OsalIsr_install(gptState.gpt9IsrObject) < 0) {
432                 retval = -ENOMEM;
433             }
434         }
435         else {
436             retval = -ENOMEM;
437         }
439         isrParams.checkAndClearFxn = gpt_clr_interrupt;
440         isrParams.fxnArgs = (Ptr)GPTIMER_4;
441         isrParams.intId = VAYU_IRQ_GPT4;
442         isrParams.sharedInt = FALSE;
443         gptState.gpt4IsrObject =
444             OsalIsr_create(&gpt_interrupt,
445                            isrParams.fxnArgs, &isrParams);
446         if(gptState.gpt4IsrObject != NULL) {
447             if (OsalIsr_install(gptState.gpt4IsrObject) < 0) {
448                 retval = -ENOMEM;
449             }
450         }
451         else {
452             retval = -ENOMEM;
453         }
456         if (retval >= 0) {
457             if (gptState.proc_handles[MultiProc_getId("IPU2")] == NULL) {
458                 /* Using IPU2's entry since it is the offically supported IPU */
459                 retval = ProcMgr_open(&gptState.proc_handles[
460                     MultiProc_getId("IPU2")], proc_id);
461             }
462         }
463         else {
464             if ((proc_id == MultiProc_getId("IPU1")) ||
465                 (proc_id == MultiProc_getId("IPU2"))) {
466                 if (gptState.gpt9IsrObject) {
467                     OsalIsr_uninstall(gptState.gpt9IsrObject);
468                     OsalIsr_delete(&gptState.gpt9IsrObject);
469                     gptState.gpt9IsrObject = NULL;
470                 }
472                 if (gptState.gpt4IsrObject) {
473                     OsalIsr_uninstall(gptState.gpt4IsrObject);
474                     OsalIsr_delete(&gptState.gpt4IsrObject);
475                     gptState.gpt4IsrObject = NULL;
476                 }
477             }
478         }
479     }
480     return retval;
483 /* Un-hook the Watchdog interrupt handler */
484 int gpt_wdt_detach(int proc_id)
486     int retval = EOK;
488     if (proc_id > MultiProc_MAXPROCESSORS) {
489         return -EINVAL;
490     }
492     if (gptState.isAttached) {
493         if ((proc_id == MultiProc_getId("IPU1")) ||
494             (proc_id == MultiProc_getId("IPU2"))) {
495             OsalIsr_uninstall(gptState.gpt9IsrObject);
496             OsalIsr_delete(&gptState.gpt9IsrObject);
497             gptState.gpt9IsrObject = NULL;
499             OsalIsr_uninstall(gptState.gpt4IsrObject);
500             OsalIsr_delete(&gptState.gpt4IsrObject);
501             gptState.gpt4IsrObject = NULL;
503             /* Using IPU2's entry since it is the offically supported IPU */
504             if (gptState.proc_handles[MultiProc_getId("IPU2")]) {
505                 ProcMgr_close(&gptState.proc_handles[MultiProc_getId("IPU2")]);
506                 gptState.proc_handles[MultiProc_getId("IPU2")] = NULL;
507             }
509             /*
510              * Stop the watchdog timers. We rely on the slave processors to
511              * start them, but on unload the host should stop them to avoid
512              * getting watchdog interrupts upon reload.
513              */
514             gpt_wdt_stop(GPTIMER_4);
515             gpt_wdt_stop(GPTIMER_9);
517             gptState.isAttached = false;
518         }
519     }
521     return retval;