QNX: DRA7XX: Fix Compilation Warnings
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / family / vayu / Gpt.c
1 /*
2  * Copyright (c) 2014-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  */
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 <Gpt.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 /* Size of timer register sets */
90 #define TIMER_REG_SIZE 0x1000
92 /* Timer physical base addresses */
93 static uint32_t gptPhyBase[GPT_TIMER_NUM] = {
94     0x4AE18000,  /* GPT_TIMER_1  */
95     0x48032000,  /* GPT_TIMER_2  */
96     0x48034000,  /* GPT_TIMER_3  */
97     0x48036000,  /* GPT_TIMER_4  */
98     0x48820000,  /* GPT_TIMER_5  */
99     0x48822000,  /* GPT_TIMER_6  */
100     0x48824000,  /* GPT_TIMER_7  */
101     0x48826000,  /* GPT_TIMER_8  */
102     0x4803E000,  /* GPT_TIMER_9  */
103     0x48086000,  /* GPT_TIMER_10 */
104     0x48088000,  /* GPT_TIMER_11 */
105 };
107 /*
108  * Interrupts for GPTimers used as watchdog
109  * They correspond to MPU_IRQ numbers + 32
110  * This works for Timers 1-11
111  */
112 #define VAYU_IRQ_GPT(x)  (37 + (x) + 32)
114 /* GPTimer registers */
115 typedef struct Gpt_Regs {
116     uint32_t tidr;
117     uint32_t space[3];
118     uint32_t tiocp_cfg;
119     uint32_t space1[3];
120     uint32_t eoi;
121     uint32_t irqstatus_raw;
122     uint32_t irqstatus;
123     uint32_t irqenable_set;
124     uint32_t irqenable_clr;
125     uint32_t irqwakeen;
126     uint32_t tclr;
127     uint32_t tcrr;
128     uint32_t tldr;
129     uint32_t ttgr;
130     uint32_t twps;
131     uint32_t tmar;
132     uint32_t tcar1;
133     uint32_t tsicr;
134     uint32_t tcar2;
135     uint32_t tpir;
136     uint32_t tnir;
137     uint32_t tcvr;
138     uint32_t tocr;
139     uint32_t towr;
140 } Gpt_Regs;
142 /*
143  * Defines the state object, which contains all the module
144  * specific information.
145  */
146 struct Gpt_module_object {
147     uintptr_t cmCoreAonBaseVa;
148     /* base address to CM_CORE_AON__IPU */
149     bool isSetup;
150     /* Indicates whether the module is setup. */
151     bool isAttached[MultiProc_MAXPROCESSORS];
152     /* Indicates whether the module is attached. */
153     OsalIsr_Handle gptIsrObjects[GPT_TIMER_NUM];
154     /* ISR handle for Watchdog timers */
155     void *         gptBaseAddr[GPT_TIMER_NUM];
156     /* Virtual base addresses of GPTimer registers */
157     ProcMgr_Handle proc_handles[MultiProc_MAXPROCESSORS];
158     /* Array of processor handles */
159     char **  wdtOwnerProcessor;
160     /* Define the processor which owns a given gptimer as watchdog timer */
161 };
163 static struct Gpt_module_object gptState = {
164     .cmCoreAonBaseVa = 0,
165     .isSetup = false
166 };
168 /* Enable a particular timer by setting its module mode */
169 static int enable(uintptr_t reg)
171     int max_tries = DELAY;
173     out32(reg, MOD_ENABLE);
174     do {
175         if (!(in32(reg) & IDLEST_MASK)) {
176             break;
177         }
178     } while (--max_tries);
180     if (max_tries == 0) {
181         return -EIO;
182     }
183     else {
184         return EOK;
185     }
188 /* Disable a particular timer by setting its module mode */
189 static int disable(uintptr_t reg)
191     uint32_t value = 0;
193     /*Check if Clock is Enabled*/
194     value = in32(reg);
195     if ((value & MODULEMODE_MASK) == MOD_ENABLE) {
196         /*Disable the Timer*/
197         value &= MOD_DISABLE;
198         out32(reg, value);
199     }
201     return EOK;
204 /* Enable GP timers (only the ones in PD_IPU for now) */
205 static int Gpt_enable()
207     /* make sure abe clock domain is enabled as it is source for gpt5-8 */
208     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
209         SW_WKUP);
211     /* Set module mode for each timer */
212     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET)
213         != EOK) {
214         return -EIO;
215     }
217     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET)
218         != EOK) {
219         return -EIO;
220     }
222     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET)
223         != EOK) {
224         return -EIO;
225     }
227     if (enable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET)
228         != EOK) {
229         return -EIO;
230     }
232     return EOK;
235 /* Disable GP timers (only the ones in PD_IPU for now) */
236 static int Gpt_disable()
238     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER5_CLKCTRL_OFFSET);
239     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER6_CLKCTRL_OFFSET);
240     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER7_CLKCTRL_OFFSET);
241     disable(gptState.cmCoreAonBaseVa + CM_IPU_TIMER8_CLKCTRL_OFFSET);
243     /* put abe clock domain back to HW_AUTO mode */
244     out32((uintptr_t)(gptState.cmCoreAonBaseVa + CM_IPU_CLKSTCTRL_OFFSET),
245         HW_AUTO);
247     return EOK;
250 /* Setup module */
251 int Gpt_setup(Gpt_Config * cfg)
253     int i;
254     int retval = EOK;
256     if (cfg == NULL) {
257         return -EINVAL;
258     }
260     if (gptState.isSetup == false) {
261         gptState.isSetup = true;
263         gptState.wdtOwnerProcessor = cfg->wdtOwnerProcessor;
265         memset(gptState.gptIsrObjects, 0, sizeof(gptState.gptIsrObjects));
266         memset(gptState.proc_handles, 0, sizeof(gptState.proc_handles));
268         gptState.cmCoreAonBaseVa = (uintptr_t)mmap_device_io(
269             CM_CORE_AON__IPU_SIZE, CM_CORE_AON__IPU_BASE);
270         if((uintptr_t)gptState.cmCoreAonBaseVa == MAP_DEVICE_FAILED) {
271             gptState.cmCoreAonBaseVa = 0;
272             retval = -errno;
273             goto exit;
274         }
276         Gpt_enable();
278         /* Map registers for watchdog timers */
279         for (i = 0; i < GPT_TIMER_NUM; i++) {
280             if (gptState.wdtOwnerProcessor[i] != NULL) {
281                 gptState.gptBaseAddr[i] = (void *)mmap_device_io(
282                     TIMER_REG_SIZE, gptPhyBase[i]);
283                 if ((uintptr_t)gptState.gptBaseAddr[i] ==
284                     MAP_DEVICE_FAILED) {
285                     retval = -ENOMEM;
286                     gptState.gptBaseAddr[i] = NULL;
287                     goto exit;
288                 }
289             }
290             else {
291                 gptState.gptBaseAddr[i] = NULL;
292             }
293         }
294     }
296 exit:
297     if (retval != EOK) {
298         Gpt_destroy();
299     }
300     return retval;
303 /* Finalize module */
304 int Gpt_destroy()
306     int i;
308     if (gptState.isSetup) {
309         /* Unmap registers for watchdog timers */
310         for (i = 0; i < GPT_TIMER_NUM; i++) {
311             if (gptState.gptBaseAddr[i] != NULL) {
312                 munmap((void *)gptState.gptBaseAddr[i], TIMER_REG_SIZE);
313                 gptState.gptBaseAddr[i] = NULL;
314             }
315         }
317         Gpt_disable();
319         if (gptState.cmCoreAonBaseVa) {
320             munmap((void *)gptState.cmCoreAonBaseVa, CM_CORE_AON__IPU_SIZE);
321             gptState.cmCoreAonBaseVa = 0;
322         }
324         gptState.isSetup = false;
325     }
326     return EOK;
329 /* Watchdog interrupt handler */
330 static Bool Gpt_interrupt(Ptr fxnArgs)
332     Gpt_Nums       timer = (Gpt_Nums)fxnArgs;
333     int            num = timer + 1;   /* GP timer number */
334     ProcMgr_Handle procHandle;
336     /* Trigger recovery by setting the ProcMgr state */
337     if (gptState.wdtOwnerProcessor[timer] != NULL) {
338         procHandle = gptState.proc_handles[MultiProc_getId(
339             gptState.wdtOwnerProcessor[timer])];
340         if (procHandle != NULL) {
341             ProcMgr_setState(procHandle, ProcMgr_State_Watchdog);
342         }
344     }
346     GT_1trace(curTrace, GT_4CLASS,
347           "Gpt_interrupt: GPTimer %d expired!", num);
349     return 0;
352 /* Interrupt clear function*/
353 static Bool Gpt_clr_interrupt(Ptr fxnArgs)
355     uintptr_t reg;
356     Gpt_Nums timer = (Gpt_Nums)fxnArgs;
357     Gpt_Regs *gptRegs = NULL;
359     gptRegs = gptState.gptBaseAddr[timer];
361     if (gptRegs == NULL) {
362         return TRUE;
363     }
365     reg = in32((uintptr_t)&gptRegs->irqstatus);
366     reg |= 0x2;
368     /*Clear Overflow event */
369     out32((uintptr_t)&gptRegs->irqstatus, reg);
370     reg = in32((uintptr_t)&gptRegs->irqstatus);
372     /*Always return TRUE for ISR*/
373     return TRUE;
376 /* Stop watchdog timer */
377 static void Gpt_wdt_stop(int num)
379     uintptr_t reg;
380     Gpt_Regs *gptRegs = NULL;
382     gptRegs = gptState.gptBaseAddr[num];
384     if (gptRegs == NULL) {
385         return;
386     }
388     reg = in32((uintptr_t)&gptRegs->tclr);
389     reg &= GPT_TCLR_STOP_MASK;
391     /* Clear Overflow event */
392     out32((uintptr_t)&gptRegs->tclr, reg);
394     reg = in32((uintptr_t)&gptRegs->twps);
395     while (reg & GPT_TWPS_W_PEND_TCLR) {
396         reg = in32((uintptr_t)&gptRegs->twps);
397     }
399     /* Clear status bits */
400     reg = in32((uintptr_t)&gptRegs->irqstatus);
401     if (reg) {
402         out32((uintptr_t)&gptRegs->irqstatus, reg);
403     }
406 /* Wire the Watchdog interrupts to trigger recovery */
407 int Gpt_wdt_attach(int proc_id)
409     int retval = EOK;
410     int i;
411     OsalIsr_Params isrParams;
413     if (proc_id > MultiProc_MAXPROCESSORS) {
414         return -EINVAL;
415     }
417     /* Only do the setup once per processor */
418     if (gptState.isAttached[proc_id]) {
419         return EOK;
420     }
422     gptState.isAttached[proc_id] = true;
424     for (i = 0; i < GPT_TIMER_NUM; i++) {
425         if ((gptState.wdtOwnerProcessor[i] != NULL) &&
426             (strcmp(gptState.wdtOwnerProcessor[i], MultiProc_getName(proc_id))
427             == 0)) {
428             isrParams.checkAndClearFxn = Gpt_clr_interrupt;
429             isrParams.fxnArgs = (Ptr)i;
430             isrParams.intId = VAYU_IRQ_GPT(i);
431             isrParams.sharedInt = FALSE;
432             gptState.gptIsrObjects[i] =
433                 OsalIsr_create(&Gpt_interrupt,
434                            isrParams.fxnArgs, &isrParams);
435             if (gptState.gptIsrObjects[i] != NULL) {
436                 if (OsalIsr_install(gptState.gptIsrObjects[i]) < 0) {
437                     retval = -ENOMEM;
438                 }
439             }
440             else {
441                 retval = -ENOMEM;
442             }
444             if (retval >= 0) {
445                 if (gptState.proc_handles[proc_id] == NULL) {
446                     retval = ProcMgr_open(&gptState.proc_handles[proc_id], proc_id);
447                     if (retval < 0) {
448                         Gpt_wdt_detach(proc_id);
449                         retval = -EPERM;
450                         break;
451                     }
452                 }
453             }
454             else {
455                 if (gptState.gptIsrObjects[i]) {
456                     OsalIsr_delete(&gptState.gptIsrObjects[i]);
457                     gptState.gptIsrObjects[i] = NULL;
458                 }
459                 break;
460             }
461         }
462     }
464     return retval;
467 /* Un-hook the Watchdog interrupt handler */
468 int Gpt_wdt_detach(int proc_id)
470     int i;
472     if (proc_id > MultiProc_MAXPROCESSORS) {
473         return -EINVAL;
474     }
476     if (gptState.isAttached[proc_id]) {
477         for (i = 0; i < GPT_TIMER_NUM; i++) {
478             if ((gptState.wdtOwnerProcessor[i] != NULL) &&
479                 (strcmp(gptState.wdtOwnerProcessor[i],
480                 MultiProc_getName(proc_id))) == 0) {
481                 /*
482                  * Stop the watchdog timers. We rely on the slave processors to
483                  * start them, but on unload the host should stop them to avoid
484                  * getting watchdog interrupts upon reload.
485                  */
486                 Gpt_wdt_stop(i);
488                 if (gptState.gptIsrObjects[i]) {
489                     OsalIsr_uninstall(gptState.gptIsrObjects[i]);
490                     OsalIsr_delete(&gptState.gptIsrObjects[i]);
491                     gptState.gptIsrObjects[i] = NULL;
492                 }
493                 if (gptState.proc_handles[proc_id]) {
494                     ProcMgr_close(&gptState.proc_handles[proc_id]);
495                     gptState.proc_handles[proc_id] = NULL;
496                 }
497             }
498         }
500         gptState.isAttached[proc_id] = false;
501     }
503     return EOK;