]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blobdiff - qnx/src/ipc3x_dev/ti/syslink/family/vayu/gptimers.c
Stop watchdog timers when shutting down VAYU IPU
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / family / vayu / gptimers.c
index 1df5a00840c3d0bce3933a222e83a88f98e2d0e6..72558458ad9bba2663e77bfcef951e1bf6cd43bf 100644 (file)
@@ -33,7 +33,7 @@
 /* Standard headers */
 #include <ti/syslink/Std.h>
 
-/*QNX specific header include */
+/* QNX specific header include */
 #include <errno.h>
 #include <unistd.h>
 #include <stdbool.h>
 #include <hw/inout.h>
 #include <sys/mman.h>
 
+#include <OsalIsr.h>
+#include <ti/syslink/ProcMgr.h>
+#include <ti/syslink/utils/Trace.h>
+#include <MultiProc.h>
+#include <_MultiProc.h>
 #include <gptimers.h>
 
 
 /* Module mode mask */
 #define MODULEMODE_MASK                   0x3
 
+/* Masks for timer registers */
+#define GPT_TWPS_W_PEND_TCLR              0x1
+#define GPT_TCLR_STOP_MASK                0xfffffffe
+
 /* Registers for clock management of timers in IPU power domain */
 #define CM_CORE_AON__IPU_SIZE             0x100
 #define CM_CORE_AON__IPU_BASE             0x4A005500
 #define CM_IPU_TIMER7_CLKCTRL_OFFSET      0x68
 #define CM_IPU_TIMER8_CLKCTRL_OFFSET      0x70
 
+/* Timer base addresses and size */
+#define GPTIMER4_BASE 0x48036000
+#define GPTIMER9_BASE 0x4803E000
+#define TIMER_REG_SIZE 0x1000
+
+/*
+ * Interrupts for GPTimers used as watchdog
+ * They correspond to MPU_IRQ numbers + 32
+ */
+#define VAYU_IRQ_GPT4 (40 + 32)
+#define VAYU_IRQ_GPT9 (45 + 32)
+
+typedef enum {
+    GPTIMER_4 = 0,
+    GPTIMER_9,
+    GPTIMER_MAX
+} gpt_Nums;
+
+/* GPTimer registers */
+typedef struct gpt_Regs {
+    uint32_t tidr;
+    uint32_t space[3];
+    uint32_t tiocp_cfg;
+    uint32_t space1[3];
+    uint32_t eoi;
+    uint32_t irqstatus_raw;
+    uint32_t irqstatus;
+    uint32_t irqenable_set;
+    uint32_t irqenable_clr;
+    uint32_t irqwakeen;
+    uint32_t tclr;
+    uint32_t tcrr;
+    uint32_t tldr;
+    uint32_t ttgr;
+    uint32_t twps;
+    uint32_t tmar;
+    uint32_t tcar1;
+    uint32_t tsicr;
+    uint32_t tcar2;
+    uint32_t tpir;
+    uint32_t tnir;
+    uint32_t tcvr;
+    uint32_t tocr;
+    uint32_t towr;
+} gpt_Regs;
+
 /*
  * Defines the state object, which contains all the module
  * specific information.
@@ -85,7 +140,19 @@ struct gpt_module_object {
     uintptr_t cmCoreAonBaseVa;
     /* base address to CM_CORE_AON__IPU */
     bool isSetup;
-    /* Indicates whether the ipu_pm module is setup. */
+    /* Indicates whether the module is setup. */
+    bool isAttached;
+    /* Indicates whether the module is attached. */
+    OsalIsr_Handle gpt4IsrObject;
+    /* ISR handle for gpt4 WDT */
+    OsalIsr_Handle gpt9IsrObject;
+    /* ISR handle for gpt9 WDT */
+    void *         gpt4BaseAddr;
+    /* Base address of GPTimer 4 registers */
+    void *         gpt9BaseAddr;
+    /* Base address of GPTimer 9 registers */
+    ProcMgr_Handle proc_handles[MultiProc_MAXPROCESSORS];
+    /* Array of processor handles */
 };
 
 static struct gpt_module_object gptState = {
@@ -181,6 +248,8 @@ int gpt_setup()
     int retval = EOK;
 
     if (gptState.isSetup == false) {
+        gptState.isSetup = true;
+
         gptState.cmCoreAonBaseVa = (uintptr_t)mmap_device_io(
             CM_CORE_AON__IPU_SIZE, CM_CORE_AON__IPU_BASE);
         if((uintptr_t)gptState.cmCoreAonBaseVa == MAP_DEVICE_FAILED) {
@@ -191,17 +260,26 @@ int gpt_setup()
 
         gpt_enable();
 
-        gptState.isSetup = true;
+        gptState.gpt4BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
+            GPTIMER4_BASE);
+        if ((uintptr_t)gptState.gpt4BaseAddr == MAP_DEVICE_FAILED) {
+            retval = -ENOMEM;
+            gptState.gpt4BaseAddr = NULL;
+            goto exit;
+        }
+
+        gptState.gpt9BaseAddr = (void *)mmap_device_io(TIMER_REG_SIZE,
+            GPTIMER9_BASE);
+        if ((uintptr_t)gptState.gpt9BaseAddr == MAP_DEVICE_FAILED) {
+            retval = -ENOMEM;
+            gptState.gpt9BaseAddr = NULL;
+            goto exit;
+        }
     }
 
 exit:
     if (retval != EOK) {
-        gpt_disable();
-
-        if (gptState.cmCoreAonBaseVa) {
-            munmap((void *)gptState.cmCoreAonBaseVa, CM_CORE_AON__IPU_SIZE);
-            gptState.cmCoreAonBaseVa = NULL;
-        }
+        gpt_destroy();
     }
     return retval;
 }
