Add support for watchdog timer interrupts on DRA7xx 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 /* Registers for clock management of timers in IPU power domain */
77 #define CM_CORE_AON__IPU_SIZE             0x100
78 #define CM_CORE_AON__IPU_BASE             0x4A005500
79 #define CM_IPU_CLKSTCTRL_OFFSET           0x40
80 #define CM_IPU_TIMER5_CLKCTRL_OFFSET      0x58
81 #define CM_IPU_TIMER6_CLKCTRL_OFFSET      0x60
82 #define CM_IPU_TIMER7_CLKCTRL_OFFSET      0x68
83 #define CM_IPU_TIMER8_CLKCTRL_OFFSET      0x70
85 /* Timer base addresses and size */
86 #define GPTIMER4_BASE 0x48036000
87 #define GPTIMER9_BASE 0x4803E000
88 #define TIMER_REG_SIZE 0x1000
90 /*
91  * Interrupts for GPTimers used as watchdog
92  * They correspond to MPU_IRQ numbers + 32
93  */
94 #define VAYU_IRQ_GPT4 (40 + 32)
95 #define VAYU_IRQ_GPT9 (45 + 32)
97 typedef enum {
98     GPTIMER_4 = 0,
99     GPTIMER_9,
100     GPTIMER_MAX
101 } gpt_Nums;
103 /* GPTimer registers */
104 typedef struct gpt_Regs {
105     uint32_t tidr;
106     uint32_t space[3];
107     uint32_t tiocp_cfg;
108     uint32_t space1[3];
109     uint32_t eoi;
110     uint32_t irqstatus_raw;
111     uint32_t irqstatus;
112     uint32_t irqenable_set;
113     uint32_t irqenable_clr;
114     uint32_t irqwakeen;
115     uint32_t tclr;
116     uint32_t tcrr;
117     uint32_t tldr;
118     uint32_t ttgr;
119     uint32_t twps;
120     uint32_t tmar;
121     uint32_t tcar1;
122     uint32_t tsicr;
123     uint32_t tcar2;
124     uint32_t tpir;
125     uint32_t tnir;
126     uint32_t tcvr;
127     uint32_t tocr;
128     uint32_t towr;
129 } gpt_Regs;
131 /*
132  * Defines the state object, which contains all the module
133  * specific information.
134  */
135 struct gpt_module_object {
136     uintptr_t cmCoreAonBaseVa;
137     /* base address to CM_CORE_AON__IPU */
138     bool isSetup;
139     /* Indicates whether the ipu_pm module is setup. */
140     OsalIsr_Handle gpt4IsrObject;
141     /* ISR handle for gpt4 WDT */
142     OsalIsr_Handle gpt9IsrObject;
143     /* ISR handle for gpt9 WDT */
144     void *         gpt4BaseAddr;
145     /* Base address of GPTimer 4 registers */
146     void *         gpt9BaseAddr;
147     /* Base address of GPTimer 9 registers */
148     ProcMgr_Handle proc_handles[MultiProc_MAXPROCESSORS];
149     /* Array of processor handles */
150 };
152 static struct gpt_module_object gptState = {
153     .cmCoreAonBaseVa = NULL,
154     .isSetup = false
155 };
157 /* Enable a particular timer by setting its module mode */
158 static int enable(uintptr_t reg)
160     int max_tries = DELAY;
162     out32(reg, MOD_ENABLE);
163     do {
164         if (!(in32(reg) & IDLEST_MASK)) {
165             break;
166         }
167     } while (--max_tries);
169     if (max_tries == 0) {
170         return -EIO;
171     }
172     else {
173         return EOK;
174     }
177 /* Disable a particular timer by setting its module mode */
178 static int disable(uintptr_t reg)
180     uint32_t value = 0;
182     /*Check if Clock is Enabled*/
183     value = in32(reg);
184     if ((value & MODULEMODE_MASK) == MOD_ENABLE) {
185         /*Disable the Timer*/
186         value &= MOD_DISABLE;
187         out32(reg, value);
188     }
190     return EOK;
193 /* Enable GP timers (only the ones in PD_IPU for now) */
194 static int gpt_enable()
196     /* make sure abe clock domain is enabled as it is source for gpt5-8 */
197     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
198         SW_WKUP);
200     /* Set module mode for each timer */
201     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET)
202         != EOK) {
203         return -EIO;
204     }
206     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET)
207         != EOK) {
208         return -EIO;
209     }
211     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET)
212         != EOK) {
213         return -EIO;
214     }
216     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET)
217         != EOK) {
218         return -EIO;
219     }
221     return EOK;
224 /* Disable GP timers (only the ones in PD_IPU for now) */
225 static int gpt_disable()
227     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET);
228     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET);
229     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET);
230     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET);
232     /* put abe clock domain back to HW_AUTO mode */
233     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
234         HW_AUTO);
236     return EOK;
239 /* Setup module */
240 int gpt_setup()
242     int retval = EOK;
244     if (gptState.isSetup == false) {
245         gptState.isSetup = true;
247         gptState.cmCoreAonBaseVa = (uintptr_t)mmap_device_io(
248             CM_CORE_AON__IPU_SIZE, CM_CORE_AON__IPU_BASE);
249         if((uintptr_t)gptState.cmCoreAonBaseVa == MAP_DEVICE_FAILED) {
250             gptState.cmCoreAonBaseVa = NULL;
251             retval = -errno;
252             goto exit;
253         }
255         gpt_enable();
257         gptState.gpt4BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
258             GPTIMER4_BASE);
259         if ((uintptr_t)gptState.gpt4BaseAddr == MAP_DEVICE_FAILED) {
260             retval = -ENOMEM;
261             gptState.gpt4BaseAddr = NULL;
262             goto exit;
263         }
265         gptState.gpt9BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
266             GPTIMER9_BASE);
267         if ((uintptr_t)gptState.gpt9BaseAddr == MAP_DEVICE_FAILED) {
268             retval = -ENOMEM;
269             gptState.gpt9BaseAddr = NULL;
270             goto exit;
271         }
272     }
274 exit:
275     if (retval != EOK) {
276         gpt_destroy();
277     }
278     return retval;
281 /* Finalize module */
282 int gpt_destroy()
284     if (gptState.isSetup) {
285         if (gptState.gpt9BaseAddr) {
286             munmap((void *)gptState.gpt9BaseAddr, TIMER_REG_SIZE);
287             gptState.gpt9BaseAddr = NULL;
288         }
290         if (gptState.gpt4BaseAddr) {
291             munmap((void *)gptState.gpt4BaseAddr, TIMER_REG_SIZE);
292             gptState.gpt4BaseAddr = NULL;
293         }
295         gpt_disable();
297         if (gptState.cmCoreAonBaseVa) {
298             munmap((void *)gptState.cmCoreAonBaseVa, CM_CORE_AON__IPU_SIZE);
299             gptState.cmCoreAonBaseVa = NULL;
300         }
302         gptState.isSetup = false;
303     }
304     return EOK;
307 /* Watchdog interrupt handler */
308 static Bool gpt_interrupt(Ptr fxnArgs)
310     int num;
311     /* Using IPU2's id since that is the offically supported IPU */
312     uint16_t ipu2_id = MultiProc_getId("IPU2");
314     /* Trigger recovery by setting the ProcMgr state */
315     switch ((uint32_t)fxnArgs) {
316         case GPTIMER_4:
317             num = 4;
318             ProcMgr_setState(gptState.proc_handles[ipu2_id],
319                 ProcMgr_State_Watchdog);
320             break;
321         case GPTIMER_9:
322             num = 9;
323             ProcMgr_setState(gptState.proc_handles[ipu2_id],
324                 ProcMgr_State_Watchdog);
325             break;
326         default:
327             num = 0;
328             break;
329     }
331     GT_1trace(curTrace, GT_4CLASS,
332               "ipu_pm_gptimer_interrupt: GPTimer %d expired!", num);
334     return 0;
337 /* Interrupt clear function*/
338 static Bool gpt_clr_interrupt(Ptr fxnArgs)
340     uintptr_t reg;
341     uint32_t num = (uint32_t)fxnArgs;
342     gpt_Regs *GPTRegs = NULL;
344     if (num == GPTIMER_4) {
345         GPTRegs = gptState.gpt4BaseAddr;
346     }
347     else if (num == GPTIMER_9) {
348         GPTRegs = gptState.gpt9BaseAddr;
349     }
350     else {
351         return TRUE;
352     }
354     reg = in32((uintptr_t)&GPTRegs->irqstatus);
355     reg |= 0x2;
357     /*Clear Overflow event */
358     out32((uintptr_t)&GPTRegs->irqstatus, reg);
359     reg = in32((uintptr_t)&GPTRegs->irqstatus);
361     /*Always return TRUE for ISR*/
362     return TRUE;
366 /* Wire the Watchdog interrupts to trigger recovery */
367 int gpt_wdt_attach(int proc_id)
369     int retval = EOK;
370     OsalIsr_Params isrParams;
372     if (proc_id > MultiProc_MAXPROCESSORS) {
373         return -EINVAL;
374     }
376     if ((proc_id == MultiProc_getId("IPU1")) ||
377         (proc_id == MultiProc_getId("IPU2"))) {
378         isrParams.checkAndClearFxn = gpt_clr_interrupt;
379         isrParams.fxnArgs = (Ptr)GPTIMER_9;
380         isrParams.intId = VAYU_IRQ_GPT9;
381         isrParams.sharedInt = FALSE;
382         gptState.gpt9IsrObject =
383             OsalIsr_create(&gpt_interrupt,
384                            isrParams.fxnArgs, &isrParams);
385         if(gptState.gpt9IsrObject != NULL) {
386             if (OsalIsr_install(gptState.gpt9IsrObject) < 0) {
387                 retval = -ENOMEM;
388             }
389         }
390         else {
391             retval = -ENOMEM;
392         }
394         isrParams.checkAndClearFxn = gpt_clr_interrupt;
395         isrParams.fxnArgs = (Ptr)GPTIMER_4;
396         isrParams.intId = VAYU_IRQ_GPT4;
397         isrParams.sharedInt = FALSE;
398         gptState.gpt4IsrObject =
399             OsalIsr_create(&gpt_interrupt,
400                            isrParams.fxnArgs, &isrParams);
401         if(gptState.gpt4IsrObject != NULL) {
402             if (OsalIsr_install(gptState.gpt4IsrObject) < 0) {
403                 retval = -ENOMEM;
404             }
405         }
406         else {
407             retval = -ENOMEM;
408         }
409     }
411     if ((retval >= 0) &&
412         (gptState.proc_handles[MultiProc_getId("IPU2")] == NULL)) {
413         /* Using IPU2's entry since it is the offically supported IPU */
414         retval = ProcMgr_open(&gptState.proc_handles[MultiProc_getId("IPU2")],
415             proc_id);
416     }
417     else {
418         if ((proc_id == MultiProc_getId("IPU1")) ||
419             (proc_id == MultiProc_getId("IPU2"))) {
420             if (gptState.gpt9IsrObject) {
421                 OsalIsr_uninstall(gptState.gpt9IsrObject);
422                 OsalIsr_delete(&gptState.gpt9IsrObject);
423                 gptState.gpt9IsrObject = NULL;
424             }
426             if (gptState.gpt4IsrObject) {
427                 OsalIsr_uninstall(gptState.gpt4IsrObject);
428                 OsalIsr_delete(&gptState.gpt4IsrObject);
429                 gptState.gpt4IsrObject = NULL;
430             }
431         }
432     }
434     return retval;
437 /* Un-hook the Watchdog interrupt handler */
438 int gpt_wdt_detach(int proc_id)
440     int retval = EOK;
442     if (proc_id > MultiProc_MAXPROCESSORS) {
443         return -EINVAL;
444     }
446     if ((proc_id == MultiProc_getId("IPU1")) ||
447         (proc_id == MultiProc_getId("IPU2"))) {
448         OsalIsr_uninstall(gptState.gpt9IsrObject);
449         OsalIsr_delete(&gptState.gpt9IsrObject);
450         gptState.gpt9IsrObject = NULL;
452         OsalIsr_uninstall(gptState.gpt4IsrObject);
453         OsalIsr_delete(&gptState.gpt4IsrObject);
454         gptState.gpt4IsrObject = NULL;
455     }
457     /* Using IPU2's entry since it is the offically supported IPU */
458     if (gptState.proc_handles[MultiProc_getId("IPU2")]) {
459         ProcMgr_close(&gptState.proc_handles[MultiProc_getId("IPU2")]);
460         gptState.proc_handles[MultiProc_getId("IPU2")] = NULL;
461     }
463     return retval;