MAX_CARLINK_A270S/MXC_A27-PCB4.5-270T/ArkmicroFiles/libcpu-amt630hv100/source/timer.c

149 lines
3.5 KiB
C

#include <stdint.h>
#include "amt630hv100.h"
#include "clock.h"
#include "timer.h"
#include "chip.h"
#define TIMER_PERIOD 1000000
#define TIMER_LOAD_VAL 0xFFFFFFFF
/* For convenience the high frequency timer increments a variable that is then
used as the time base for the run time stats. */
volatile uint32_t ulHighFrequencyTimerCounts = 0;
void vTimerInit(uint32_t id, int32_t inten, int32_t periodic, uint32_t rate)
{
uint32_t regbase = REGS_TIMER_BASE;
uint32_t ctrl = TIMER_CTRL_INT_MASK;
if (inten) ctrl &= ~TIMER_CTRL_INT_MASK;
if (periodic) ctrl |= TIMER_CTRL_PERIODIC;
writel(0, regbase + TIMER_CTRL(id));
writel(ulClkGetRate(CLK_TIMER) / rate, regbase + TIMER_LOAD_COUNT(id));
writel(ctrl, regbase + TIMER_CTRL(id));
}
void vTimerEnable(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(readl(regbase + TIMER_CTRL(id)) | TIMER_CTRL_ENABLE, regbase + TIMER_CTRL(id));
}
void vTimerDisable(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(readl(regbase + TIMER_CTRL(id)) & ~TIMER_CTRL_ENABLE, regbase + TIMER_CTRL(id));
}
void vTimerClrInt(uint32_t id)
{
uint32_t regbase = REGS_TIMER_BASE;
volatile uint32_t val;
val = readl(regbase + TIMER_EOI(id));
}
/*-----------------------------------------------------------*/
static void prvRunTimer_Handler( void *para )
{
vTimerClrInt((uint32_t)para);
ulHighFrequencyTimerCounts++;
}
void vInitialiseTimerForRunTimeState(void)
{
vTimerInit(TIMER_ID1, 1, 1, configTICK_RATE_HZ * 20);
request_irq(TIMER1_IRQn, 1, prvRunTimer_Handler, (void*)TIMER_ID1);
vTimerEnable(TIMER_ID1);
}
uint32_t ulGetRunTimeCountValue(void)
{
uint32_t regbase = REGS_TIMER_BASE;
return TIMER_LOAD_VAL - readl(regbase + TIMER_CURRENT_VAL(TIMER_ID1));
}
void vInitialiseTimerForDelay(void)
{
uint32_t regbase = REGS_TIMER_BASE;
writel(0, regbase + TIMER_CTRL(TIMER_ID2));
writel(TIMER_LOAD_VAL, regbase + TIMER_LOAD_COUNT(TIMER_ID2));
writel(TIMER_CTRL_INT_MASK | TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE,
regbase + TIMER_CTRL(TIMER_ID2));
}
void udelay(uint32_t usec)
{
uint32_t regbase = REGS_TIMER_BASE;
long tmo = usec * (ulClkGetRate(CLK_TIMER) / TIMER_PERIOD);
unsigned long last = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
unsigned long now;
while (tmo > 0) {
now = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
if (last >= now)
tmo -= last - now;
else
tmo -= last + (TIMER_LOAD_VAL - now);
last = now;
}
}
void mdelay(uint32_t msec)
{
udelay(msec * 1000);
}
void vTimerUdelay(uint32_t usec)
{
udelay(usec);
}
void vTimerMdelay(uint32_t msec)
{
vTimerUdelay(msec * 1000);
}
static unsigned long long timestamp;
static unsigned long lastdec;
uint32_t get_timer_masked(void)
{
uint32_t regbase = REGS_TIMER_BASE;
unsigned long now = readl(regbase + TIMER_CURRENT_VAL(TIMER_ID2));
if (lastdec >= now) { /* normal mode (non roll) */
/* normal mode */
timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */
} else { /* we have overflow of the count down timer */
/* nts = ts + ld + (TLV - now)
* ts=old stamp, ld=time that passed before passing through -1
* (TLV-now) amount of time after passing though -1
* nts = new "advancing time stamp"...it could also roll and cause problems.
*/
timestamp += lastdec + (TIMER_LOAD_VAL - now);
}
lastdec = now;
return timestamp / (ulClkGetRate(CLK_TIMER) / TIMER_PERIOD);
}
uint32_t get_timer(uint32_t base)
{
uint32_t now = get_timer_masked();
if (now >= base) {
return now - base;
} else {
return 0xffffffff - base + now;
}
}