Add support for watchdog timer interrupts on DRA7xx IPU
authorvwan@ti.com <vwan@ti.com>
Wed, 28 May 2014 20:21:48 +0000 (13:21 -0700)
committerRobert Tivy <rtivy@ti.com>
Wed, 28 May 2014 20:43:45 +0000 (13:43 -0700)
This commit adds QNX support for watchdog timer interrupts. The resource
manager schedules recovery whenever an interrupt from GPTimer 4 or 9
is received.

Only one of IPU1 or IPU2 can use watchdog timers.

Signed-off-by: VW <vwan@ti.com>
qnx/src/ipc3x_dev/ti/syslink/family/vayu/gptimers.c
qnx/src/ipc3x_dev/ti/syslink/family/vayu/gptimers.h
qnx/src/ipc3x_dev/ti/syslink/ipc/hlos/knl/Ipc.c

index 1df5a00840c3d0bce3933a222e83a88f98e2d0e6..1789984df82df6ee3ae64825800c49b0bab5da0f 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>
 
 
 #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.
@@ -86,6 +137,16 @@ struct gpt_module_object {
     /* base address to CM_CORE_AON__IPU */
     bool isSetup;
     /* Indicates whether the ipu_pm module is setup. */
+    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 +242,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 +254,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 +282,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 +303,162 @@ 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,
+              "ipu_pm_gptimer_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;
+}
+
+
+/* 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;
+    }
+
+    if ((proc_id == MultiProc_getId("IPU1")) ||
+        (proc_id == MultiProc_getId("IPU2"))) {
+        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) &&
+        (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 ((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;
+    }
+
+    return retval;
+}
index 5d9fa1656ee71c1e1f82579caa6828dfbd83b476..1370a42bce7f990aafa4b23011e355a348a49d17 100644 (file)
@@ -44,6 +44,12 @@ int gpt_setup();
 /* Disable GP timers */
 int gpt_destroy();
 
+/* Wire the Watchdog interrupts to trigger recovery */
+int gpt_wdt_attach(int proc_id);
+
+/* Un-hook the Watchdog interrupt handler */
+int gpt_wdt_detach(int proc_id);
+
 #if defined (__cplusplus)
 }
 #endif /* defined (__cplusplus) */
index 3723e27eee5eb081022c8036c047afc8d7a61772..8a954098f88f9d7a6ef0da6738c120e60f648607 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2008-2013, Texas Instruments Incorporated
+ *  Copyright (c) 2008-2014, Texas Instruments Incorporated
  *
  *  Redistribution and use in source and binary forms, with or without
  *  modification, are permitted provided that the following conditions
 #include <_MessageQCopy.h>
 #include <ti/ipc/MessageQCopy.h>
 
+#if defined(SYSLINK_PLATFORM_VAYU)
+#include <gptimers.h>
+#endif
+
 /*  ----------------------------------- SysLink utils Headers   */
 #include <ti/syslink/inc/_MultiProc.h>
 #include <ti/ipc/MultiProc.h>
@@ -200,7 +204,7 @@ Int Ipc_attach (UInt16 remoteProcId)
             ProcMgr_close(&procHandle);
         }
 
-#if defined(SYSLINK_USE_IPU_PM)
+#if defined(SYSLINK_USE_IPU_PM) && defined(SYSLINK_PLATFORM_OMAP5)
         if (status >= 0) {
             status = ipu_pm_attach(remoteProcId);
             if (status < 0) {
@@ -209,6 +213,15 @@ Int Ipc_attach (UInt16 remoteProcId)
         }
 #endif
 
+#if defined(SYSLINK_PLATFORM_VAYU)
+        if (status >= 0) {
+            status = gpt_wdt_attach(remoteProcId);
+            if (status < 0) {
+                MessageQCopy_detach(remoteProcId);
+            }
+        }
+#endif
+
         if (status >= 0) {
             key = Gate_enterSystem ();
             Ipc_module->procEntry[remoteProcId].isAttached++;
@@ -243,10 +256,14 @@ Int Ipc_detach (UInt16 remoteProcId)
     else {
         Gate_leaveSystem (key);
 
-#if defined(SYSLINK_USE_IPU_PM)
+#if defined(SYSLINK_USE_IPU_PM) && defined(SYSLINK_PLATFORM_OMAP5)
         status = ipu_pm_detach (remoteProcId);
 #endif
 
+#if defined(SYSLINK_PLATFORM_VAYU)
+        status = gpt_wdt_detach(remoteProcId);
+#endif
+
         status = MessageQCopy_detach (remoteProcId);
 
         key = Gate_enterSystem ();