@@ -210,6 +288,16 @@ exit:
 int gpt_destroy()
 {
     if (gptState.isSetup) {
+        if (gptState.gpt9BaseAddr) {
+            munmap((void *)gptState.gpt9BaseAddr, TIMER_REG_SIZE);
+            gptState.gpt9BaseAddr = NULL;
+        }
+
+        if (gptState.gpt4BaseAddr) {
+            munmap((void *)gptState.gpt4BaseAddr, TIMER_REG_SIZE);
+            gptState.gpt4BaseAddr = NULL;
+        }
+
         gpt_disable();
 
         if (gptState.cmCoreAonBaseVa) {
@@ -221,3 +309,214 @@ int gpt_destroy()
     }
     return EOK;
 }
+
+/* Watchdog interrupt handler */
+static Bool gpt_interrupt(Ptr fxnArgs)
+{
+    int num;
+    /* Using IPU2's id since that is the offically supported IPU */
+    uint16_t ipu2_id = MultiProc_getId("IPU2");
+
+    /* Trigger recovery by setting the ProcMgr state */
+    switch ((uint32_t)fxnArgs) {
+        case GPTIMER_4:
+            num = 4;
+            ProcMgr_setState(gptState.proc_handles[ipu2_id],
+                ProcMgr_State_Watchdog);
+            break;
+        case GPTIMER_9:
+            num = 9;
+            ProcMgr_setState(gptState.proc_handles[ipu2_id],
+                ProcMgr_State_Watchdog);
+            break;
+        default:
+            num = 0;
+            break;
+    }
+
+    GT_1trace(curTrace, GT_4CLASS,
+              "gpt_interrupt: GPTimer %d expired!", num);
+
+    return 0;
+}
+
+/* Interrupt clear function*/
+static Bool gpt_clr_interrupt(Ptr fxnArgs)
+{
+    uintptr_t reg;
+    uint32_t num = (uint32_t)fxnArgs;
+    gpt_Regs *GPTRegs = NULL;
+
+    if (num == GPTIMER_4) {
+        GPTRegs = gptState.gpt4BaseAddr;
+    }
+    else if (num == GPTIMER_9) {
+        GPTRegs = gptState.gpt9BaseAddr;
+    }
+    else {
+        return TRUE;
+    }
+
+    reg = in32((uintptr_t)&GPTRegs->irqstatus);
+    reg |= 0x2;
+
+    /*Clear Overflow event */
+    out32((uintptr_t)&GPTRegs->irqstatus, reg);
+    reg = in32((uintptr_t)&GPTRegs->irqstatus);
+
+    /*Always return TRUE for ISR*/
+    return TRUE;
+}
+
+/* Stop watchdog timer */
+static void gpt_wdt_stop(int num)
+{
+    uintptr_t reg;
+    gpt_Regs *GPTRegs = NULL;
+
+    if (num == GPTIMER_4) {
+        GPTRegs = gptState.gpt4BaseAddr;
+    }
+    else if (num == GPTIMER_9) {
+        GPTRegs = gptState.gpt9BaseAddr;
+    }
+    else {
+        return;
+    }
+
+    reg = in32((uintptr_t)&GPTRegs->tclr);
+    reg &= GPT_TCLR_STOP_MASK;
+
+    /* Clear Overflow event */
+    out32((uintptr_t)&GPTRegs->tclr, reg);
+
+    reg = in32((uintptr_t)&GPTRegs->twps);
+    while (reg & GPT_TWPS_W_PEND_TCLR) {
+        reg = in32((uintptr_t)&GPTRegs->twps);
+    }
+
+    /* Clear status bits */
+    reg = in32((uintptr_t)&GPTRegs->irqstatus);
+    if (reg) {
+        out32((uintptr_t)&GPTRegs->irqstatus, reg);
+    }
+}
+
+/* Wire the Watchdog interrupts to trigger recovery */
+int gpt_wdt_attach(int proc_id)
+{
+    int retval = EOK;
+    OsalIsr_Params isrParams;
+
+    if (proc_id > MultiProc_MAXPROCESSORS) {
+        return -EINVAL;
+    }
+
+    /* Only do the setup once since we only have two watchdog timers */
+    if (gptState.isAttached) {
+        return EOK;
+    }
+
+    if ((proc_id == MultiProc_getId("IPU1")) ||
+        (proc_id == MultiProc_getId("IPU2"))) {
+        gptState.isAttached = true;
+        isrParams.checkAndClearFxn = gpt_clr_interrupt;
+        isrParams.fxnArgs = (Ptr)GPTIMER_9;
+        isrParams.intId = VAYU_IRQ_GPT9;
+        isrParams.sharedInt = FALSE;
+        gptState.gpt9IsrObject =
+            OsalIsr_create(&gpt_interrupt,
+                           isrParams.fxnArgs, &isrParams);
+        if(gptState.gpt9IsrObject != NULL) {
+            if (OsalIsr_install(gptState.gpt9IsrObject) < 0) {
+                retval = -ENOMEM;
+            }
+        }
+        else {
+            retval = -ENOMEM;
+        }
+
+        isrParams.checkAndClearFxn = gpt_clr_interrupt;
+        isrParams.fxnArgs = (Ptr)GPTIMER_4;
+        isrParams.intId = VAYU_IRQ_GPT4;
+        isrParams.sharedInt = FALSE;
+        gptState.gpt4IsrObject =
+            OsalIsr_create(&gpt_interrupt,
+                           isrParams.fxnArgs, &isrParams);
+        if(gptState.gpt4IsrObject != NULL) {
+            if (OsalIsr_install(gptState.gpt4IsrObject) < 0) {
+                retval = -ENOMEM;
+            }
+        }
+        else {
+            retval = -ENOMEM;
+        }
+
+
+        if (retval >= 0) {
+            if (gptState.proc_handles[MultiProc_getId("IPU2")] == NULL) {
+                /* Using IPU2's entry since it is the offically supported IPU */
+                retval = ProcMgr_open(&gptState.proc_handles[
+                    MultiProc_getId("IPU2")], proc_id);
+            }
+        }
+        else {
+            if ((proc_id == MultiProc_getId("IPU1")) ||
+                (proc_id == MultiProc_getId("IPU2"))) {
+                if (gptState.gpt9IsrObject) {
+                    OsalIsr_uninstall(gptState.gpt9IsrObject);
+                    OsalIsr_delete(&gptState.gpt9IsrObject);
+                    gptState.gpt9IsrObject = NULL;
+                }
+
+                if (gptState.gpt4IsrObject) {
+                    OsalIsr_uninstall(gptState.gpt4IsrObject);
+                    OsalIsr_delete(&gptState.gpt4IsrObject);
+                    gptState.gpt4IsrObject = NULL;
+                }
+            }
+        }
+    }
+    return retval;
+}
+
+/* Un-hook the Watchdog interrupt handler */
+int gpt_wdt_detach(int proc_id)
+{
+    int retval = EOK;
+
+    if (proc_id > MultiProc_MAXPROCESSORS) {
+        return -EINVAL;
+    }
+
+    if (gptState.isAttached) {
+        if ((proc_id == MultiProc_getId("IPU1")) ||
+            (proc_id == MultiProc_getId("IPU2"))) {
+            OsalIsr_uninstall(gptState.gpt9IsrObject);
+            OsalIsr_delete(&gptState.gpt9IsrObject);
+            gptState.gpt9IsrObject = NULL;
+
+            OsalIsr_uninstall(gptState.gpt4IsrObject);
+            OsalIsr_delete(&gptState.gpt4IsrObject);
+            gptState.gpt4IsrObject = NULL;
+
+            /* Using IPU2's entry since it is the offically supported IPU */
+            if (gptState.proc_handles[MultiProc_getId("IPU2")]) {
+                ProcMgr_close(&gptState.proc_handles[MultiProc_getId("IPU2")]);
+                gptState.proc_handles[MultiProc_getId("IPU2")] = NULL;
+            }
+
+            /*
+             * Stop the watchdog timers. We rely on the slave processors to
+             * start them, but on unload the host should stop them to avoid
+             * getting watchdog interrupts upon reload.
+             */
+            gpt_wdt_stop(GPTIMER_4);
+            gpt_wdt_stop(GPTIMER_9);
+
+            gptState.isAttached = false;
+        }
+    }
+
+    return retval;
+}