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.

1292 lines
32 KiB

/* 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 <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 AUX_TIMER_DBG_ON
#ifdef AUX_TIMER_DBG_ON
/* turning local symbols into global symbols */
#ifdef LOCAL
#undef LOCAL
#define LOCAL
#endif
#include <private/kwriteLibP.h> /* _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;
}
}