/* vxbArmv7GenTimer.c - ARMV7 Generic 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 GEN_TIMER_DBG_ON #ifdef GEN_TIMER_DBG_ON /* turning local symbols into global symbols */ #ifdef LOCAL #undef LOCAL #define LOCAL #endif #include /* _func_kprintf */ #define GEN_TIMER_DBG_OFF 0x00000000 #define GEN_TIMER_DBG_ISR 0x00000001 #define GEN_TIMER_DBG_ERR 0x00000002 #define GEN_TIMER_DBG_INFO 0x00000004 #define GEN_TIMER_DBG_ALL 0xffffffff LOCAL UINT32 armv7GenTimerDbgMask = GEN_TIMER_DBG_ALL; #define GEN_TIMER_DBG(mask, ...) \ do \ { \ if ((armv7GenTimerDbgMask & (mask)) || \ ((mask) == GEN_TIMER_DBG_ALL)) \ { \ uartf(__VA_ARGS__); \ } \ } \ while ((FALSE)) #else #define GEN_TIMER_DBG(...) #endif /* GEN_TIMER_DBG_ON */ #undef TIMERFUNC_TO_TIMERDATA #define TIMERFUNC_TO_TIMERDATA(pTimerFunc) \ (ARMV7_GEN_TIMER_DATA *)((ULONG)(pTimerFunc) - \ OFFSET (ARMV7_GEN_TIMER_DATA, timerFunc)) #define ARMV7_GEN_TIMER_NAME "armv7GenTimer" #define ARMV7_GEN_TIMER_MAX_COUNT 0x7fffffff #define ARMV7_GEN_TIMER_DEFAULT_TPS 60 /*default*/ #define ARMV7_GEN_TIMER_DEFAULT_MIN_FREQ 10 /*default*/ #define ARMV7_GEN_TIMER_DEFAULT_MAX_FREQ 5000 /*default*/ #define ARMV7_GEN_TIMER_MAX_CLK_FREQ 50000000 #define ARMV7_GEN_TIMER_MIN_CLK_FREQ 1000000 #define GEN_TIMER_REG_CTL 0 #define GEN_TIMER_REG_TVAL 1 #define GEN_TIMER_CTRL_ENABLE (1 << 0) #define GEN_TIMER_CTRL_IMASK (1 << 1) #define GEN_TIMER_CTRL_ISTATUS (1 << 2) #define GEN_TIMER_SECURE_PHY_PPI (0) #define GEN_TIMER_NON_SECURE_PHY_PPI (1) #define GEN_TIMER_VIRTURE_PPI (2) #define GEN_TIMER_HYP_PPI (3) #define GEN_TIMER_MAX_PPI (4) /* externs */ /* globals */ /* structure to store the timer information */ typedef struct armv7GenTimerData { 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_GEN_TIMER_DATA; ARMV7_GEN_TIMER_DATA * pArmv7GenTimer = NULL; /* function declarations */ LOCAL STATUS armv7GenTimerAttach (VXB_DEVICE_ID pDev); LOCAL void armv7GenTimerInt (ARMV7_GEN_TIMER_DATA * pTimer); LOCAL STATUS armv7GenTimerAllocate ( VXB_DEVICE_ID pInst, UINT32 flags, void ** pCookie, UINT32 timerNo ); LOCAL STATUS armv7GenTimerRelease ( VXB_DEVICE_ID pInst, void* pCookie ); LOCAL STATUS armv7GenTimerRolloverGet (void * pCookie, UINT32 * count); LOCAL STATUS armv7GenTimerCountGet (void * pCookie, UINT32 * count); LOCAL STATUS armv7GenTimerCountGet64 (void * pCookie, UINT64 * count64); LOCAL STATUS armv7GenTimerDisable (void * pCookie); LOCAL STATUS armv7GenTimerEnable (void * pCookie, UINT32 maxTimerCount); LOCAL STATUS armv7GenTimerISRSet (void * pCookie, void (*pFunc)(int), int arg); IMPORT volatile UINT32 __inline__GetVirtTimerCnt(void); IMPORT volatile UINT32 __inline__GetPhyTimerCnt(void); LOCAL void armv7GenTimerInstInit ( struct vxbDev * pDev ); LOCAL void armv7GenTimerInstInit2 ( struct vxbDev * pDev ); LOCAL void armv7GenTimerInstConnect ( struct vxbDev * pDev ); /* locals */ LOCAL struct drvBusFuncs armv7GenTimerFuncs = { armv7GenTimerInstInit, /* devInstanceInit */ armv7GenTimerInstInit2, /* devInstanceInit2 */ armv7GenTimerInstConnect /* devConnect */ }; LOCAL STATUS armv7GenTimerFuncGet ( VXB_DEVICE_ID pInst, struct vxbTimerFunctionality** pTimerFunc, int timerNo ); /* driver methods */ LOCAL device_method_t davinciTimerDrv_methods[] = { DEVMETHOD(vxbTimerFuncGet,armv7GenTimerFuncGet), {0, NULL} }; LOCAL struct vxbDevRegInfo armv7GenTimerRegistration = { NULL, /* pNext */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PLB */ VXB_VER_4_0_0, /* vxbVersion */ "armGenTimer", /* drvName */ &armv7GenTimerFuncs, /* pDrvBusFuncs */ NULL, NULL, /* devProbe */ NULL /* pParamDefaults */ }; void armv7GenTimerRegister(void) { vxbDevRegister((struct vxbDevRegInfo *)&armv7GenTimerRegistration); } LOCAL void armv7GenTimerInstInit ( struct vxbDev * pDev ) { armv7GenTimerAttach(pDev); return; } LOCAL void armv7GenTimerInstInit2 ( struct vxbDev * pDev ) { return; } LOCAL void armv7GenTimerInstConnect ( struct vxbDev * pDev ) { return; } /* * The inline assembly to access generic timer on c14 follows diab's inline * assembly syntax, so diab compiler must be used. */ #ifndef __DCC__ UINT32 __inline__GetCntFreq (void) { UINT32 rtn; __asm__ volatile ( "mrc p15, 0, %0, c14, c0, 0 \n" : "=r" (rtn) ); return (rtn); } UINT32 __inline__GetVirtTimerValue (void) { UINT32 rtn; __asm__ volatile ( "mrc p15, 0, %0, c14, c3, 0 \n" : "=r" (rtn) ); return (rtn); } UINT32 __inline__GetVirtTimerCtrl (void) { UINT32 rtn; __asm__ volatile ( "mrc p15, 0, %0, c14, c3, 1\n" : "=r" (rtn) ); return (rtn); } void __inline__SetVirtTimerValue (UINT32 val) { __asm__ volatile ( "mcr p15, 0, %0, c14, c3, 0 \n" : : "r" (val) : "memory" ); } void __inline__SetVirtTimerCtrl (UINT32 val) { __asm__ volatile ( "mcr p15, 0, %0, c14, c3, 1 \n" : : "r" (val) : "memory" ); } /* unsigned int sys_gtimer_timervalue_get(void) */ UINT32 __inline__GetPhyTimerValue (void) { UINT32 rtn; __asm__ volatile ( "mrc p15, 0, %0, c14, c2, 0 \n" : "=r" (rtn) ); return (rtn); } /* sys_gtimer_timervalue_set(unsigned int value) */ void __inline__SetPhyTimerValue (UINT32 val) { __asm__ volatile ( "mcr p15, 0, %0, c14, c2, 0 \n" : : "r" (val) : "memory" ); } /* sys_gtimer_pl1phyctrl_set */ void __inline__SetPhyTimerCtrl (UINT32 val) { __asm__ volatile ( "mcr p15, 0, %0, c14, c2, 1 \n" : : "r" (val) : "memory" ); } /* sys_gtimer_pl1phyctrl_get */ UINT32 __inline__GetPhyTimerCtrl (void) { UINT32 rtn; __asm__ volatile ( "mrc p15, 0, %0, c14, c2, 1 \n" : "=r" (rtn) ); return (rtn); } #else /* __DCC__ for diab */ __asm volatile UINT32 __macro__GetCntFreq (void) { ! "r0" mrc p15, 0, r0, c14, c0, 0 } volatile UINT32 __inline__GetCntFreq (void) { return __macro__GetCntFreq(); } __asm volatile UINT32 __macro__GetVirtTimerValue (void) { ! "r0" mrc p15, 0, r0, c14, c3, 0 } volatile UINT32 __inline__GetVirtTimerValue (void) { return __macro__GetVirtTimerValue (); } __asm volatile UINT32 __macro__GetVirtTimerCtrl (void) { ! "r0" mrc p15, 0, r0, c14, c3, 1 } volatile UINT32 __inline__GetVirtTimerCtrl (void) { return __macro__GetVirtTimerCtrl(); } __asm volatile void __macro__SetVirtTimerValue (UINT32 val) { % reg val ! "r0" mcr p15, 0, val, c14, c3, 0 } volatile void __inline__SetVirtTimerValue (UINT32 val) { __macro__SetVirtTimerValue(val); } __asm volatile void __macro__SetVirtTimerCtrl (UINT32 val) { % reg val ! "r0" mcr p15, 0, val, c14, c3, 1 } volatile void __inline__SetVirtTimerCtrl (UINT32 val) { __macro__SetVirtTimerCtrl (val); } __asm volatile UINT32 __macro__GetPhyTimerValue (void) { ! "r0" mrc p15, 0, r0, c14, c2, 0 } volatile UINT32 __inline__GetPhyTimerValue (void) { return __macro__GetPhyTimerValue(); } __asm volatile UINT32 __macro__GetPhyTimerCtrl (void) { ! "r0" mrc p15, 0, r0, c14, c2, 1 } volatile UINT32 __inline__GetPhyTimerCtrl (void) { return __macro__GetPhyTimerCtrl(); } __asm volatile void __macro__SetPhyTimerValue (UINT32 val) { % reg val ! "r0" mcr p15, 0, val, c14, c2, 0 } volatile void __inline__SetPhyTimerValue (UINT32 val) { __macro__SetPhyTimerValue (val); } __asm volatile void __macro__SetPhyTimerCtrl (UINT32 val) { % reg val ! "r0" mcr p15, 0, val, c14, c2, 1 } volatile void __inline__SetPhyTimerCtrl (UINT32 val) { __macro__SetPhyTimerCtrl (val); } #endif /******************************************************************************* * * armv7GenTimerWriteReg - write the timer register * * This routine writes value to the generic timer register. * * RETURNS: N/A * * ERRNO: N/A */ _WRS_INLINE void armv7GenTimerWriteReg ( BOOL isVirtual, UINT32 reg, UINT32 val ) { if (isVirtual) { if (reg == GEN_TIMER_REG_CTL) { __inline__SetVirtTimerCtrl (val); } else { __inline__SetVirtTimerValue (val); } } else { if (reg == GEN_TIMER_REG_CTL) { __inline__SetPhyTimerCtrl (val); } else { __inline__SetPhyTimerValue (val); } } WRS_ASM ("ISB"); } /******************************************************************************* * * armv7GenTimerReadReg - read the timer register * * This routine reads the generic timer register value. * * RETURNS: timer register value. * * ERRNO: N/A */ _WRS_INLINE UINT32 armv7GenTimerReadReg ( BOOL isVirtual, UINT32 reg ) { UINT32 val = 0; if (isVirtual) { if (reg == GEN_TIMER_REG_CTL) { val = __inline__GetVirtTimerCtrl (); } else { val = __inline__GetVirtTimerValue (); } } else { if (reg == GEN_TIMER_REG_CTL) { val = __inline__GetPhyTimerCtrl (); } else { val = __inline__GetPhyTimerValue (); } } return val; } /******************************************************************************* * * armv7GenTimerGetTimerCnt - get the generic timer count * * This routine gets the generic timer counter register value. * * RETURNS: timer counter. * * ERRNO: N/A */ _WRS_INLINE UINT64 armv7GenTimerGetTimerCnt ( BOOL isVirtual ) { UINT64 val = 0; WRS_ASM ("ISB"); if (isVirtual) { val = __inline__GetVirtTimerCnt (); } else { val = __inline__GetPhyTimerCnt (); } return val; } /******************************************************************************* * * armv7GenTimerAllocate - 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 armv7GenTimerAllocate ( VXB_DEVICE_ID pInst, UINT32 flags, void ** pCookie, UINT32 timerNo ) { ARMV7_GEN_TIMER_DATA * pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); VXB_ASSERT_NONNULL (pCookie, ERROR); pTimer = (ARMV7_GEN_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; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); return OK; } /******************************************************************************* * * armv7GenTimerDisableInternal - 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 armv7GenTimerDisableInternal ( ARMV7_GEN_TIMER_DATA * pTimer ) { VXB_DEVICE_ID pInst; if (!pTimer->isEnabled) return; /* disable the timer */ armv7GenTimerWriteReg (pTimer->isVirtual, GEN_TIMER_REG_CTL, GEN_TIMER_CTRL_IMASK); /* disable the timer interrupt */ pInst = pTimer->pInst; vxbIntDisable (pInst, 0, armv7GenTimerInt, pTimer); pTimer->maxCount = ARMV7_GEN_TIMER_MAX_COUNT; pTimer->isEnabled = FALSE; } /******************************************************************************* * * armv7GenTimerRelease - 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 armv7GenTimerRelease ( VXB_DEVICE_ID pInst, void* pCookie ) { ARMV7_GEN_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); pTimer = (ARMV7_GEN_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)armv7GenTimerDisableInternal (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); GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "%s:Line:%d\r\n", (int)__FUNCTION__, __LINE__); return OK; } /******************************************************************************* * * armv7GenTimerRolloverGet - 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 armv7GenTimerRolloverGet ( void * pCookie, UINT32 * pCount ) { ARMV7_GEN_TIMER_DATA * pTimer; VXB_ASSERT_NONNULL (pCount, ERROR); /* free run counter, always get the MAX count for timestamp */ pTimer = (ARMV7_GEN_TIMER_DATA *)pCookie; if (pTimer == NULL) { GEN_TIMER_DBG (GEN_TIMER_DBG_ERR,"%s,%d: pTimer is bad!\r\n",__FILE__,__LINE__); return ERROR; } *pCount = pTimer->maxCount; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerRolloverGet: %u. for vx68\r\n", pTimer->maxCount); GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerRolloverGet: %u\r\n", ARMV7_GEN_TIMER_MAX_COUNT); return OK; } /******************************************************************************* * * armv7GenTimerCountGet - 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 armv7GenTimerCountGet ( void * pCookie, UINT32 * pCount ) { UINT64 cnt64; UINT32 cnt32; ARMV7_GEN_TIMER_DATA * pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerCountGet\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); VXB_ASSERT_NONNULL (pCount, ERROR); pTimer = (ARMV7_GEN_TIMER_DATA *)pCookie; /* the timer counter is from the lower 32 bits of the 64 bits register */ cnt64 = armv7GenTimerGetTimerCnt (pTimer->isVirtual); cnt32 = (UINT32)(cnt64 % ((UINT32)ARMV7_GEN_TIMER_MAX_COUNT + 1)); *pCount = cnt32; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerCountGet: cnt32=%u\r\n", cnt32); return OK; } /******************************************************************************* * * armv7GenTimerCountGet64 - 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 armv7GenTimerCountGet64 ( void * pCookie, UINT64 * pCount64 ) { UINT64 cnt64; ARMV7_GEN_TIMER_DATA * pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerCountGet64\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); VXB_ASSERT_NONNULL (pCount64, ERROR); pTimer = (ARMV7_GEN_TIMER_DATA *)pCookie; cnt64 = armv7GenTimerGetTimerCnt (pTimer->isVirtual); *pCount64 = cnt64; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerCountGet64: cnt64=%x_%08x\r\n", (UINT32)(cnt64>>32), (UINT32)(cnt64&0xFFFFFFFF)); return OK; } /******************************************************************************* * * armv7GenTimerISRSet - 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 armv7GenTimerISRSet ( void * pCookie, void (*pFunc)(int), int arg ) { ARMV7_GEN_TIMER_DATA * pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerISRSet\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); pTimer = (ARMV7_GEN_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 == armv7GenTimerDisable) { (void)armv7GenTimerDisable (pCookie); } else if ((STATUS (*)(void *, UINT32))func == armv7GenTimerEnable) { maxTimerCount = (UINT32)pParams[2]; (void)armv7GenTimerEnable (pCookie, maxTimerCount); } } #endif /* _WRS_CONFIG_SMP */ /******************************************************************************* * * armv7GenTimerDisable - 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 armv7GenTimerDisable ( void * pCookie ) { #ifdef _WRS_CONFIG_SMP cpuset_t cpuSet; ULONG cpcParam[2]; #endif /* _WRS_CONFIG_SMP */ ARMV7_GEN_TIMER_DATA * pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerDisable\r\n"); VXB_ASSERT_NONNULL (pCookie, ERROR); /* retrieve the pTimer */ pTimer = (ARMV7_GEN_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) armv7GenTimerDisable; 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); armv7GenTimerDisableInternal (pTimer); /* close interrupt */ SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); return OK; } /******************************************************************************* * * armv7GenTimerEnable - enable the timer interrupt * * This function enables the timer interrupt. * * RETURNS: OK or ERROR if timer is not enabled * * ERRNO */ LOCAL STATUS armv7GenTimerEnable ( void * pCookie, UINT32 maxTimerCount ) { #ifdef _WRS_CONFIG_SMP cpuset_t cpuSet; ULONG cpcParam[3]; #endif /* _WRS_CONFIG_SMP */ ARMV7_GEN_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; VXB_DEVICE_ID pInst; VXB_ASSERT_NONNULL (pCookie, ERROR); GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerEnable: New TimerCount: %u (0x%x)\r\n", maxTimerCount,maxTimerCount); if ((maxTimerCount > ARMV7_GEN_TIMER_MAX_COUNT) || (maxTimerCount == 0)) { GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerEnable: This TimerCount is invalid!\r\n"); return ERROR; } /* retrieve the pTimer */ pTimer = (ARMV7_GEN_TIMER_DATA *)pCookie; if (pTimer == NULL) return ERROR; 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) armv7GenTimerEnable; 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)armv7GenTimerDisableInternal (pTimer); } pTimer->maxCount = maxTimerCount; /* recalculate ticksPerSecond */ pTimerFunc->ticksPerSecond = pTimerFunc->clkFrequency / pTimer->maxCount; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerEnable New ticksPerSecond = %d.(should be 60)\r\n", pTimerFunc->ticksPerSecond); /* update the timer value register with maxTimerCount */ armv7GenTimerWriteReg (pTimer->isVirtual, GEN_TIMER_REG_TVAL, maxTimerCount); /* set up the timer control register */ armv7GenTimerWriteReg (pTimer->isVirtual, GEN_TIMER_REG_CTL, GEN_TIMER_CTRL_ENABLE); pTimer->isEnabled = TRUE; SPIN_LOCK_ISR_GIVE (&pTimer->spinLock); if (pTimer->isVirtual) { if (vxbIntEnable (pInst, 0,armv7GenTimerInt, pTimer) != OK) { GEN_TIMER_DBG (GEN_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,armv7GenTimerInt, pTimer) != OK)) { pTimer->secPhyAvail = FALSE; } if (pTimer->nonSecPhyAvail && (vxbIntEnable (pInst, 0,armv7GenTimerInt, pTimer) != OK)) { pTimer->nonSecPhyAvail = FALSE; } if (!pTimer->secPhyAvail && !pTimer->nonSecPhyAvail) { GEN_TIMER_DBG (GEN_TIMER_DBG_ERR, "Interrupt enable failed for physical timer\n"); /*SPIN_LOCK_ISR_GIVE (&pTimer->spinLock);*/ return ERROR; } } GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerEnable OK\r\n"); return OK; } /******************************************************************************* * * armv7GenTimerInt - ISR for the ARM Generic Timer * * This routine handles the ARM Generic Timer interrupt. * * RETURNS : N/A */ LOCAL void armv7GenTimerInt ( ARMV7_GEN_TIMER_DATA * pTimer ) { UINT32 ctl; ctl = armv7GenTimerReadReg (pTimer->isVirtual, GEN_TIMER_REG_CTL); if ((ctl & GEN_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) { armv7GenTimerWriteReg (pTimer->isVirtual, GEN_TIMER_REG_TVAL, pTimer->maxCount); } else { armv7GenTimerWriteReg (pTimer->isVirtual, GEN_TIMER_REG_CTL, GEN_TIMER_CTRL_IMASK); } /* call the ISR hooked by armv7GenTimerISRSet() */ if (pTimer->pIsrFunc != NULL) pTimer->pIsrFunc (pTimer->arg); } /****************************************************************************** * * armv7GenTimerAttach - 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 armv7GenTimerAttach ( VXB_DEVICE_ID pDev ) { ARMV7_GEN_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; HCF_DEVICE * pHcf = NULL; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "Enter armv7GenTimerAttach\r\n"); /* check for valid parameter */ VXB_ASSERT_NONNULL (pDev, ERROR); /* get the HCF_DEVICE address */ pHcf = hcfDeviceGet(pDev); if (pHcf == NULL) { GEN_TIMER_DBG (GEN_TIMER_DBG_ERR, "There is no HCF for this device.\r\n"); return ERROR; } /* allocate the memory for the timer structure */ pTimer = (ARMV7_GEN_TIMER_DATA *)hwMemAlloc (sizeof(ARMV7_GEN_TIMER_DATA)); if (pTimer == NULL) { return ERROR; } pArmv7GenTimer = pTimer; /* * Use virtual timer by default, but if it's not available, * use physical timer. */ pTimer->secPhyAvail = TRUE; pTimer->isVirtual = FALSE; pTimer->nonSecPhyAvail = FALSE; if (pTimer->secPhyAvail && (vxbIntConnect (pDev, 0, /*pTimer->intRes[GEN_TIMER_SECURE_PHY_PPI],*/ armv7GenTimerInt, pTimer) != OK)) { GEN_TIMER_DBG (GEN_TIMER_DBG_ERR, "Secure physical timer is not available\r\n"); pTimer->secPhyAvail = 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_GEN_TIMER_DEFAULT_MIN_FREQ; } if (devResourceGet(pHcf,"maxClkRate",HCF_RES_INT, (void *)&pTimerFunc->maxFrequency) != OK) { /*default value*/ pTimerFunc->maxFrequency = ARMV7_GEN_TIMER_DEFAULT_MAX_FREQ; } pTimerFunc->clkFrequency = __inline__GetCntFreq(); GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "Clock Frequency: %d\r\n", pTimerFunc->clkFrequency); if ((pTimerFunc->clkFrequency < ARMV7_GEN_TIMER_MIN_CLK_FREQ) || (pTimerFunc->clkFrequency > ARMV7_GEN_TIMER_MAX_CLK_FREQ)) { GEN_TIMER_DBG (GEN_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_GEN_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_GEN_TIMER_DEFAULT_TPS; pTimerFunc->rolloverPeriod = pTimer->maxCount / pTimerFunc->clkFrequency; (void)strncpy (pTimerFunc->timerName, ARMV7_GEN_TIMER_NAME, MAX_DRV_NAME_LEN); /* populate the function pointers */ pTimerFunc->timerAllocate = armv7GenTimerAllocate; pTimerFunc->timerRelease = armv7GenTimerRelease; pTimerFunc->timerRolloverGet = armv7GenTimerRolloverGet; pTimerFunc->timerCountGet = armv7GenTimerCountGet; pTimerFunc->timerCountGet64 = armv7GenTimerCountGet64; pTimerFunc->timerDisable = armv7GenTimerDisable; pTimerFunc->timerEnable = armv7GenTimerEnable; pTimerFunc->timerISRSet = armv7GenTimerISRSet; /* initialize the spinlock */ SPIN_LOCK_ISR_INIT (&pTimer->spinLock, 0); /* publish methods */ pDev->pMethods = davinciTimerDrv_methods; pDev->pDrvCtrl = pTimer; GEN_TIMER_DBG (GEN_TIMER_DBG_INFO, "armv7GenTimerAttach OK\r\n"); return OK; errOut: hwMemFree ((char * )pTimer); return ERROR; } /******************************************************************************* * * armv7GenTimerFuncGet - 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 armv7GenTimerFuncGet ( VXB_DEVICE_ID pInst, struct vxbTimerFunctionality** pTimerFunc, int timerNo ) { ARMV7_GEN_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_GEN_TIMER_DATA *)(pInst->pDrvCtrl); /* update the timer functionality pointer */ *pTimerFunc = &(pTimerData->timerFunc); return OK; } /* delay 1us */ void armV7GenUsDelay ( int delay /* length of time in US to delay */ ) { ARMV7_GEN_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 = pArmv7GenTimer; 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 = armv7GenTimerGetTimerCnt (pTimer->isVirtual); oldVal = (UINT32)(cnt64 % ((UINT32)ARMV7_GEN_TIMER_MAX_COUNT + 1)); while (decElapsed < totalDelta) { loopcount++; cnt64 = armv7GenTimerGetTimerCnt (pTimer->isVirtual); newVal = (UINT32)(cnt64 % ((UINT32)ARMV7_GEN_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; } } #ifdef DEBUG_GEN_TIMER void testtm(void) { ARMV7_GEN_TIMER_DATA * pTimer; struct vxbTimerFunctionality * pTimerFunc; volatile register UINT32 oldVal; UINT64 cnt64; pTimer = pArmv7GenTimer; if(pTimer == NULL) { printf("No valid armv7 gen timer!\r\n"); return; } pTimerFunc = &(pTimer->timerFunc); printf("pTimer->isVirtual=%d\r\n", pTimer->isVirtual); cnt64 = armv7GenTimerGetTimerCnt (pTimer->isVirtual); oldVal = (UINT32)(cnt64 % ((UINT32)ARMV7_GEN_TIMER_MAX_COUNT + 1)); printf("clkFreq=%d. oldVal = %d;\r\n", pTimerFunc->clkFrequency, oldVal); printf("cnt64=%lld", cnt64); } UINT64 testtmcount(void) { UINT64 v_val = 0; UINT64 p_val = 0; UINT32 reg32; BOOL isVirtual = TRUE; WRS_ASM ("ISB"); v_val = __inline__GetVirtTimerCnt (); p_val = __inline__GetPhyTimerCnt (); printf("v_val=0x%x_%08x; p_val=0x%x_%08x \r\n", (UINT32)(v_val>>32),(UINT32)(v_val&0XFFFFFFFF), (UINT32)(p_val>>32),(UINT32)(p_val&0XFFFFFFFF)); printf("----------- Virtual REGs ------------------- \r\n"); reg32 = armv7GenTimerReadReg(isVirtual, GEN_TIMER_REG_CTL); printf("CTL = 0x%08x \r\n", reg32); reg32 = armv7GenTimerReadReg(isVirtual, GEN_TIMER_REG_TVAL); printf("TVAL = 0x%08x \r\n", reg32); printf("--------------------------------------------- \r\n\n"); printf("----------- Phy REGs ------------------- \r\n"); isVirtual = FALSE; reg32 = armv7GenTimerReadReg(isVirtual, GEN_TIMER_REG_CTL); printf("CTL = 0x%08x \r\n", reg32); reg32 = armv7GenTimerReadReg(isVirtual, GEN_TIMER_REG_TVAL); printf("TVAL = 0x%08x \r\n", reg32); printf("--------------------------------------------- \r\n\n"); return v_val; } #endif