You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1541 lines
37 KiB

/* 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 <vxWorks.h>
#include <stdio.h>
#include <string.h>
#include <intLib.h>
#include <vsbConfig.h>
#include <hwif/vxbus/vxBus.h>
#include <vxbTimerLib.h>
#include <hwif/util/hwMemLib.h>
#include <hwif/vxbus/hwConf.h>
#ifdef _WRS_CONFIG_SMP
#include <cpuset.h>
#include <taskLib.h>
#include <private/cpcLibP.h>
#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 <private/kwriteLibP.h> /* _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