/* vxbArmv7AuxTimer.c - ARMV7 Auxeric Timer driver for VxBus */ /* * * This program is OPEN SOURCE software: you can redistribute it and/or modify it; * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ /* includes */ #include #include #include #include #include #include #include #include #include #ifdef _WRS_CONFIG_SMP #include #include #include #endif /* _WRS_CONFIG_SMP */ IMPORT int uartf(const char * fmt, ...); /* defines */ #ifdef ARMBE8 # define SWAP32 vxbSwap32 #else # define SWAP32 #endif /* ARMBE8 */ /* debug macro */ #undef AUX_TIMER_DBG_ON #ifdef AUX_TIMER_DBG_ON /* turning local symbols into global symbols */ #ifdef LOCAL #undef LOCAL #define LOCAL #endif #include /* _func_kprintf */ #define AUX_TIMER_DBG_OFF 0x00000000 #define AUX_TIMER_DBG_ISR 0x00000001 #define AUX_TIMER_DBG_ERR 0x00000002 #define AUX_TIMER_DBG_INFO 0x00000004 #define AUX_TIMER_DBG_ALL 0xffffffff LOCAL UINT32 armv7AuxTimerDbgMask = AUX_TIMER_DBG_ALL; #define AUX_TIMER_DBG(mask, ...) \ do \ { \ if ((armv7AuxTimerDbgMask & (mask)) || \ ((mask) == AUX_TIMER_DBG_ALL)) \ { \ uartf(__VA_ARGS__); \ } \ } \ while ((FALSE)) #else #define AUX_TIMER_DBG(...) #endif /* AUX_TIMER_DBG_ON */ #undef TIMERFUNC_TO_TIMERDATA #define TIMERFUNC_TO_TIMERDATA(pTimerFunc) \ (ARMV7_AUX_TIMER_DATA *)((ULONG)(pTimerFunc) - \ OFFSET (ARMV7_AUX_TIMER_DATA, timerFunc)) #define ARMV7_AUX_TIMER_NAME "armv7AuxTimer" #define ARMV7_AUX_TIMER_MAX_COUNT 0x7fffffff #define ARMV7_AUX_TIMER_DEFAULT_TPS 60 /*default*/ #define ARMV7_AUX_TIMER_DEFAULT_MIN_FREQ 10 /*default*/ /*#define ARMV7_AUX_TIMER_DEFAULT_MAX_FREQ 5000*/ #define ARMV7_AUX_TIMER_DEFAULT_MAX_FREQ 1000000 #define ARMV7_AUX_TIMER_MAX_CLK_FREQ 50000000 #define ARMV7_AUX_TIMER_MIN_CLK_FREQ 1000000 #define AUX_TIMER_REG_CTL 0 #define AUX_TIMER_REG_TVAL 1 #define AUX_TIMER_CTRL_ENABLE (1 << 0) #define AUX_TIMER_CTRL_IMASK (1 << 1) #define AUX_TIMER_CTRL_ISTATUS (1 << 2) #define AUX_TIMER_SECURE_PHY_PPI (0) #define AUX_TIMER_NON_SECURE_PHY_PPI (1) #define AUX_TIMER_VIRTURE_PPI (2) #define AUX_TIMER_HYP_PPI (3) #define AUX_TIMER_MAX_PPI (4) /* externs */ /* globals */ /* structure to store the timer information */ typedef struct armv7AuxTimerData { VXB_DEVICE_ID pInst; struct vxbTimerFunctionality timerFunc; void (*pIsrFunc)(int); int arg; spinlockIsr_t spinLock; UINT32 maxCount; UINT32 flags; BOOL isEnabled; BOOL isVirtual; BOOL secPhyAvail; BOOL nonSecPhyAvail; BOOL autoReload; } ARMV7_AUX_TIMER_DATA; ARMV7_AUX_TIMER_DATA * pArmv7AuxTimer = NULL; /* function declarations */ LOCAL STATUS armv7AuxTimerAttach (VXB_DEVICE_ID pDev); LOCAL void armv7AuxTimerInt (ARMV7_AUX_TIMER_DATA * pTimer); LOCAL STATUS armv7AuxTimerAllocate ( VXB_DEVICE_ID pInst, UINT32 flags, void ** pCookie, UINT32 timerNo ); LOCAL STATUS armv7AuxTimerRelease ( VXB_DEVICE_ID pInst, void* pCookie ); LOCAL STATUS armv7AuxTimerRolloverGet (void * pCookie, UINT32 * count); LOCAL STATUS armv7AuxTimerCountGet (void * pCookie, UINT32 * count); LOCAL STATUS armv7AuxTimerCountGet64 (void * pCookie, UINT64 * count64); LOCAL STATUS armv7AuxTimerDisable (void * pCookie); LOCAL STATUS armv7AuxTimerEnable (void * pCookie, UINT32 maxTimerCount); LOCAL STATUS armv7AuxTimerISRSet (void * pCookie, void (*pFunc)(int), int arg); IMPORT volatile UINT32 __inline__GetCntFreq (void); IMPORT volatile UINT32 __inline__GetVirtTimerValue (void); IMPORT volatile UINT32 __inline__GetVirtTimerCtrl (void); IMPORT volatile void __inline__SetVirtTimerValue (UINT32 val); IMPORT volatile void __inline__SetVirtTimerCtrl (UINT32 val); IMPORT volatile UINT32 __inline__GetPhyTimerValue (void); IMPORT volatile UINT32 __inline__GetPhyTimerCtrl (void); IMPORT volatile void __inline__SetPhyTimerValue (UINT32 val); IMPORT volatile void __inline__SetPhyTimerCtrl (UINT32 val); IMPORT volatile UINT32 __inline__GetVirtTimerCnt(void); IMPORT volatile UINT32 __inline__GetPhyTimerCnt(void); LOCAL void armv7AuxTimerInstInit ( struct vxbDev * pDev ); LOCAL void armv7AuxTimerInstInit2 ( struct vxbDev * pDev ); LOCAL void armv7AuxTimerInstConnect ( struct vxbDev * pDev ); /* locals */ LOCAL struct drvBusFuncs armv7AuxTimerFuncs = { armv7AuxTimerInstInit, /* devInstanceInit */ armv7AuxTimerInstInit2, /* devInstanceInit2 */ armv7AuxTimerInstConnect /* devConnect */ }; LOCAL STATUS armv7AuxTimerFuncGet ( VXB_DEVICE_ID pInst, struct vxbTimerFunctionality** pTimerFunc, int timerNo ); /* driver methods */ LOCAL device_method_t davinciTimerDrv_methods[] = { DEVMETHOD(vxbTimerFuncGet,armv7AuxTimerFuncGet), {0, NULL} }; LOCAL struct vxbDevRegInfo armv7AuxTimerRegistration = { NULL, /* pNext */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PLB */ VXB_VER_4_0_0, /* vxbVersion */ "armAuxTimer", /* drvName */ &armv7AuxTimerFuncs, /* pDrvBusFuncs */ NULL, NULL, /* devProbe */ NULL /* pParamDefaults */ }; void armv7AuxTimerRegister(void) { vxbDevRegister((struct vxbDevRegInfo *)&armv7AuxTimerRegistration); } LOCAL void armv7AuxTimerInstInit ( struct vxbDev * pDev ) { armv7AuxTimerAttach(pDev); return; } LOCAL void armv7AuxTimerInstInit2 ( struct vxbDev * pDev ) { return; } LOCAL void armv7AuxTimerInstConnect ( struct vxbDev * pDev ) { return; } /******************************************************************************* * * armv7AuxTimerWriteReg - write the timer register * * This routine writes value to the generic timer register. * * RETURNS: N/A * * ERRNO: N/A */ _WRS_INLINE void armv7AuxTimerWriteReg ( BOOL isVirtual, UINT32 reg, UINT32 val ) { if (isVirtual) { if (reg == AUX_TIMER_REG_CTL) { __inline__SetVirtTimerCtrl (val); } else { __inline__SetVirtTimerValue (val); } } else { if (reg == AUX_TIMER_REG_CTL) { __inline__SetPhyTimerCtrl (val); } else { __inline__SetPhyTimerValue (val); } } WRS_ASM ("ISB"); } /******************************************************************************* * * armv7AuxTimerReadReg - read the timer register * * This routine reads the generic timer register value. * * RETURNS: timer register value. * * ERRNO: N/A */ _WRS_INLINE UINT32 armv7AuxTimerReadReg ( BOOL isVirtual, UINT32 reg ) { UINT32 val = 0; if (isVirtual) { if (reg == AUX_TIMER_REG_CTL) { val = __inline__GetVirtTimerCtrl (); } else { val = __inline__GetVirtTimerValue (); } } else { if (reg == AUX_TIMER_REG_CTL) { val = __inline__GetPhyTimerCtrl (); } else { val = __inline__GetPhyTimerValue (); } } return val; } /******************************************************************************* * * armv7AuxTimerGetTimerCnt - get the generic timer count * * This routine gets the generic timer counter register value. * * RETURNS: timer counter. * * ERRNO: N/A */ _WRS_INLINE UINT64 armv7AuxTimerGetTimerCnt ( BOOL isVirtual ) { UINT64 val = 0; WRS_ASM ("ISB"); if (isVirtual) { val = __inline__GetVirtTimerCnt (); } else { val = __inline__GetPhyTimerCnt (); } return val; } /******************************************************************************* * * armv7AuxTimerAllocate - allocate resources for a timer * * This is the function called to allocate a timer for usage by the * Timer Abstraction Layer. * * RETURNS: OK or ERROR if timer allocation failed. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerAllocate ( VXB_DEVICE_ID pInst, UINT32 flags, void ** pCookie, UINT32 timerNo ) { ARMV7_AUX_TIMER_DATA * pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); VXB_ASSERT_NONNULL (pCookie, ERROR); pTimer = (ARMV7_AUX_TIMER_DATA *)(pInst->pDrvCtrl); /* check whether 'pTimerData' is valid or not */ if (pTimer != NULL) { /* if the timer is already allocated, return ERROR */ if ((pTimer->pInst != NULL) || (pTimer->timerFunc.allocated)) { uartf("%s,%d: pTimer->pInst = %p . This is error!\r\n",__FILE__,__LINE__, pTimer->pInst); return ERROR; } /* set the auto-reload flag */ if ((flags & VXB_TIMER_AUTO_RELOAD) != 0) pTimer->autoReload = TRUE; /* copy the instance pointer */ pTimer->pInst = pInst; /* set the allocated flag */ pTimer->timerFunc.allocated = TRUE; } else return ERROR; /* store the timer information in the pCookie */ *pCookie = pInst->pDrvCtrl; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); return OK; } /******************************************************************************* * * armv7AuxTimerDisableInternal - disable the timer without spinlock * * This routine stops the timer and disables interrupt generation for the * requested hardware timer without spinlock. * * RETURNS: N/A * * ERRNO: N/A * */ LOCAL void armv7AuxTimerDisableInternal ( ARMV7_AUX_TIMER_DATA * pTimer ) { VXB_DEVICE_ID pInst; if (!pTimer->isEnabled) return; /* disable the timer */ armv7AuxTimerWriteReg (pTimer->isVirtual, AUX_TIMER_REG_CTL, AUX_TIMER_CTRL_IMASK); /* disable the timer interrupt */ pInst = pTimer->pInst; vxbIntDisable (pInst, 0, armv7AuxTimerInt, pTimer); pTimer->maxCount = ARMV7_AUX_TIMER_MAX_COUNT; pTimer->isEnabled = FALSE; } /******************************************************************************* * * armv7AuxTimerRelease - release the timer resource * * This is the function called to release a timer device. * * RETURNS: OK or ERROR if parameter is not valid. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerRelease ( VXB_DEVICE_ID pInst, void* pCookie ) { ARMV7_AUX_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; if ((pTimer == NULL) || (pTimer->pInst != pInst) || (!pTimer->timerFunc.allocated)) { uartf("%s,%d: pTimer is bad!\r\n",__FILE__,__LINE__); return ERROR; } pTimerFunc = &(pTimer->timerFunc); SPIN_LOCK_ISR_TAKE (&pTimer->spinLock); /* check that timer is allocated */ if (!pTimerFunc->allocated) { SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); return ERROR; } /* disable the timer */ (void)armv7AuxTimerDisableInternal (pTimer); /* reset the autoReload flag */ if (pTimer->autoReload) { pTimer->autoReload = FALSE; } pTimer->pIsrFunc = NULL; pTimer->arg = 0; pTimer->flags = 0; /* reset the timer allocated flag */ pTimerFunc->allocated = FALSE; pTimer->pInst = NULL; SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); return OK; } /******************************************************************************* * * armv7AuxTimerRolloverGet - retrieve the maximum value of the counter * * This is the function called to retrieve the maximum value of the counter. * The maximum value is returned in 'pCount' parameter. * * RETURNS: OK or ERROR if the parameter is invalid. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerRolloverGet ( void * pCookie, UINT32 * pCount ) { ARMV7_AUX_TIMER_DATA * pTimer; VXB_ASSERT_NONNULL (pCount, ERROR); /* free run counter, always get the MAX count for timestamp */ pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; if (pTimer == NULL) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR,"%s,%d: pTimer is bad!\r\n",__FILE__,__LINE__); return ERROR; } *pCount = pTimer->maxCount; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerRolloverGet: %u. for vx68\r\n", pTimer->maxCount); AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerRolloverGet: %u\r\n", ARMV7_AUX_TIMER_MAX_COUNT); return OK; } /******************************************************************************* * * armv7AuxTimerCountGet - retrieve the current value of the counter * * This function is used to retrieve the current value of the counter. * The current value is returned in 'pCount' parameter. * * RETURNS: OK or ERROR if the parameter is invalid. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerCountGet ( void * pCookie, UINT32 * pCount ) { UINT64 cnt64; UINT32 cnt32; ARMV7_AUX_TIMER_DATA * pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerCountGet\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); VXB_ASSERT_NONNULL (pCount, ERROR); pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; /* the timer counter is from the lower 32 bits of the 64 bits register */ cnt64 = armv7AuxTimerGetTimerCnt (pTimer->isVirtual); cnt32 = (UINT32)(cnt64 % ((UINT32)ARMV7_AUX_TIMER_MAX_COUNT + 1)); *pCount = cnt32; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerCountGet: cnt32=%u\r\n", cnt32); return OK; } /******************************************************************************* * * armv7AuxTimerCountGet64 - retrieve the current 64bit value of the counter * * This function is used to retrieve the current 64bit value of the counter. * The current value is returned in 'pCount' parameter. * * RETURNS: OK or ERROR if the parameter is invalid. * * ERRNO: N/A */ /* Note-20201112: verified bits[63-31] are sign bits: -> testtmcount v_val=0xffffffff_f859af64; p_val=0xffffffff_f859af66 -> testtmcount v_val=0xffffffff_fd1b6b3d; p_val=0xffffffff_fd1b6b3f -> testtmcount v_val=0x0_02d50ffb; p_val=0x0_02d50ffe 64bit is NOT supported! This func is only a placeholder. */ LOCAL STATUS armv7AuxTimerCountGet64 ( void * pCookie, UINT64 * pCount64 ) { UINT64 cnt64; ARMV7_AUX_TIMER_DATA * pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerCountGet64\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); VXB_ASSERT_NONNULL (pCount64, ERROR); pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; /* the timer counter is from the lower 32 bits of the 64 bits register */ cnt64 = armv7AuxTimerGetTimerCnt (pTimer->isVirtual); *pCount64 = cnt64; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerCountGet64:cnt64=%x_%08x\r\n", (UINT32)(cnt64>>32), (UINT32)(cnt64&0xFFFFFFFF)); return OK; } /******************************************************************************* * * armv7AuxTimerISRSet - set a function to be called on the timer interrupt * * This function is called to set a function which can be called whenever * the timer interrupt occurs. * * RETURNS: OK or ERROR if the parameter is invalid. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerISRSet ( void * pCookie, void (*pFunc)(int), int arg ) { ARMV7_AUX_TIMER_DATA * pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerISRSet\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; /* take the spinlock to update pIsrFunc and arg atomically */ SPIN_LOCK_ISR_TAKE (&pTimer->spinLock); /* store the interrupt routine and argument information */ pTimer->pIsrFunc = pFunc; pTimer->arg = arg; /* release the spinlock */ SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); return OK; } #ifdef _WRS_CONFIG_SMP /******************************************************************************* * * armGenTimerExecOnCpu - execute a function on the specified CPU * * This routine is called to execute a function on the specified CPU. * * RETURNS: N/A * * ERRNO */ LOCAL void armGenTimerExecOnCpu ( ULONG * pParams, size_t paramSize ) { void * func = (void *)pParams[0]; void * pCookie = (void *)pParams[1]; UINT32 maxTimerCount; /* Execute the specified function with parameters */ if ((STATUS (*)(void *))func == armv7AuxTimerDisable) { (void)armv7AuxTimerDisable (pCookie); } else if ((STATUS (*)(void *, UINT32))func == armv7AuxTimerEnable) { maxTimerCount = (UINT32)pParams[2]; (void)armv7AuxTimerEnable (pCookie, maxTimerCount); } } #endif /* _WRS_CONFIG_SMP */ /******************************************************************************* * * armv7AuxTimerDisable - disable the timer interrupt * * This function is called to disable the timer interrupt. * * RETURNS: OK or ERROR if timer is not disabled * * ERRNO */ LOCAL STATUS armv7AuxTimerDisable ( void * pCookie ) { #ifdef _WRS_CONFIG_SMP cpuset_t cpuSet; ULONG cpcParam[2]; #endif /* _WRS_CONFIG_SMP */ ARMV7_AUX_TIMER_DATA * pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerDisable\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); /* retrieve the pTimer */ pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; if (pTimer == NULL) return ERROR; #ifdef _WRS_CONFIG_SMP /* if not being executed on the boot processor ... */ if (vxCpuIndexGet () != 0) { /* send CPC to boot processor only - CPU 0 */ CPUSET_ZERO (cpuSet); CPUSET_SET (cpuSet, 0); cpcParam[0] = (ULONG) armv7AuxTimerDisable; cpcParam[1] = (ULONG) pCookie; /* if not in interrupt context, taskCpuLock */ (void) taskCpuLock (); /* execute on boot processor */ cpcInvoke (cpuSet, (CPC_FUNC) armGenTimerExecOnCpu, cpcParam, sizeof (cpcParam), VX_CPC_SYNC); /* if not in interrupt context, taskCpuUnlock */ (void) taskCpuUnlock (); return OK; } #endif /* _WRS_CONFIG_SMP */ SPIN_LOCK_ISR_TAKE (&pTimer->spinLock); armv7AuxTimerDisableInternal (pTimer); /* close interrupt */ SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); return OK; } /******************************************************************************* * * armv7AuxTimerEnable - enable the timer interrupt * * This function enables the timer interrupt. * * RETURNS: OK or ERROR if timer is not enabled * * ERRNO */ LOCAL STATUS armv7AuxTimerEnable ( void * pCookie, UINT32 maxTimerCount ) { #ifdef _WRS_CONFIG_SMP cpuset_t cpuSet; ULONG cpcParam[3]; #endif /* _WRS_CONFIG_SMP */ ARMV7_AUX_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; VXB_DEVICE_ID pInst; VXB_ASSERT_NONNULL (pCookie, ERROR); AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerEnable: New TimerCount: %u (0x%x)\r\n", maxTimerCount,maxTimerCount); if ((maxTimerCount > ARMV7_AUX_TIMER_MAX_COUNT) || (maxTimerCount == 0)) { AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerEnable: This TimerCount is invalid!\r\n"); return ERROR; } /* retrieve the pTimer */ pTimer = (ARMV7_AUX_TIMER_DATA *)pCookie; pTimerFunc = &(pTimer->timerFunc); pInst = pTimer->pInst; #ifdef _WRS_CONFIG_SMP /* if not being executed on the boot processor */ if (vxCpuIndexGet() != 0) { /* send CPC to boot processor only - CPU 0 */ CPUSET_ZERO (cpuSet); CPUSET_SET (cpuSet, 0); cpcParam[0] = (ULONG) armv7AuxTimerEnable; cpcParam[1] = (ULONG) pCookie; cpcParam[2] = (ULONG) maxTimerCount; /* if not in interrupt context, taskCpuLock */ (void) taskCpuLock (); /* execute on boot processor */ cpcInvoke (cpuSet, (CPC_FUNC) armGenTimerExecOnCpu, cpcParam, sizeof(cpcParam), VX_CPC_SYNC); /* if not in interrupt context, taskCpuUnlock */ (void) taskCpuUnlock (); return OK; } #endif /* _WRS_CONFIG_SMP */ SPIN_LOCK_ISR_TAKE (&pTimer->spinLock); /* if the timer is already running, stop it before making adjustments */ if (pTimer->isEnabled) { (void)armv7AuxTimerDisableInternal (pTimer); } pTimer->maxCount = maxTimerCount; /* recalculate ticksPerSecond */ pTimerFunc->ticksPerSecond = pTimerFunc->clkFrequency / pTimer->maxCount; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerEnable New ticksPerSecond = %d.(should be 60) pTimer->isVirtual %d\r\n", pTimerFunc->ticksPerSecond ,pTimer->isVirtual); /* update the timer value register with maxTimerCount */ armv7AuxTimerWriteReg (pTimer->isVirtual, AUX_TIMER_REG_TVAL, maxTimerCount); /* set up the timer control register */ armv7AuxTimerWriteReg (pTimer->isVirtual, AUX_TIMER_REG_CTL, AUX_TIMER_CTRL_ENABLE); pTimer->isEnabled = TRUE; SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); if (pTimer->isVirtual) { if (vxbIntEnable (pInst, 0,armv7AuxTimerInt, pTimer) != OK) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR, "Interrupt enable failed for virtual timer\n"); /*SPIN_LOCK_ISR_GIVE (&pTimer->spinLock);*/ return ERROR; } } else { if (pTimer->secPhyAvail && (vxbIntEnable (pInst, 0,armv7AuxTimerInt, pTimer) != OK)) { pTimer->secPhyAvail = FALSE; } if (pTimer->nonSecPhyAvail && (vxbIntEnable (pInst, 0,armv7AuxTimerInt, pTimer) != OK)) { pTimer->nonSecPhyAvail = FALSE; } if (!pTimer->secPhyAvail && !pTimer->nonSecPhyAvail) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR, "Interrupt enable failed for physical timer\n"); /*SPIN_LOCK_ISR_GIVE (&pTimer->spinLock);*/ return ERROR; } } AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerEnable OK\r\n"); return OK; } /******************************************************************************* * * armv7AuxTimerInt - ISR for the ARM Auxeric Timer * * This routine handles the ARM Auxeric Timer interrupt. * * RETURNS : N/A */ LOCAL void armv7AuxTimerInt ( ARMV7_AUX_TIMER_DATA * pTimer ) { UINT32 ctl; ctl = armv7AuxTimerReadReg (pTimer->isVirtual, AUX_TIMER_REG_CTL); if ((ctl & AUX_TIMER_CTRL_ISTATUS) == 0) { uartf("\033[34m%s,%d: ctl=0x%x. pTimer->maxCount=0x%x. No TimerInt. Return directly!\033[m\r\n",__FILE__,__LINE__,ctl, pTimer->maxCount); return; } /* auto reload */ if ((pTimer->timerFunc.features & VXB_TIMER_AUTO_RELOAD) != 0) { armv7AuxTimerWriteReg (pTimer->isVirtual, AUX_TIMER_REG_TVAL, pTimer->maxCount); } else { armv7AuxTimerWriteReg (pTimer->isVirtual, AUX_TIMER_REG_CTL, AUX_TIMER_CTRL_IMASK); } /* call the ISR hooked by armv7AuxTimerISRSet() */ if (pTimer->pIsrFunc != NULL) pTimer->pIsrFunc (pTimer->arg); } /****************************************************************************** * * armv7AuxTimerAttach - attach arm generic timer device * * This is the arm generic timer initialization routine. * * RETURNS: OK, or ERROR if initialization failed. * * ERRNO: N/A */ LOCAL STATUS armv7AuxTimerAttach ( VXB_DEVICE_ID pDev ) { ARMV7_AUX_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; HCF_DEVICE * pHcf = NULL; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "Enter armv7AuxTimerAttach\r\n"); /* check for valid parameter */ VXB_ASSERT_NONNULL (pDev, ERROR); /* get the HCF_DEVICE address */ pHcf = hcfDeviceGet(pDev); if (pHcf == NULL) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR, "There is no HCF for this device.\r\n"); return ERROR; } /* allocate the memory for the timer structure */ pTimer = (ARMV7_AUX_TIMER_DATA *)hwMemAlloc (sizeof(ARMV7_AUX_TIMER_DATA)); if (pTimer == NULL) { return ERROR; } pArmv7AuxTimer = pTimer; /* * Use virtual timer by default, but if it's not available, * use physical timer. */ pTimer->secPhyAvail = FALSE; pTimer->isVirtual = TRUE; pTimer->nonSecPhyAvail = FALSE; if (vxbIntConnect (pDev, 0, /*pTimer->intRes[AUX_TIMER_SECURE_PHY_PPI],*/ armv7AuxTimerInt, pTimer) != OK) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR, "Secure physical timer is not available\r\n"); pTimer->isVirtual = FALSE; } /* locate the timer functionality data structure */ pTimerFunc = &(pTimer->timerFunc); if (devResourceGet(pHcf,"minClkRate",HCF_RES_INT, (void *)&pTimerFunc->minFrequency) != OK) { /*default value. */ pTimerFunc->minFrequency = ARMV7_AUX_TIMER_DEFAULT_MIN_FREQ; } if (devResourceGet(pHcf,"maxClkRate",HCF_RES_INT, (void *)&pTimerFunc->maxFrequency) != OK) { /*default value*/ pTimerFunc->maxFrequency = ARMV7_AUX_TIMER_DEFAULT_MAX_FREQ; } pTimerFunc->clkFrequency = __inline__GetCntFreq(); AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "Clock Frequency: %d\r\n", pTimerFunc->clkFrequency); if ((pTimerFunc->clkFrequency < ARMV7_AUX_TIMER_MIN_CLK_FREQ) || (pTimerFunc->clkFrequency > ARMV7_AUX_TIMER_MAX_CLK_FREQ)) { AUX_TIMER_DBG (AUX_TIMER_DBG_ERR, "clkFrequency wrong for ARM generic timer\r\n"); goto errOut; } /* store the feature provided by the timer */ pTimerFunc->features = VXB_TIMER_CAN_INTERRUPT | VXB_TIMER_INTERMEDIATE_COUNT | VXB_TIMER_SIZE_32 | VXB_TIMER_SIZE_64 | VXB_TIMER_AUTO_RELOAD ; /* set the default ticks per second */ pTimerFunc->ticksPerSecond = ARMV7_AUX_TIMER_DEFAULT_TPS; /* * Requires to initialize maxCount field for timestamp timer. * It will be used as a return value for sysTimestampPeriod(). */ pTimer->maxCount = pTimerFunc->clkFrequency/ARMV7_AUX_TIMER_DEFAULT_TPS; pTimerFunc->rolloverPeriod = pTimer->maxCount / pTimerFunc->clkFrequency; (void)strncpy (pTimerFunc->timerName, ARMV7_AUX_TIMER_NAME, MAX_DRV_NAME_LEN); /* populate the function pointers */ pTimerFunc->timerAllocate = armv7AuxTimerAllocate; pTimerFunc->timerRelease = armv7AuxTimerRelease; pTimerFunc->timerRolloverGet = armv7AuxTimerRolloverGet; pTimerFunc->timerCountGet = armv7AuxTimerCountGet; pTimerFunc->timerCountGet64 = armv7AuxTimerCountGet64; pTimerFunc->timerDisable = armv7AuxTimerDisable; pTimerFunc->timerEnable = armv7AuxTimerEnable; pTimerFunc->timerISRSet = armv7AuxTimerISRSet; /* initialize the spinlock */ SPIN_LOCK_ISR_INIT (&pTimer->spinLock, 0); /* publish methods */ pDev->pMethods = davinciTimerDrv_methods; pDev->pDrvCtrl = pTimer; AUX_TIMER_DBG (AUX_TIMER_DBG_INFO, "armv7AuxTimerAttach OK\r\n"); return OK; errOut: hwMemFree ((char * )pTimer); return ERROR; } /******************************************************************************* * * armv7AuxTimerFuncGet - method to retrieve the timer functionality * * This function is the driver method used to retrieve the timer functionality. * * RETURNS: OK or ERROR if functionality is not retrieved. * * ERRNO */ LOCAL STATUS armv7AuxTimerFuncGet ( VXB_DEVICE_ID pInst, struct vxbTimerFunctionality** pTimerFunc, int timerNo ) { ARMV7_AUX_TIMER_DATA * pTimerData; /* since the device supports only a single timer functionality */ if ( timerNo != 0) return ERROR; /* check the validity of parameters */ if ( (pInst == NULL) || (pInst->pDrvCtrl == NULL) || (pTimerFunc == NULL) ) { return ERROR; } /* retrieve the timer specific data */ pTimerData = (ARMV7_AUX_TIMER_DATA *)(pInst->pDrvCtrl); /* update the timer functionality pointer */ *pTimerFunc = &(pTimerData->timerFunc); return OK; } /* delay 1us */ void armV7AuxUsDelay ( int delay /* length of time in US to delay */ ) { ARMV7_AUX_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; volatile register UINT32 oldVal; volatile register UINT32 newVal; volatile register UINT32 decElapsed = 0; register UINT32 totalDelta; UINT32 maxTickCount; /*UINT32 minTickCount = 0;*/ UINT32 ticksPerUs = 0; int loopcount = 0; UINT64 cnt64; if(delay == 0) { return; } pTimer = pArmv7AuxTimer; if(pTimer == NULL) { uartf("No valid armv7 gen timer!\r\n"); return; } pTimerFunc = &(pTimer->timerFunc); ticksPerUs = pTimerFunc->clkFrequency / 1000000; if(ticksPerUs != 50) { uartf("ticksPerUs-%d should be 50 for this board, please check it!\r\n", ticksPerUs); } maxTickCount = pTimer->maxCount; totalDelta = delay * (ticksPerUs); /* total clock ticks for long delay */ cnt64 = armv7AuxTimerGetTimerCnt (pTimer->isVirtual); oldVal = (UINT32)(cnt64 % ((UINT32)ARMV7_AUX_TIMER_MAX_COUNT + 1)); while (decElapsed < totalDelta) { loopcount++; cnt64 = armv7AuxTimerGetTimerCnt (pTimer->isVirtual); newVal = (UINT32)(cnt64 % ((UINT32)ARMV7_AUX_TIMER_MAX_COUNT + 1)); if(newVal == oldVal) { continue; } /* no rollover. count down... */ if (newVal < oldVal) { decElapsed += (oldVal - newVal); } /* rollover */ else { decElapsed += ((maxTickCount - newVal) + oldVal); } oldVal = newVal; } }